Design changes on fold

pull/301/head
faizatflutter 2 days ago
parent 1a6dff29f1
commit cb299c5bca

@ -601,7 +601,7 @@ SPEC CHECKSUMS:
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 0b743cbb62d8e47eab856f09262bb8c1ddcfe6ba path_provider_foundation: 0b743cbb62d8e47eab856f09262bb8c1ddcfe6ba
PayFortSDK: 233eabe9a45601fdbeac67fa6e5aae46ed8faf82 PayFortSDK: e12f79051ae15b2e29536771a45354900180bfcb
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1 Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
@ -612,7 +612,7 @@ SPEC CHECKSUMS:
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6 shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
Solar-dev: 4612dc9878b9fed2667d23b327f1d4e54e16e8d0 Solar-dev: 4612dc9878b9fed2667d23b327f1d4e54e16e8d0
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153 SwiftProtobuf: 9e106a71456f4d3f6a3b0c8fd87ef0be085efc38
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e Turf: aa2ede4298009639d10db36aba1a7ebaad072a5e
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa

@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.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/dependencies.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/app_update_page.dart'; import 'package:hmg_patient_app_new/presentation/home/app_update_page.dart';
@ -16,7 +17,6 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../exceptions/api_failure.dart';
abstract class ApiClient { abstract class ApiClient {
static final NavigationService _navigationService = getIt.get<NavigationService>(); static final NavigationService _navigationService = getIt.get<NavigationService>();

@ -9,18 +9,17 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_callkit_incoming/entities/android_params.dart'; import 'package:flutter_callkit_incoming/entities/android_params.dart';
import 'package:flutter_callkit_incoming/entities/call_event.dart';
import 'package:flutter_callkit_incoming/entities/call_kit_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/ios_params.dart';
import 'package:flutter_callkit_incoming/entities/notification_params.dart'; import 'package:flutter_callkit_incoming/entities/notification_params.dart';
import 'package:flutter_callkit_incoming/flutter_callkit_incoming.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/call_state_type.dart';
import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart'; import 'package:flutter_ios_voip_kit_karmm/flutter_ios_voip_kit.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/cache_consts.dart'; import 'package:hmg_patient_app_new/core/cache_consts.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@ -33,7 +32,7 @@ String? _currentSessionId; // Store session ID for API call
// |--> Push Notification Background // |--> Push Notification Background
@pragma('vm:entry-point') @pragma('vm:entry-point')
Future<dynamic> backgroundMessageHandler(dynamic message) async { Future<dynamic> backgroundMessageHandler(dynamic message) async {
print("Firebase backgroundMessageHandler!!!"); log("Firebase backgroundMessageHandler!!!");
await Firebase.initializeApp(); await Firebase.initializeApp();
fir.RemoteMessage message_; fir.RemoteMessage message_;
@ -47,20 +46,20 @@ Future<dynamic> backgroundMessageHandler(dynamic message) async {
callPage(String sessionID, String token) async {} callPage(String sessionID, String token) async {}
_incomingCall(Map<String, dynamic> data) async { _incomingCall(Map<String, dynamic> data) async {
print('the value of the _incomingCall remote message is $data'); log('the value of the _incomingCall remote message is $data');
// Check if there's already a call in progress to prevent duplicates // Check if there's already a call in progress to prevent duplicates
if (_isCallInProgress && _currentCallId != null) { if (_isCallInProgress && _currentCallId != null) {
print('⚠️ Call already in progress (ID: $_currentCallId), ignoring duplicate notification'); log('⚠️ Call already in progress (ID: $_currentCallId), ignoring duplicate notification');
return; return;
} }
String roomID = data['session_id'] ?? ''; String roomID = data['session_id'] ?? '';
String callTypeID = data['AppointmentNo'] ?? ''; String callTypeID = data['AppointmentNo'] ?? '';
print('🔍 Extracted from notification data:'); log('🔍 Extracted from notification data:');
print(' - roomID (session_id): "$roomID"'); log(' - roomID (session_id): "$roomID"');
print(' - callTypeID (AppointmentNo): "$callTypeID"'); log(' - callTypeID (AppointmentNo): "$callTypeID"');
// Generate unique call ID // Generate unique call ID
var _currentUuid = Uuid().v4(); var _currentUuid = Uuid().v4();
@ -68,16 +67,16 @@ _incomingCall(Map<String, dynamic> data) async {
_isCallInProgress = true; _isCallInProgress = true;
_currentSessionId = roomID; // Store session ID for decline API call _currentSessionId = roomID; // Store session ID for decline API call
print('📞 Starting new call with ID: $_currentCallId, Session: $_currentSessionId'); log('📞 Starting new call with ID: $_currentCallId, Session: $_currentSessionId');
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, roomID); await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, roomID);
await Utils.saveStringFromPrefs(CacheConst.callTypeID, callTypeID); await Utils.saveStringFromPrefs(CacheConst.callTypeID, callTypeID);
await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, true); await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, true);
print('💾 Saved to cache:'); log('💾 Saved to cache:');
print(' - CacheConst.zoomRoomID: "$roomID"'); log(' - CacheConst.zoomRoomID: "$roomID"');
print(' - CacheConst.callTypeID: "$callTypeID"'); log(' - CacheConst.callTypeID: "$callTypeID"');
print(' - CacheConst.isAppOpenedFromCall: true'); log(' - CacheConst.isAppOpenedFromCall: true');
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -148,7 +147,7 @@ _incomingCall(Map<String, dynamic> data) async {
// Start 60-second timeout timer to auto-dismiss call // Start 60-second timeout timer to auto-dismiss call
_callTimeoutTimer?.cancel(); // Cancel any existing timer _callTimeoutTimer?.cancel(); // Cancel any existing timer
_callTimeoutTimer = Timer(Duration(seconds: 40), () async { _callTimeoutTimer = Timer(Duration(seconds: 40), () async {
print('⏱️ Call timeout (60 seconds) - auto dismissing call notification'); log('⏱️ Call timeout (60 seconds) - auto dismissing call notification');
await _endCallAndCleanup(_currentUuid); await _endCallAndCleanup(_currentUuid);
}); });
@ -158,8 +157,6 @@ _incomingCall(Map<String, dynamic> data) async {
// Helper method to end call and cleanup // Helper method to end call and cleanup
Future<void> _endCallAndCleanup(String callId, {bool isDeclined = false}) async { Future<void> _endCallAndCleanup(String callId, {bool isDeclined = false}) async {
try { try {
print('🧹 Cleaning up call: $callId');
// If call was declined, update session status via API // If call was declined, update session status via API
if (isDeclined && _currentSessionId != null && _currentSessionId!.isNotEmpty) { if (isDeclined && _currentSessionId != null && _currentSessionId!.isNotEmpty) {
await _updateSessionStatus(_currentSessionId!, 3, 'Patient'); await _updateSessionStatus(_currentSessionId!, 3, 'Patient');
@ -184,10 +181,7 @@ Future<void> _endCallAndCleanup(String callId, {bool isDeclined = false}) async
await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, false); await Utils.saveBoolFromPrefs(CacheConst.isAppOpenedFromCall, false);
await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, ''); await Utils.saveStringFromPrefs(CacheConst.zoomRoomID, '');
await Utils.saveStringFromPrefs(CacheConst.callTypeID, ''); await Utils.saveStringFromPrefs(CacheConst.callTypeID, '');
print('✅ Call and push notification cleanup completed successfully');
} catch (e) { } catch (e) {
print('❌ Error during call cleanup: $e');
// Force reset flags even if there's an error // Force reset flags even if there's an error
_isCallInProgress = false; _isCallInProgress = false;
_currentCallId = null; _currentCallId = null;
@ -200,27 +194,20 @@ Future<void> _endCallAndCleanup(String callId, {bool isDeclined = false}) async
// Helper method to update session status via API // Helper method to update session status via API
Future<void> _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async { Future<void> _updateSessionStatus(String sessionId, int sessionStatus, String sessionEndedBy) async {
try { try {
final apiClient = getIt.get<ApiClient>(); final apiClient = getIt.get<ApiClient>();
Map<String, dynamic> requestBody = { Map<String, dynamic> requestBody = {"Open_SessionID": sessionId, "SessionStatus": sessionStatus, "SessionEndedBy": sessionEndedBy};
"Open_SessionID": sessionId,
"SessionStatus": sessionStatus,
"SessionEndedBy": sessionEndedBy
};
await apiClient.post( await apiClient.post(
CHANGE_PATIENT_ER_SESSION, CHANGE_PATIENT_ER_SESSION,
body: requestBody, body: requestBody,
onSuccess: (response, statusCode, {messageStatus, errorMessage}) { onSuccess: (response, statusCode, {messageStatus, errorMessage}) {},
print('✅ Session status updated successfully: $response');
},
onFailure: (error, statusCode, {messageStatus, failureType}) { onFailure: (error, statusCode, {messageStatus, failureType}) {
print('❌ Failed to update session status: $error'); log('❌ Failed to update session status: $error');
}, },
); );
} catch (e) { } catch (e) {
print('❌ Exception updating session status: $e'); log('❌ Exception updating session status: $e');
} }
} }
@ -252,7 +239,7 @@ Future<void> openCallPage(BuildContext context) async {
// ); // );
// } // }
} catch (err) { } catch (err) {
print(err); log(err.toString());
// await PlatformExceptionAlertDialog( // await PlatformExceptionAlertDialog(
// exception: Exception(err), // exception: Exception(err),
// ).show(context); // ).show(context);
@ -351,7 +338,7 @@ class PushNotificationHandler {
// int seconds = 30, // int seconds = 30,
// }) async { // }) async {
// timeOutTimer = Timer(Duration(seconds: seconds), () async { // timeOutTimer = Timer(Duration(seconds: seconds), () async {
// print('🎈 example: timeOut'); // log('🎈 example: timeOut');
// final incomingCallerName = await voIPKit.getIncomingCallerName(); // final incomingCallerName = await voIPKit.getIncomingCallerName();
// voIPKit.unansweredIncomingCall( // voIPKit.unansweredIncomingCall(
// skipLocalNotification: false, // skipLocalNotification: false,
@ -366,19 +353,19 @@ class PushNotificationHandler {
if (Platform.isIOS) { if (Platform.isIOS) {
voIPKit.getVoIPToken().then((value) { voIPKit.getVoIPToken().then((value) {
print("🎈 APNS VOIP KIT TOKEN: $value"); log("🎈 APNS VOIP KIT TOKEN: $value");
Utils.saveStringFromPrefs(CacheConst.voipToken, value ?? ""); Utils.saveStringFromPrefs(CacheConst.voipToken, value ?? "");
// AppSharedPreferences().setString(APNS_TOKEN, value!); // AppSharedPreferences().setString(APNS_TOKEN, value!);
}); });
voIPKit.onDidUpdatePushToken = (String token) { voIPKit.onDidUpdatePushToken = (String token) {
print('🎈 example: onDidUpdatePushToken: $token'); log('🎈 example: onDidUpdatePushToken: $token');
}; };
voIPKit.onDidReceiveIncomingPush = ( voIPKit.onDidReceiveIncomingPush = (
Map<String, dynamic> payload, Map<String, dynamic> payload,
) async { ) async {
print('🎈 example: onDidReceiveIncomingPush $payload'); log('🎈 example: onDidReceiveIncomingPush $payload');
// _timeOut(); // _timeOut();
}; };
@ -387,20 +374,22 @@ class PushNotificationHandler {
String callerId, String callerId,
) async { ) async {
try { try {
print('🎈 example: onDidRejectIncomingCall $uuid - $callerId'); log('🎈 example: onDidRejectIncomingCall $uuid - $callerId');
timeOutTimer.cancel(); timeOutTimer.cancel();
// Cleanup on reject with API call // Cleanup on reject with API call
if (_currentCallId != null) { if (_currentCallId != null) {
await _endCallAndCleanup(_currentCallId!, isDeclined: true); await _endCallAndCleanup(_currentCallId!, isDeclined: true);
} }
} catch (err) {} } catch (err) {
log(err.toString());
}
}; };
voIPKit.onDidAcceptIncomingCall = ( voIPKit.onDidAcceptIncomingCall = (
String uuid, String uuid,
String callerId, String callerId,
) async { ) async {
print('🎈 example: onDidAcceptIncomingCall $uuid - $callerId'); log('🎈 example: onDidAcceptIncomingCall $uuid - $callerId');
await voIPKit.acceptIncomingCall(callerState: CallStateType.calling); await voIPKit.acceptIncomingCall(callerState: CallStateType.calling);
await voIPKit.callConnected(); await voIPKit.callConnected();
@ -430,12 +419,12 @@ class PushNotificationHandler {
if (Platform.isAndroid) { if (Platform.isAndroid) {
try { try {
final fcmToken = await FirebaseMessaging.instance.getToken().catchError((err) { final fcmToken = await FirebaseMessaging.instance.getToken().catchError((err) {
print(err); log(err);
}); });
if (fcmToken != null) onToken(fcmToken); if (fcmToken != null) onToken(fcmToken);
// } // }
} catch (ex) { } catch (ex) {
print("Notification Exception: $ex"); log("Notification Exception: $ex");
} }
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
} }
@ -467,7 +456,7 @@ class PushNotificationHandler {
} catch (ex) {} } catch (ex) {}
FirebaseMessaging.onMessage.listen((RemoteMessage message) async { FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print("Firebase onMessage!!!"); log("Firebase onMessage!!!");
// showCallkitIncoming(); // showCallkitIncoming();
if (Platform.isIOS) { if (Platform.isIOS) {
await Future.delayed(Duration(milliseconds: 3000)).then((value) { await Future.delayed(Duration(milliseconds: 3000)).then((value) {
@ -479,7 +468,7 @@ class PushNotificationHandler {
}); });
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print("Firebase onMessageOpenedApp!!!"); log("Firebase onMessageOpenedApp!!!");
if (Platform.isIOS) { if (Platform.isIOS) {
await Future.delayed(Duration(milliseconds: 3000)).then((value) { await Future.delayed(Duration(milliseconds: 3000)).then((value) {
newMessage(message); newMessage(message);
@ -491,21 +480,21 @@ class PushNotificationHandler {
if (Platform.isIOS) { if (Platform.isIOS) {
FirebaseMessaging.instance.getAPNSToken().then((String? token) { FirebaseMessaging.instance.getAPNSToken().then((String? token) {
print("Push Notification getAPNSToken: ${token!}"); log("Push Notification getAPNSToken: ${token!}");
}).catchError((err) { }).catchError((err) {
print("Push Notification getAPNSToken ERR: ${err.toString()}"); log("Push Notification getAPNSToken ERR: ${err.toString()}");
}); });
} }
FirebaseMessaging.instance.getToken().then((String? token) { FirebaseMessaging.instance.getToken().then((String? token) {
print("Push Notification getToken: ${token!}"); log("Push Notification getToken: ${token!}");
onToken(token!); onToken(token!);
}).catchError((err) { }).catchError((err) {
print(err); log(err);
}); });
FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) { FirebaseMessaging.instance.onTokenRefresh.listen((fcm_token) {
print("Push Notification onTokenRefresh: $fcm_token"); log("Push Notification onTokenRefresh: $fcm_token");
onToken(fcm_token); onToken(fcm_token);
}); });
@ -521,11 +510,11 @@ class PushNotificationHandler {
} }
newMessage(RemoteMessage remoteMessage) async { newMessage(RemoteMessage remoteMessage) async {
print("Remote Message: ${remoteMessage.data}"); log("Remote Message: ${remoteMessage.data}");
if (remoteMessage.data.isEmpty) { if (remoteMessage.data.isEmpty) {
return; return;
} }
debugPrint('the value of the remote message is ${remoteMessage.data}'); log('the value of the remote message is ${remoteMessage.data}');
if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) { if (remoteMessage.data['is_call'] == 'true' || remoteMessage.data['is_call'] == true) {
_incomingCall(remoteMessage.data); _incomingCall(remoteMessage.data);
// showCallkitIncoming(); // showCallkitIncoming();
@ -547,7 +536,7 @@ class PushNotificationHandler {
} }
onToken(String token) async { onToken(String token) async {
print("Push Notification Token: $token"); log("Push Notification Token: $token");
await Utils.saveStringFromPrefs(CacheConst.pushToken, token); await Utils.saveStringFromPrefs(CacheConst.pushToken, token);
} }
@ -569,11 +558,11 @@ class PushNotificationHandler {
// Permission.audio, // Permission.audio,
// Permission.microphone, // Permission.microphone,
].request(); ].request();
print("=-=-=-=-=-=-=-=-=-=-"); log("=-=-=-=-=-=-=-=-=-=-");
print(statuses[Permission.notification]); log(statuses[Permission.notification].toString());
} }
} catch (_) { } catch (_) {
debugPrint(_.toString()); log(_.toString());
} }
} }
} }

@ -115,12 +115,14 @@ extension EmailValidator on String {
bool isCenter = false, bool isCenter = false,
double? height, double? height,
double? letterSpacing, double? letterSpacing,
TextOverflow? textOverflow,
int maxLine = 0}) => int maxLine = 0}) =>
Text( Text(
this, this,
textAlign: isCenter ? TextAlign.center : textAlignment, textAlign: isCenter ? TextAlign.center : textAlignment,
maxLines: (maxLine > 0) ? maxLine : null, maxLines: (maxLine > 0) ? maxLine : null,
style: TextStyle( style: TextStyle(
overflow: textOverflow,
fontSize: 12.f, fontSize: 12.f,
fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: fontWeight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,

@ -262,7 +262,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Expanded( Expanded(
child: CollapsingListView( child: CollapsingListView(
title: LocaleKeys.appointmentDetails.tr(context: context), title: LocaleKeys.appointmentDetails.tr(context: context),
report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) && widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment==false && widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed! ==true && widget.patientAppointmentHistoryResponseModel.isActiveDoctor! == true report: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) &&
widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment == false &&
widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed! == true &&
widget.patientAppointmentHistoryResponseModel.isActiveDoctor! == true
? () { ? () {
contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد')); contactUsViewModel.setSelectedFeedbackType(FeedbackType(id: 1, nameEN: "Complaint for appointment", nameAR: 'شكوى على موعد'));
contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); contactUsViewModel.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel);
@ -280,8 +283,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
children: [ children: [
AppointmentDoctorCard( AppointmentDoctorCard(
// renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) || // renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
renderWidgetForERDisplay: renderWidgetForERDisplay: ((widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
((widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) || !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)), !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID)),
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel, patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onAskDoctorTap: () async { onAskDoctorTap: () async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context)); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.checkingDoctorAvailability.tr(context: context));
@ -416,14 +419,17 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Utils.buildSvgWithAssets(icon: AppAssets.prescription_reminder_icon, width: 40.w, height: 40.h, applyThemeColor: false), Utils.buildSvgWithAssets(
icon: AppAssets.prescription_reminder_icon, width: 40.w, height: 40.h, applyThemeColor: false),
SizedBox(width: 8.w), SizedBox(width: 8.w),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4.h, spacing: 4.h,
children: [ children: [
LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), LocaleKeys.setReminder.tr(context: context).toText13(isBold: true),
LocaleKeys.notifyMeBeforeAppointment.tr(context: context).toText11(color: AppColors.textColorLight, isBold: true), LocaleKeys.notifyMeBeforeAppointment
.tr(context: context)
.toText11(color: AppColors.textColorLight, isBold: true),
], ],
), ),
const Spacer(), const Spacer(),
@ -438,48 +444,53 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
inactiveCircleColor: AppColors.greyTextColor, inactiveCircleColor: AppColors.greyTextColor,
activeIconColor: AppColors.bgGreenColor, activeIconColor: AppColors.bgGreenColor,
inactiveIconColor: AppColors.greyTextColor, inactiveIconColor: AppColors.greyTextColor,
activeIcon: Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 12.w, height: 12.h), activeIcon:
inactiveIcon: Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 12.w, height: 12.h), Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 12.w, height: 12.h),
inactiveIcon:
Utils.buildSvgWithAssets(icon: AppAssets.bell, iconColor: AppColors.whiteColor, width: 12.w, height: 12.h),
onChanged: (newValue) async { onChanged: (newValue) async {
CalenderUtilsNew calender = CalenderUtilsNew.instance; CalenderUtilsNew calender = CalenderUtilsNew.instance;
bool isEventAddedOrRemoved = false; bool isEventAddedOrRemoved = false;
if (newValue == true) { if (newValue == true) {
DateTime startDate = DateTime.now(); DateTime startDate = DateTime.now();
DateTime endDate = DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate); DateTime endDate =
DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate);
// Show reminder bottom sheet and check if permission was granted // Show reminder bottom sheet and check if permission was granted
bool permissionGranted = await BottomSheetUtils().showReminderBottomSheet( bool permissionGranted = await BottomSheetUtils().showReminderBottomSheet(
context, context,
endDate, endDate,
widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "", widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "",
"${widget.patientAppointmentHistoryResponseModel.appointmentNo}" ?? "", "${widget.patientAppointmentHistoryResponseModel.appointmentNo}" ?? "",
"", "",
"", "",
title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}", title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}",
description: description:
"${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}", "${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () { onSuccess: () {
setState(() { setState(() {
myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel); myAppointmentsViewModel.setAppointmentReminder(
}); newValue, widget.patientAppointmentHistoryResponseModel);
}, });
isMultiAllowed: true, },
onMultiDateSuccess: (int selectedIndex) async { isMultiAllowed: true,
isEventAddedOrRemoved = await calender.createOrUpdateEvent( onMultiDateSuccess: (int selectedIndex) async {
title: isEventAddedOrRemoved = await calender.createOrUpdateEvent(
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}", title:
description: "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}", description:
scheduleDateTime: DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), "Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}",
eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}", scheduleDateTime:
location: '', DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate),
reminderMinutes: selectedIndex); eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
setState(() { location: '',
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel); reminderMinutes: selectedIndex);
}); setState(() {
}, myAppointmentsViewModel.setAppointmentReminder(
isForAppointment: true isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
); });
},
isForAppointment: true);
// If permission was not granted, revert the switch back to OFF // If permission was not granted, revert the switch back to OFF
if (!permissionGranted) { if (!permissionGranted) {
@ -490,7 +501,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
id: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}", id: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
); );
setState(() { setState(() {
myAppointmentsViewModel.setAppointmentReminder(!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel); myAppointmentsViewModel.setAppointmentReminder(
!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
}); });
} }
}, },
@ -581,8 +593,12 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true), LocaleKeys.appointmentStatus.tr(context: context).toText16(isBold: true),
SizedBox(height: 4.h), SizedBox(height: 4.h),
(!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel) (!AppointmentType.isConfirmed(widget.patientAppointmentHistoryResponseModel)
? LocaleKeys.notConfirmed.tr(context: context).toText12(color: AppColors.primaryRedColor, isBold: true) ? LocaleKeys.notConfirmed
: LocaleKeys.confirmed.tr(context: context).toText12(color: AppColors.successColor, isBold: true)), .tr(context: context)
.toText12(color: AppColors.primaryRedColor, isBold: true)
: LocaleKeys.confirmed
.tr(context: context)
.toText12(color: AppColors.successColor, isBold: true)),
SizedBox(height: 16.h), SizedBox(height: 16.h),
], ],
), ),
@ -640,7 +656,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
LocaleKeys.doctorWillCallYou.tr(context: context).toText14(color: AppColors.greyTextColor, isBold: true), LocaleKeys.doctorWillCallYou
.tr(context: context)
.toText14(color: AppColors.greyTextColor, isBold: true),
], ],
), ),
), ),
@ -648,13 +666,17 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
) )
: Stack( : Stack(
children: [ children: [
ClipRRect( SizedBox(
clipBehavior: Clip.hardEdge, width: double.infinity,
borderRadius: BorderRadius.circular(24.r), child: ClipRRect(
// Todo: what is this???? Api Key??? 😲 clipBehavior: Clip.hardEdge,
child: Image.network( borderRadius: BorderRadius.circular(24.r),
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}", // Todo: what is this???? Api Key??? 😲
fit: BoxFit.contain, child: Image.network(
"https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=${(MediaQuery.of(context).size.width * 1.5).toInt()}x${(MediaQuery.of(context).size.height * 0.35).toInt()}&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=${ApiKeyConstants.googleMapsApiKey}",
fit: BoxFit.cover,
width: double.infinity,
),
), ),
), ),
Positioned( Positioned(
@ -663,7 +685,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
width: MediaQuery.of(context).size.width - 85.w, width: MediaQuery.of(context).size.width - 85.w,
child: CustomButton( child: CustomButton(
onPressed: () async { onPressed: () async {
if (widget.patientAppointmentHistoryResponseModel.projectID == 130 || widget.patientAppointmentHistoryResponseModel.projectID == 120) { if (widget.patientAppointmentHistoryResponseModel.projectID == 130 ||
widget.patientAppointmentHistoryResponseModel.projectID == 120) {
showDirectionsBottomSheet(); showDirectionsBottomSheet();
} else { } else {
await MapLauncher.showMarker( await MapLauncher.showMarker(
@ -683,7 +706,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
}, },
text: LocaleKeys.getDirections.tr(context: context), text: LocaleKeys.getDirections.tr(context: context),
backgroundColor: AppColors.bookAppointment.withValues(alpha: 0.8), backgroundColor: AppColors.bookAppointment.withValues(alpha: 0.8),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), borderColor: AppointmentType.getNextActionButtonColor(
widget.patientAppointmentHistoryResponseModel.nextAction)
.withValues(alpha: 0.01),
textColor: Colors.white, textColor: Colors.white,
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -974,7 +999,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
); );
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: PrescriptionDetailPage(isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel), page: PrescriptionDetailPage(
isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel),
), ),
); );
} else { } else {
@ -1289,7 +1315,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20) if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 ||
widget.patientAppointmentHistoryResponseModel.nextAction == 20)
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -1297,7 +1324,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor,
13,
isSaudiCurrency: true), isSaudiCurrency: true),
], ],
), ),
@ -1305,8 +1335,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)), Expanded(
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64), child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})"
.toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
], ],
), ),
SizedBox(height: 18.h), SizedBox(height: 18.h),
@ -1320,7 +1352,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17, Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true),
AppColors.blackColor,
17,
isSaudiCurrency: true), isSaudiCurrency: true),
], ],
), ),
@ -1358,7 +1393,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction); handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction);
}, },
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction), backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
.withValues(alpha: 0.01),
textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white, textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white,
fontSize: 16.f, fontSize: 16.f,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1398,7 +1434,10 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
text: LocaleKeys.insideHospital.tr(context: context), text: LocaleKeys.insideHospital.tr(context: context),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
initPenguinSDK(widget.patientAppointmentHistoryResponseModel.projectID == 130 ? 1 : (widget.patientAppointmentHistoryResponseModel.projectID == 120 ? 3 : -1), initPenguinSDK(
widget.patientAppointmentHistoryResponseModel.projectID == 130
? 1
: (widget.patientAppointmentHistoryResponseModel.projectID == 120 ? 3 : -1),
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID.toString()); clinicID: widget.patientAppointmentHistoryResponseModel.clinicID.toString());
}, },
backgroundColor: AppColors.primaryRedColor, backgroundColor: AppColors.primaryRedColor,
@ -1417,12 +1456,14 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Navigator.pop(context); Navigator.pop(context);
await MapLauncher.showMarker( await MapLauncher.showMarker(
mapType: MapType.google, mapType: MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)), coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital", title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
).catchError((err) { ).catchError((err) {
MapLauncher.showMarker( MapLauncher.showMarker(
mapType: Platform.isIOS ? MapType.apple : MapType.google, mapType: Platform.isIOS ? MapType.apple : MapType.google,
coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!), double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)), coords: Coords(double.parse(widget.patientAppointmentHistoryResponseModel.latitude!),
double.parse(widget.patientAppointmentHistoryResponseModel.longitude!)),
title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital", title: widget.patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
); );
}); });
@ -1456,7 +1497,9 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Permission.bluetoothScan, Permission.bluetoothScan,
Permission.activityRecognition, Permission.activityRecognition,
].request().whenComplete(() { ].request().whenComplete(() {
PenguinMethodChannel().launch("penguin", getIt.get<AppState>().isArabic() ? "ar" : "en", getIt.get<AppState>().getAuthenticatedUser()?.patientId?.toString() ?? "", true, details: data); PenguinMethodChannel().launch("penguin", getIt.get<AppState>().isArabic() ? "ar" : "en",
getIt.get<AppState>().getAuthenticatedUser()?.patientId?.toString() ?? "", true,
details: data);
}); });
} }
} }
@ -1514,12 +1557,20 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
LoaderBottomSheet.hideLoader(); LoaderBottomSheet.hideLoader();
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
showCommonBottomSheet(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)), callBackFunc: (str) { showCommonBottomSheet(context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentConfirmedSuccessfully.tr(context: context)), callBackFunc: (str) {
myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true); myAppointmentsViewModel.setIsAppointmentDataToBeLoaded(true);
myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false); myAppointmentsViewModel.getPatientAppointments(true, false);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isAutoDismiss: true, isCloseButtonVisible: true, isDismissible: false, isFullScreen: false, isSuccessDialog: true); },
title: "",
height: ResponsiveExtension.screenHeight * 0.3,
isAutoDismiss: true,
isCloseButtonVisible: true,
isDismissible: false,
isFullScreen: false,
isSuccessDialog: true);
}); });
// LoaderBottomSheet.hideLoader(); // LoaderBottomSheet.hideLoader();
case 15: case 15:
@ -1539,7 +1590,8 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Lottie.asset(AppAnimations.warningAnimation, repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), Lottie.asset(AppAnimations.warningAnimation,
repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox( SizedBox(
height: 12, height: 12,
), ),

@ -1,4 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -18,6 +20,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart'; import 'package:hmg_patient_app_new/features/my_appointments/utils/appointment_type.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/medical_file/eye_measurement_details_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/eye_measurement_details_page.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -26,8 +29,6 @@ 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/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.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:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'dart:ui' as ui;
import 'package:hmg_patient_app_new/presentation/appointments/appointment_payment_page.dart';
import 'package:lottie/lottie.dart'; import 'package:lottie/lottie.dart';
class AppointmentCard extends StatefulWidget { class AppointmentCard extends StatefulWidget {
@ -42,6 +43,7 @@ class AppointmentCard extends StatefulWidget {
final ContactUsViewModel? contactUsViewModel; final ContactUsViewModel? contactUsViewModel;
final BookAppointmentsViewModel bookAppointmentsViewModel; final BookAppointmentsViewModel bookAppointmentsViewModel;
final bool isForRate; final bool isForRate;
// bool isAppointmentWithin4Hours = false; // bool isAppointmentWithin4Hours = false;
const AppointmentCard( const AppointmentCard(
@ -189,20 +191,28 @@ class _AppointmentCardState extends State<AppointmentCard> {
runSpacing: 6.h, runSpacing: 6.h,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
icon: widget.isLoading ? AppAssets.walkin_appointment_icon : (isLiveCare ? AppAssets.small_livecare_icon : AppAssets.walkin_appointment_icon), icon:
widget.isLoading ? AppAssets.walkin_appointment_icon : (isLiveCare ? AppAssets.small_livecare_icon : AppAssets.walkin_appointment_icon),
iconColor: widget.isLoading ? AppColors.textColor : (isLiveCare ? Colors.white : AppColors.textColor), iconColor: widget.isLoading ? AppColors.textColor : (isLiveCare ? Colors.white : AppColors.textColor),
labelText: widget.isLoading ? LocaleKeys.walkin.tr(context: context) : (isLiveCare ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context)), labelText: widget.isLoading
? LocaleKeys.walkin.tr(context: context)
: (isLiveCare ? LocaleKeys.livecare.tr(context: context) : LocaleKeys.walkin.tr(context: context)),
backgroundColor: widget.isLoading ? AppColors.greyColor : (isLiveCare ? AppColors.successColor : AppColors.greyColor), backgroundColor: widget.isLoading ? AppColors.greyColor : (isLiveCare ? AppColors.successColor : AppColors.greyColor),
textColor: widget.isLoading ? AppColors.textColor : (isLiveCare ? Colors.white : AppColors.textColor), textColor: widget.isLoading ? AppColors.textColor : (isLiveCare ? Colors.white : AppColors.textColor),
).toShimmer2(isShow: widget.isLoading), ).toShimmer2(isShow: widget.isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: labelText: widget.isLoading
widget.isLoading ? 'OutPatient' : (appState.isArabic() ? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! : widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!), ? 'OutPatient'
: (appState.isArabic()
? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1), backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.1),
textColor: AppColors.warningColorYellow, textColor: AppColors.warningColorYellow,
).toShimmer2(isShow: widget.isLoading), ).toShimmer2(isShow: widget.isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: widget.isLoading ? 'Booked' : AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!), labelText: widget.isLoading
? 'Booked'
: AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!),
backgroundColor: AppColors.successColor.withValues(alpha: 0.1), backgroundColor: AppColors.successColor.withValues(alpha: 0.1),
textColor: AppColors.successColor, textColor: AppColors.successColor,
).toShimmer2(isShow: widget.isLoading), ).toShimmer2(isShow: widget.isLoading),
@ -218,7 +228,9 @@ class _AppointmentCardState extends State<AppointmentCard> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Image.network( Image.network(
widget.isLoading ? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png' : widget.patientAppointmentHistoryResponseModel.doctorImageURL!, widget.isLoading
? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png'
: widget.patientAppointmentHistoryResponseModel.doctorImageURL!,
width: 63.h, width: 63.h,
height: 63.h, height: 63.h,
fit: BoxFit.cover, fit: BoxFit.cover,
@ -242,8 +254,10 @@ class _AppointmentCardState extends State<AppointmentCard> {
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow), Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h, iconColor: AppColors.ratingColorYellow),
SizedBox(height: 2.h), SizedBox(height: 2.h),
(isFoldable || isTablet) (isFoldable || isTablet)
? "${widget.patientAppointmentHistoryResponseModel.decimalDoctorRate}".toText9(isBold: true, color: AppColors.textColor, isEnglishOnly: true) ? "${widget.patientAppointmentHistoryResponseModel.decimalDoctorRate}"
: "${widget.patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}".toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true), .toText9(isBold: true, color: AppColors.textColor, isEnglishOnly: true)
: "${widget.patientAppointmentHistoryResponseModel.decimalDoctorRate ?? "0.0"}"
.toText11(isBold: true, color: AppColors.textColor, isEnglishOnly: true),
], ],
), ),
).circle(100).toShimmer2(isShow: widget.isLoading), ).circle(100).toShimmer2(isShow: widget.isLoading),
@ -258,10 +272,16 @@ class _AppointmentCardState extends State<AppointmentCard> {
Row( Row(
children: [ children: [
(widget.isLoading ? 'Dr' : "${widget.patientAppointmentHistoryResponseModel.doctorTitle}").toText16(isBold: true, maxlines: 1), (widget.isLoading ? 'Dr' : "${widget.patientAppointmentHistoryResponseModel.doctorTitle}").toText16(isBold: true, maxlines: 1),
(widget.isLoading ? 'John Doe' : " ${widget.patientAppointmentHistoryResponseModel.doctorNameObj!.truncate(20)}") Expanded(
.toText16(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "John Doe")), child: (widget.isLoading ? 'John Doe' : " ${widget.patientAppointmentHistoryResponseModel.doctorNameObj!.truncate(20)}").toText16(
isBold: true,
maxlines: 1,
textOverflow: TextOverflow.ellipsis,
isEnglishOnly: !Utils.isArabicText(widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "John Doe")),
),
SizedBox(width: 12.w), SizedBox(width: 12.w),
(widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null && widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL!.isNotEmpty) (widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL != null &&
widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL!.isNotEmpty)
? Image.network( ? Image.network(
widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png", widget.patientAppointmentHistoryResponseModel.doctorNationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
width: 20.h, width: 20.h,
@ -419,40 +439,40 @@ class _AppointmentCardState extends State<AppointmentCard> {
// } else { // } else {
return CustomButton( return CustomButton(
text: widget.isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context), text: widget.isFromMedicalReport ? LocaleKeys.selectAppointment.tr(context: context) : LocaleKeys.viewDetails.tr(context: context),
onPressed: () { onPressed: () {
if (widget.isFromMedicalReport) { if (widget.isFromMedicalReport) {
if (widget.isForFeedback) { if (widget.isForFeedback) {
widget.contactUsViewModel!.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel); widget.contactUsViewModel!.setPatientFeedbackSelectedAppointment(widget.patientAppointmentHistoryResponseModel);
} else {
widget.medicalFileViewModel!.setSelectedMedicalReportAppointment(widget.patientAppointmentHistoryResponseModel);
}
Navigator.pop(context, false);
} else { } else {
Navigator.of(context) widget.medicalFileViewModel!.setSelectedMedicalReportAppointment(widget.patientAppointmentHistoryResponseModel);
.push(
CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
),
)
.then((_) {
widget.myAppointmentsViewModel.initAppointmentsViewModel();
widget.myAppointmentsViewModel.getPatientAppointments(true, false);
});
} }
}, Navigator.pop(context, false);
backgroundColor: AppColors.secondaryLightRedColor, } else {
borderColor: AppColors.secondaryLightRedColor, Navigator.of(context)
textColor: AppColors.primaryRedColor, .push(
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, CustomPageRoute(
fontWeight: FontWeight.w600, page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
borderRadius: 12.r, ),
padding: EdgeInsets.symmetric(horizontal: 10.w), )
// height: isTablet || isFoldable ? 46.h : 40.h, .then((_) {
height: 40.h, widget.myAppointmentsViewModel.initAppointmentsViewModel();
icon: widget.isFromMedicalReport ? AppAssets.checkmark_icon : null, widget.myAppointmentsViewModel.getPatientAppointments(true, false);
iconColor: AppColors.primaryRedColor, });
iconSize: 16.h, }
); },
backgroundColor: AppColors.secondaryLightRedColor,
borderColor: AppColors.secondaryLightRedColor,
textColor: AppColors.primaryRedColor,
fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
// height: isTablet || isFoldable ? 46.h : 40.h,
height: 40.h,
icon: widget.isFromMedicalReport ? AppAssets.checkmark_icon : null,
iconColor: AppColors.primaryRedColor,
iconSize: 16.h,
);
// } // }
} else { } else {
if (widget.isFromMedicalReport) { if (widget.isFromMedicalReport) {
@ -486,7 +506,7 @@ class _AppointmentCardState extends State<AppointmentCard> {
} }
return (widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) return (widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true)
? (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) && ? (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) &&
widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false) widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false)
? // Show only View Details button without arrow when rebooking not allowed ? // Show only View Details button without arrow when rebooking not allowed
_getArrivedButton(context) _getArrivedButton(context)
: Row( : Row(
@ -498,8 +518,10 @@ class _AppointmentCardState extends State<AppointmentCard> {
: CustomButton( : CustomButton(
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
onPressed: () => handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context), onPressed: () => handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context),
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), .withValues(alpha: 0.15),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
.withValues(alpha: 0.01),
textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction),
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -589,10 +611,10 @@ class _AppointmentCardState extends State<AppointmentCard> {
// Show Rebook button // Show Rebook button
return CustomButton( return CustomButton(
borderSide: BorderSide( borderSide: BorderSide(
color: AppColors.textColor, color: AppColors.textColor,
width: 1.2, width: 1.2,
), ),
text: LocaleKeys.rebookSameDoctor.tr(context: context), text: LocaleKeys.rebookSameDoctor.tr(context: context),
onPressed: () => openDoctorScheduleCalendar(context), onPressed: () => openDoctorScheduleCalendar(context),
backgroundColor: AppColors.transparent, backgroundColor: AppColors.transparent,
@ -620,7 +642,8 @@ class _AppointmentCardState extends State<AppointmentCard> {
); );
} else { } else {
if (!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) { if (!AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) {
widget.bookAppointmentsViewModel.getAppointmentNearestGate(projectID: widget.patientAppointmentHistoryResponseModel.projectID, clinicID: widget.patientAppointmentHistoryResponseModel.clinicID); widget.bookAppointmentsViewModel.getAppointmentNearestGate(
projectID: widget.patientAppointmentHistoryResponseModel.projectID, clinicID: widget.patientAppointmentHistoryResponseModel.clinicID);
} }
Navigator.of(context) Navigator.of(context)
.push( .push(
@ -708,46 +731,47 @@ class _AppointmentCardState extends State<AppointmentCard> {
children: [ children: [
Lottie.asset(AppAnimations.warningAnimation, Lottie.asset(AppAnimations.warningAnimation,
repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill), repeat: false, reverse: false, frameRate: FrameRate(60), width: 100.h, height: 100.h, fit: BoxFit.fill),
SizedBox(height: 12,), SizedBox(
LocaleKeys.upcomingPaymentPending.tr(context: context).toText14( height: 12,
color: AppColors.textColor,
isCenter: true,
), ),
LocaleKeys.upcomingPaymentPending.tr(context: context).toText14(
color: AppColors.textColor,
isCenter: true,
),
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Countdown Timer - DD : HH : MM : SS format with labels // Countdown Timer - DD : HH : MM : SS format with labels
Directionality( Directionality(
textDirection: ui.TextDirection.ltr, textDirection: ui.TextDirection.ltr,
child:Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Days // Days
_buildTimeUnit( _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00', _timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00',
LocaleKeys.days.tr(context: context), LocaleKeys.days.tr(context: context),
), ),
_buildTimeSeparator(), _buildTimeSeparator(),
// Hours // Hours
_buildTimeUnit( _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00', _timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00',
LocaleKeys.hours.tr(context: context), LocaleKeys.hours.tr(context: context),
), ),
_buildTimeSeparator(), _buildTimeSeparator(),
// Minutes // Minutes
_buildTimeUnit( _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00', _timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.minutes.tr(context: context), LocaleKeys.minutes.tr(context: context),
), ),
_buildTimeSeparator(), _buildTimeSeparator(),
// Seconds // Seconds
_buildTimeUnit( _buildTimeUnit(
_timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00', _timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00',
LocaleKeys.seconds.tr(context: context), LocaleKeys.seconds.tr(context: context),
), ),
], ],
)), )),
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Green Acknowledge button with checkmark icon // Green Acknowledge button with checkmark icon
CustomButton( CustomButton(
@ -800,4 +824,3 @@ class _AppointmentCardState extends State<AppointmentCard> {
} }
} }
} }

@ -1,4 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart';
@ -18,10 +20,8 @@ import 'package:hmg_patient_app_new/presentation/appointments/appointment_paymen
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.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/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'dart:ui' as ui;
class MedicalFileAppointmentCard extends StatefulWidget { class MedicalFileAppointmentCard extends StatefulWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@ -138,169 +138,193 @@ class _MedicalFileAppointmentCardState extends State<MedicalFileAppointmentCard>
richText: Directionality( richText: Directionality(
textDirection: ui.TextDirection.ltr, textDirection: ui.TextDirection.ltr,
child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false) child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)
.toText12(color: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, isBold: true, isEnglishOnly: true) .toText12(
color: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
isBold: true,
isEnglishOnly: true)
.paddingSymmetrical(8.w, 0), .paddingSymmetrical(8.w, 0),
), ),
icon: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon, icon: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
? AppAssets.appointment_calendar_icon
: AppAssets.alarm_clock_icon,
iconColor: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, iconColor: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
iconSize: 16.w, iconSize: 16.w,
backgroundColor: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.greyColor : AppColors.secondaryLightRedColor, backgroundColor:
AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.greyColor : AppColors.secondaryLightRedColor,
textColor: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, textColor: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
padding: EdgeInsets.only(top: 12.h, bottom: 12.h, left: 8.w, right: 8.w), padding: EdgeInsets.only(top: 12.h, bottom: 12.h, left: 8.w, right: 8.w),
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), ).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Container( IntrinsicWidth(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false), child: Container(
width: 200.w, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: [ children: [
Image.network( Image.network(
widget.patientAppointmentHistoryResponseModel.doctorImageURL ?? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png", widget.patientAppointmentHistoryResponseModel.doctorImageURL ??
width: 25.w, "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png",
height: 27.h, width: 25.w,
fit: BoxFit.fill, height: 27.h,
).circle(100).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), fit: BoxFit.fill,
SizedBox(width: 8.w), ).circle(100).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
Expanded( SizedBox(width: 8.w),
child: Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
(widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText14(isBold: true, maxlines: 1, isEnglishOnly: !Utils.isArabicText(widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "")).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), children: [
(widget.patientAppointmentHistoryResponseModel.clinicName ?? "") (widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? "")
.toText12(maxLine: 1, isBold: true, color: AppColors.greyTextColor) .toText14(
.toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), isBold: true,
], maxlines: 1,
isEnglishOnly: !Utils.isArabicText(widget.patientAppointmentHistoryResponseModel.doctorNameObj ?? ""))
.toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
(widget.patientAppointmentHistoryResponseModel.clinicName ?? "")
.toText12(maxLine: 1, textOverflow: TextOverflow.ellipsis, isBold: true, color: AppColors.greyTextColor)
.toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
],
),
), ),
), ],
], ),
), SizedBox(height: 8.h),
SizedBox(height: 12.h), // Check if doctor is active - if not, show only View Details button
// Check if doctor is active - if not, show only View Details button (widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true)
(widget.patientAppointmentHistoryResponseModel.isActiveDoctor ?? true) ? // Doctor is active - check rebooking logic
? // Doctor is active - check rebooking logic (AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) &&
(AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) && widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false)
widget.patientAppointmentHistoryResponseModel.isClinicReBookingAllowed == false) ? // Show only the button without arrow when rebooking not allowed
? // Show only the button without arrow when rebooking not allowed widget.myAppointmentsViewModel.isMyAppointmentsLoading
widget.myAppointmentsViewModel.isMyAppointmentsLoading ? Container().toShimmer2(isShow: true, height: 40.h, width: 100.w, radius: 12.r)
? Container().toShimmer2(isShow: true, height: 40.h, width: 100.w, radius: 12.r) : AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) ? getArrivedAppointmentButton(context).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading)
? getArrivedAppointmentButton(context).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading) : CustomButton(
: CustomButton( text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), onPressed: () {
onPressed: () { handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context);
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context); },
}, backgroundColor:
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), .withValues(alpha: 0.15),
textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
fontSize: 14.f, .withValues(alpha: 0.01),
fontWeight: FontWeight.w600, textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction),
borderRadius: 12.r, fontSize: 14.f,
padding: EdgeInsets.symmetric(horizontal: 10.w), fontWeight: FontWeight.w600,
height: 40.h, borderRadius: 12.r,
icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), padding: EdgeInsets.symmetric(horizontal: 10.w),
iconColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), height: 40.h,
iconSize: 14.h, icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction),
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading) iconColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction),
: // Normal flow - show button with arrow iconSize: 14.h,
Row( ).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading)
children: [ : // Normal flow - show button with arrow
widget.myAppointmentsViewModel.isMyAppointmentsLoading Row(
? Container().toShimmer2(isShow: true, height: 40.h, width: 100.w, radius: 12.r) children: [
: Expanded( widget.myAppointmentsViewModel.isMyAppointmentsLoading
flex: 7, ? Container().toShimmer2(isShow: true, height: 40.h, width: 100.w, radius: 12.r)
child: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) : Expanded(
? getArrivedAppointmentButton(context).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading) flex: 7,
: CustomButton( child: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)
text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), ? getArrivedAppointmentButton(context)
onPressed: () { .toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading)
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context); : CustomButton(
}, text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction),
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), onPressed: () {
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction, context);
textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), },
fontSize: 14.f, backgroundColor:
fontWeight: FontWeight.w600, AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
borderRadius: 12.r, .withValues(alpha: 0.15),
padding: EdgeInsets.symmetric(horizontal: 10.w), borderColor:
height: 40.h, AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction)
icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), .withValues(alpha: 0.01),
iconColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), textColor:
iconSize: 14.h, AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction),
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), fontSize: 14.f,
), fontWeight: FontWeight.w600,
SizedBox(width: 8.w), borderRadius: 12.r,
((((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) || padding: EdgeInsets.symmetric(horizontal: 10.w),
(widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) || height: 40.h,
!Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID ?? 0))) && icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction),
AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel)) iconColor:
? SizedBox.shrink() AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction),
: Expanded( iconSize: 14.h,
flex: 2, ).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
child: Container( ),
height: 40.h, SizedBox(width: 8.w),
width: 40.w, ((((widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment ?? false) ||
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( (widget.patientAppointmentHistoryResponseModel.isExecludeDoctor ?? false) ||
color: AppColors.textColor, !Utils.isClinicAllowedForRebook(widget.patientAppointmentHistoryResponseModel.clinicID ?? 0))) &&
borderRadius: 10.r, AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel))
), ? SizedBox.shrink()
child: Padding( : Expanded(
padding: EdgeInsets.all(10.w), flex: 2,
child: Transform.flip( child: Container(
flipX: appState.isArabic(), height: 40.h,
child: Utils.buildSvgWithAssets( width: 40.w,
iconColor: AppColors.whiteColor, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
icon: AppAssets.forward_arrow_icon_small, color: AppColors.textColor,
width: 40.w, borderRadius: 10.r,
height: 40.h,
fit: BoxFit.contain,
),
), ),
), child: Padding(
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading).onPress(() { padding: EdgeInsets.all(10.w),
Navigator.of(context) child: Transform.flip(
.push( flipX: appState.isArabic(),
CustomPageRoute( child: Utils.buildSvgWithAssets(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), iconColor: AppColors.whiteColor,
icon: AppAssets.forward_arrow_icon_small,
width: 40.w,
height: 40.h,
fit: BoxFit.contain,
),
),
), ),
) ).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading).onPress(() {
.then((val) { Navigator.of(context)
// widget.myAppointmentsViewModel.initAppointmentsViewModel(); .push(
// widget.myAppointmentsViewModel.getPatientAppointments(true, false); CustomPageRoute(
}); page: AppointmentDetailsPage(
}), patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
), ),
], )
) .then((val) {
: // Doctor is not active - show only View Details button // widget.myAppointmentsViewModel.initAppointmentsViewModel();
CustomButton( // widget.myAppointmentsViewModel.getPatientAppointments(true, false);
text: LocaleKeys.viewDetails.tr(context: context), });
onPressed: () { }),
Navigator.of(context) ),
.push( ],
CustomPageRoute( )
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), : // Doctor is not active - show only View Details button
), CustomButton(
) text: LocaleKeys.viewDetails.tr(context: context),
.then((_) { onPressed: () {
widget.myAppointmentsViewModel.initAppointmentsViewModel(); Navigator.of(context)
widget.myAppointmentsViewModel.getPatientAppointments(true, false); .push(
}); CustomPageRoute(
}, page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
backgroundColor: AppColors.secondaryLightRedColor, ),
borderColor: AppColors.secondaryLightRedColor, )
textColor: AppColors.primaryRedColor, .then((_) {
fontSize: (isFoldable || isTablet) ? 12.f : 14.f, widget.myAppointmentsViewModel.initAppointmentsViewModel();
fontWeight: FontWeight.w600, widget.myAppointmentsViewModel.getPatientAppointments(true, false);
borderRadius: 12.r, });
padding: EdgeInsets.symmetric(horizontal: 10.w), },
height: 40.h, backgroundColor: AppColors.secondaryLightRedColor,
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading), borderColor: AppColors.secondaryLightRedColor,
], textColor: AppColors.primaryRedColor,
).paddingAll(16.w), fontSize: (isFoldable || isTablet) ? 12.f : 14.f,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
).toShimmer2(isShow: widget.myAppointmentsViewModel.isMyAppointmentsLoading),
],
).paddingAll(16.w),
),
), ),
], ],
); );
@ -393,16 +417,16 @@ class _MedicalFileAppointmentCardState extends State<MedicalFileAppointmentCard>
// No action needed - go to details // No action needed - go to details
Navigator.of(context) Navigator.of(context)
.push(CustomPageRoute( .push(CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
)) ))
.then((val) {}); .then((val) {});
break; break;
case 10: case 10:
// Confirm appointment - go to details // Confirm appointment - go to details
Navigator.of(context) Navigator.of(context)
.push(CustomPageRoute( .push(CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
)) ))
.then((val) {}); .then((val) {});
break; break;
case 15: case 15:
@ -425,41 +449,42 @@ class _MedicalFileAppointmentCardState extends State<MedicalFileAppointmentCard>
children: [ children: [
// Message text // Message text
LocaleKeys.upcomingPaymentPending.tr(context: context).toText14( LocaleKeys.upcomingPaymentPending.tr(context: context).toText14(
color: AppColors.textColor, color: AppColors.textColor,
isCenter: true, isCenter: true,
), ),
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Countdown Timer - DD : HH : MM : SS format with labels // Countdown Timer - DD : HH : MM : SS format with labels
Directionality( Directionality(
textDirection: ui.TextDirection.ltr, child:Row( textDirection: ui.TextDirection.ltr,
mainAxisAlignment: MainAxisAlignment.center, child: Row(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
// Days children: [
_buildTimeUnit( // Days
_timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00', _buildTimeUnit(
LocaleKeys.days.tr(context: context), _timeRemaining != null ? _timeRemaining!.inDays.toString().padLeft(2, '0') : '00',
), LocaleKeys.days.tr(context: context),
_buildTimeSeparator(), ),
// Hours _buildTimeSeparator(),
_buildTimeUnit( // Hours
_timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00', _buildTimeUnit(
LocaleKeys.hours.tr(context: context), _timeRemaining != null ? _timeRemaining!.inHours.remainder(24).toString().padLeft(2, '0') : '00',
), LocaleKeys.hours.tr(context: context),
_buildTimeSeparator(), ),
// Minutes _buildTimeSeparator(),
_buildTimeUnit( // Minutes
_timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00', _buildTimeUnit(
LocaleKeys.minutes.tr(context: context), _timeRemaining != null ? _timeRemaining!.inMinutes.remainder(60).toString().padLeft(2, '0') : '00',
), LocaleKeys.minutes.tr(context: context),
_buildTimeSeparator(), ),
// Seconds _buildTimeSeparator(),
_buildTimeUnit( // Seconds
_timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00', _buildTimeUnit(
LocaleKeys.seconds.tr(context: context), _timeRemaining != null ? _timeRemaining!.inSeconds.remainder(60).toString().padLeft(2, '0') : '00',
), LocaleKeys.seconds.tr(context: context),
], ),
)), ],
)),
SizedBox(height: 24.h), SizedBox(height: 24.h),
// Green Acknowledge button with checkmark icon // Green Acknowledge button with checkmark icon
CustomButton( CustomButton(
@ -502,26 +527,25 @@ class _MedicalFileAppointmentCardState extends State<MedicalFileAppointmentCard>
// Confirm livecare - go to details // Confirm livecare - go to details
Navigator.of(context) Navigator.of(context)
.push(CustomPageRoute( .push(CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
)) ))
.then((val) {}); .then((val) {});
break; break;
case 90: case 90:
// Check-in - go to details // Check-in - go to details
Navigator.of(context) Navigator.of(context)
.push(CustomPageRoute( .push(CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
)) ))
.then((val) {}); .then((val) {});
break; break;
default: default:
// Default - go to details // Default - go to details
Navigator.of(context) Navigator.of(context)
.push(CustomPageRoute( .push(CustomPageRoute(
page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel),
)) ))
.then((val) {}); .then((val) {});
} }
} }
} }

@ -99,9 +99,8 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
title.toText14(isBold: true), title.toText14(isBold: true),
subTitle subTitle.toText12(color: AppColors.primaryRedColor, isBold: true, isEnglishOnly: true).toShimmer2(
.toText12(color: AppColors.primaryRedColor, isBold: true, isEnglishOnly: true) isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading),
.toShimmer2(isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading),
], ],
), ),
], ],
@ -159,7 +158,9 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
} }
} }
} else { } else {
name = ""; /// as per the mahmooud instruction, if user is not authenticated, we will not show any name in the greeting message name = "";
/// as per the mahmooud instruction, if user is not authenticated, we will not show any name in the greeting message
} }
return Scaffold( return Scaffold(
@ -167,7 +168,10 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
body: Consumer2<SymptomsCheckerViewModel, HmgServicesViewModel>( body: Consumer2<SymptomsCheckerViewModel, HmgServicesViewModel>(
builder: (context, viewModel, hmgServicesVM, child) { builder: (context, viewModel, hmgServicesVM, child) {
// Check if any field is empty // Check if any field is empty
bool hasEmptyFields = viewModel.selectedGender == null || viewModel.selectedAge == null || viewModel.selectedHeight == null || viewModel.selectedWeight == null; bool hasEmptyFields = viewModel.selectedGender == null ||
viewModel.selectedAge == null ||
viewModel.selectedHeight == null ||
viewModel.selectedWeight == null;
// Get display values // Get display values
String genderText = _getLocalizedGender(viewModel.selectedGender, context); String genderText = _getLocalizedGender(viewModel.selectedGender, context);
@ -313,6 +317,7 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
), ),
], ],
), ),
SizedBox(height: 24.h),
], ],
).paddingSymmetrical(24.w, 0), ).paddingSymmetrical(24.w, 0),
), ),

@ -181,7 +181,7 @@ class _UserInfoFlowManagerState extends State<UserInfoFlowManager> {
color: AppColors.whiteColor, color: AppColors.whiteColor,
borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)), borderRadius: BorderRadius.vertical(top: Radius.circular(24.r)),
), ),
padding: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h), padding: EdgeInsets.only(left: 24.w, right: 24.w, top: 16.h, bottom: 24.h),
child: SafeArea( child: SafeArea(
top: false, top: false,
child: isSingleEdit child: isSingleEdit

@ -1042,13 +1042,13 @@ packages:
source: hosted source: hosted
version: "1.2.1" version: "1.2.1"
image_picker_android: image_picker_android:
dependency: transitive dependency: "direct main"
description: description:
name: image_picker_android name: image_picker_android
sha256: "5e9bf126c37c117cf8094215373c6d561117a3cfb50ebc5add1a61dc6e224677" sha256: "66810af8e99b2657ee98e5c6f02064f69bb63f7a70e343937f70946c5f8c6622"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.13+10" version: "0.8.13+16"
image_picker_for_web: image_picker_for_web:
dependency: transitive dependency: transitive
description: description:
@ -1082,7 +1082,7 @@ packages:
source: hosted source: hosted
version: "0.2.2+1" version: "0.2.2+1"
image_picker_platform_interface: image_picker_platform_interface:
dependency: transitive dependency: "direct main"
description: description:
name: image_picker_platform_interface name: image_picker_platform_interface
sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c"

@ -101,9 +101,7 @@ dependencies:
flutter_widget_from_html: ^0.17.1 flutter_widget_from_html: ^0.17.1
huawei_map: ^6.12.0+301 huawei_map: ^6.12.0+301
flutter_image_compress: ^2.3.0 flutter_image_compress: ^2.3.0
scrollable_positioned_list: ^0.3.8 scrollable_positioned_list: ^0.3.8
in_app_review: ^2.0.11 in_app_review: ^2.0.11
dev_dependencies: dev_dependencies:

Loading…
Cancel
Save