From e8c71e96d9f4d557298b3673f8c4754ce2f82b3a Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Wed, 22 Oct 2025 15:20:22 +0300 Subject: [PATCH 1/4] Updated README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e50fc23..1a459e3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # HMG Patient App -A comprehensive Flutter-based mobile application for HMG (Hospital Management Group) patients, +A comprehensive Flutter-based mobile application for HMG (Habib Medical Group) patients, providing seamless healthcare services and patient management features. ## 📱 Features @@ -162,5 +162,4 @@ flutter build ios --release This project is proprietary software developed for HMG Healthcare Group. - **Built with ❤️ for better healthcare accessibility** From 28f8aec60fa0157774e595d55b3ee06538766d43 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Wed, 22 Oct 2025 15:23:07 +0300 Subject: [PATCH 2/4] resolved fSize issue --- .../call_ambulance/tracking_screen.dart | 234 ++++++++---------- 1 file changed, 104 insertions(+), 130 deletions(-) diff --git a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart index a48ca10..0926d55 100644 --- a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart +++ b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart @@ -7,7 +7,6 @@ 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/emergency_services/emergency_services_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/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; @@ -21,37 +20,39 @@ import 'package:provider/provider.dart'; class TrackingScreen extends StatelessWidget { final OrderTrackingState state = OrderTrackingState.ended; + @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: Visibility( - visible: state == OrderTrackingState.ended, + visible: state == OrderTrackingState.ended, child: SafeArea( child: CustomButton( - height: 56.h, - backgroundColor: AppColors.bgGreenColor, - borderColor: Colors.transparent, - text: "Close".needTranslation, - textColor: AppColors.whiteColor, - onPressed: () {}, - ).paddingOnly(left:16.h,right:16.h), + height: 56.h, + backgroundColor: AppColors.bgGreenColor, + borderColor: Colors.transparent, + text: "Close".needTranslation, + textColor: AppColors.whiteColor, + onPressed: () {}, + ).paddingOnly(left: 16.h, right: 16.h), ), ), body: CollapsingListView( title: "Tracking Details".needTranslation, child: SingleChildScrollView( child: Column( - children: [ - animationSection(), - Column( - spacing: 16.h, - children: [OrderStatus(context), OrderTrackingId(), ContactSection()], - ).paddingAll(16.h), - ], - ))), + children: [ + animationSection(), + Column( + spacing: 16.h, + children: [OrderStatus(context), OrderTrackingId(), ContactSection()], + ).paddingAll(16.h), + ], + ))), ); } - animationSection(){ + + animationSection() { switch (state) { case OrderTrackingState.waitingForCall: case OrderTrackingState.dispactched: @@ -59,7 +60,7 @@ class TrackingScreen extends StatelessWidget { return Lottie.asset(AppAnimations.ambulance, repeat: true, reverse: false, width: 260.h, height: 200.h); case OrderTrackingState.ended: default: - return Lottie.asset(AppAnimations.checkmark, repeat: true, width: 260.h, height: 200.h); + return Lottie.asset(AppAnimations.checkmark, repeat: true, width: 260.h, height: 200.h); } } @@ -95,7 +96,9 @@ class TrackingScreen extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 16,), + SizedBox( + height: 16, + ), CustomButton( text: "Cancel Request".needTranslation, onPressed: () async {}, @@ -119,7 +122,7 @@ class TrackingScreen extends StatelessWidget { backgroundColor: AppColors.lightRedButtonColor, borderColor: Colors.transparent, text: "Share Your Live Locatin on Whatsapp".needTranslation, - fontSize: 12.fSize, + fontSize: 12.f, textColor: AppColors.primaryRedColor, iconColor: AppColors.primaryRedColor, onPressed: () {}, @@ -131,11 +134,7 @@ class TrackingScreen extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 12.h, - children: [ - dividerSection, - doctorSection(), - mapSection(context) - ], + children: [dividerSection, doctorSection(), mapSection(context)], ); case OrderTrackingState.ended: default: @@ -170,17 +169,14 @@ class TrackingScreen extends StatelessWidget { return Row( spacing: 16.h, children: [ - Utils.buildImgWithNetwork(url: "", iconColor: Colors.transparent) - .circle(52.h), + Utils.buildImgWithNetwork(url: "", iconColor: Colors.transparent).circle(52.h), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - "Dr. John Doe".toText16( - color: AppColors.textColor, weight: FontWeight.w600), + "Dr. John Doe".toText16(color: AppColors.textColor, weight: FontWeight.w600), SizedBox(height: 4.h), - "MBBS, MD - General Medicine".toText12( - color: AppColors.greyTextColor, fontWeight: FontWeight.w500), + "MBBS, MD - General Medicine".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500), ], ), ), @@ -204,23 +200,16 @@ class TrackingScreen extends StatelessWidget { Widget mapForRequestedCoordinate(BuildContext context) { // return SizedBox.shrink(); - if (context.read().isGMSAvailable || - Platform.isIOS) - return GMSMap( - myLocationEnabled: false, - currentLocation: - context.read().getGMSLocation(), - onCameraMoved: (value) => context - .read() - .handleGMSMapCameraMoved(value)); + if (context.read().isGMSAvailable || Platform.isIOS) + return GMSMap( + myLocationEnabled: false, + currentLocation: context.read().getGMSLocation(), + onCameraMoved: (value) => context.read().handleGMSMapCameraMoved(value)); else return HMSMap( myLocationEnabled: false, - currentLocation: - context.read().getHMSLocation(), - onCameraMoved: (value) => context - .read() - .handleHMSMapCameraMoved(value)); + currentLocation: context.read().getHMSLocation(), + onCameraMoved: (value) => context.read().handleHMSMapCameraMoved(value)); } informationRegardingTrackingSection() { @@ -229,71 +218,68 @@ class TrackingScreen extends StatelessWidget { children: [ currentStatus(), SizedBox(height: 4.h), - "You will receive a call from HMG for confirmation ".toText12( - color: AppColors.greyTextColor, fontWeight: FontWeight.w500) + "You will receive a call from HMG for confirmation ".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500) ], ); } currentStatus() { - switch (state) { - case OrderTrackingState.waitingForCall: - case OrderTrackingState.dispactched: - return RichText( - text: TextSpan(children: [ - TextSpan( - text: "Please wait for the call".needTranslation, - style: TextStyle( - fontSize: 21.fSize, - fontWeight: FontWeight.w600, - color: AppColors.textColor, - ), - ), - TextSpan( - text: "...".needTranslation, - style: TextStyle( - fontSize: 21.fSize, - fontWeight: FontWeight.w600, - color: AppColors.errorColor, - ), - ), - ]), - ); - case OrderTrackingState.returning: - return RichText( - text: TextSpan(children: [ - TextSpan( - text: "15:30".needTranslation, - style: TextStyle( - fontSize: 21.fSize, - fontWeight: FontWeight.w600, - color: AppColors.textColor, - ), - ), - TextSpan( - text: " mins ".needTranslation, - style: TextStyle( - fontSize: 21.fSize, - fontWeight: FontWeight.w600, - color: AppColors.errorColor, - ), - ), - TextSpan( - text: "to hospital".needTranslation, - style: TextStyle( - fontSize: 21.fSize, - fontWeight: FontWeight.w600, - color: AppColors.textColor, - ), - ), - ]), - ); - case OrderTrackingState.ended: - default: - return "Arrived" - .needTranslation - .toText21(color: AppColors.textColor, weight: FontWeight.w600); - } + switch (state) { + case OrderTrackingState.waitingForCall: + case OrderTrackingState.dispactched: + return RichText( + text: TextSpan(children: [ + TextSpan( + text: "Please wait for the call".needTranslation, + style: TextStyle( + fontSize: 21.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, + ), + ), + TextSpan( + text: "...".needTranslation, + style: TextStyle( + fontSize: 21.f, + fontWeight: FontWeight.w600, + color: AppColors.errorColor, + ), + ), + ]), + ); + case OrderTrackingState.returning: + return RichText( + text: TextSpan(children: [ + TextSpan( + text: "15:30".needTranslation, + style: TextStyle( + fontSize: 21.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, + ), + ), + TextSpan( + text: " mins ".needTranslation, + style: TextStyle( + fontSize: 21.f, + fontWeight: FontWeight.w600, + color: AppColors.errorColor, + ), + ), + TextSpan( + text: "to hospital".needTranslation, + style: TextStyle( + fontSize: 21.f, + fontWeight: FontWeight.w600, + color: AppColors.textColor, + ), + ), + ]), + ); + case OrderTrackingState.ended: + default: + return "Arrived".needTranslation.toText21(color: AppColors.textColor, weight: FontWeight.w600); + } } OrderTrackingId() { @@ -308,19 +294,15 @@ class TrackingScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.h, children: [ - "Req ID:1234567890" - .toText16(color: AppColors.textColor, weight: FontWeight.w600), + "Req ID:1234567890".toText16(color: AppColors.textColor, weight: FontWeight.w600), Row( spacing: 8.h, children: [ - Chip("location name".needTranslation, AppAssets.location_pickup, - AppColors.blackBgColor), - Chip("hotel name ".needTranslation, AppAssets.hospital, - AppColors.blackBgColor), + Chip("location name".needTranslation, AppAssets.location_pickup, AppColors.blackBgColor), + Chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), ], ), - Chip("hotel name ".needTranslation, AppAssets.hospital, - AppColors.blackBgColor), + Chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), ], ), ); @@ -350,11 +332,8 @@ class TrackingScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, spacing: 4.h, children: [ - "Contact Rapid Response Team (RRT)".needTranslation.toText14( - color: AppColors.textColor, weight: FontWeight.w600), - "1223456789".needTranslation.toText12( - color: AppColors.primaryRedColor, - fontWeight: FontWeight.w500), + "Contact Rapid Response Team (RRT)".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w600), + "1223456789".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(height: 8.h), ], ), @@ -390,27 +369,22 @@ class TrackingScreen extends StatelessWidget { getTitle(OrderTrackingState state) { switch (state) { case OrderTrackingState.waitingForCall: - return "Confirmation Call".needTranslation - .toText16(color: AppColors.textColor, weight: FontWeight.w600); + return "Confirmation Call".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); case OrderTrackingState.dispactched: - return "Pickup Up from Home".needTranslation - .toText16(color: AppColors.textColor, weight: FontWeight.w600); + return "Pickup Up from Home".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); case OrderTrackingState.returning: - return " On The Way To Hospital".needTranslation - .toText16(color: AppColors.textColor, weight: FontWeight.w600); + return " On The Way To Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); case OrderTrackingState.ended: default: - return "Arrived at Hospital".needTranslation - .toText16(color: AppColors.textColor, weight: FontWeight.w600); + return "Arrived at Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); } } mapSection(BuildContext context) { - return SizedBox( + return SizedBox( height: 170.h, width: double.infinity, - child: ClipRRect( - borderRadius: BorderRadius.circular(20.h),child: mapForRequestedCoordinate(context)), + child: ClipRRect(borderRadius: BorderRadius.circular(20.h), child: mapForRequestedCoordinate(context)), ); } } From dc5eba7d12d71cf8f737f96b69b24617126e2153 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Wed, 22 Oct 2025 15:24:18 +0300 Subject: [PATCH 3/4] refactored code --- .../call_ambulance/tracking_screen.dart | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart index 0926d55..9df0558 100644 --- a/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart +++ b/lib/presentation/emergency_services/call_ambulance/tracking_screen.dart @@ -21,6 +21,8 @@ import 'package:provider/provider.dart'; class TrackingScreen extends StatelessWidget { final OrderTrackingState state = OrderTrackingState.ended; + const TrackingScreen({super.key}); + @override Widget build(BuildContext context) { return Scaffold( @@ -45,7 +47,7 @@ class TrackingScreen extends StatelessWidget { animationSection(), Column( spacing: 16.h, - children: [OrderStatus(context), OrderTrackingId(), ContactSection()], + children: [orderStatus(context), orderTrackingId(), contactSection()], ).paddingAll(16.h), ], ))), @@ -59,12 +61,11 @@ class TrackingScreen extends StatelessWidget { case OrderTrackingState.returning: return Lottie.asset(AppAnimations.ambulance, repeat: true, reverse: false, width: 260.h, height: 200.h); case OrderTrackingState.ended: - default: return Lottie.asset(AppAnimations.checkmark, repeat: true, width: 260.h, height: 200.h); } } - OrderStatus(BuildContext context) { + orderStatus(BuildContext context) { return Container( padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( @@ -137,7 +138,6 @@ class TrackingScreen extends StatelessWidget { children: [dividerSection, doctorSection(), mapSection(context)], ); case OrderTrackingState.ended: - default: return Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 12.h, @@ -200,16 +200,17 @@ class TrackingScreen extends StatelessWidget { Widget mapForRequestedCoordinate(BuildContext context) { // return SizedBox.shrink(); - if (context.read().isGMSAvailable || Platform.isIOS) + if (context.read().isGMSAvailable || Platform.isIOS) { return GMSMap( myLocationEnabled: false, currentLocation: context.read().getGMSLocation(), onCameraMoved: (value) => context.read().handleGMSMapCameraMoved(value)); - else + } else { return HMSMap( myLocationEnabled: false, currentLocation: context.read().getHMSLocation(), onCameraMoved: (value) => context.read().handleHMSMapCameraMoved(value)); + } } informationRegardingTrackingSection() { @@ -277,12 +278,11 @@ class TrackingScreen extends StatelessWidget { ]), ); case OrderTrackingState.ended: - default: return "Arrived".needTranslation.toText21(color: AppColors.textColor, weight: FontWeight.w600); } } - OrderTrackingId() { + orderTrackingId() { return Container( padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( @@ -298,17 +298,17 @@ class TrackingScreen extends StatelessWidget { Row( spacing: 8.h, children: [ - Chip("location name".needTranslation, AppAssets.location_pickup, AppColors.blackBgColor), - Chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), + chip("location name".needTranslation, AppAssets.location_pickup, AppColors.blackBgColor), + chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), ], ), - Chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), + chip("hotel name ".needTranslation, AppAssets.hospital, AppColors.blackBgColor), ], ), ); } - Chip(String title, String iconString, Color iconColor) { + chip(String title, String iconString, Color iconColor) { return AppCustomChipWidget( labelText: title, icon: iconString, @@ -317,7 +317,7 @@ class TrackingScreen extends StatelessWidget { ); } - ContactSection() { + contactSection() { return Container( padding: EdgeInsets.all(16.h), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( @@ -375,7 +375,6 @@ class TrackingScreen extends StatelessWidget { case OrderTrackingState.returning: return " On The Way To Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); case OrderTrackingState.ended: - default: return "Arrived at Hospital".needTranslation.toText16(color: AppColors.textColor, weight: FontWeight.w600); } } From b698b74eb5a0a8fd720de0ce29434ea7d01b0892 Mon Sep 17 00:00:00 2001 From: faizatflutter Date: Sun, 2 Nov 2025 12:23:57 +0300 Subject: [PATCH 4/4] Design Updates --- lib/core/api_consts.dart | 12 +- lib/core/utils/size_utils.dart | 1 + .../appointment_details_page.dart | 140 +++-- .../widgets/appointment_card.dart | 594 +++++++++--------- .../widgets/appointment_doctor_card.dart | 85 ++- .../authentication/saved_login_screen.dart | 471 +++++++------- .../book_appointment_page.dart | 254 ++++---- lib/presentation/home/landing_page.dart | 10 +- .../medical_file/medical_file_page.dart | 36 +- .../onboarding/onboarding_screen.dart | 10 +- lib/widgets/appbar/app_bar_widget.dart | 10 +- lib/widgets/appbar/collapsing_list_view.dart | 14 +- lib/widgets/buttons/custom_button.dart | 6 +- lib/widgets/chip/app_custom_chip_widget.dart | 107 ++-- lib/widgets/custom_tab_bar.dart | 3 +- lib/widgets/language_switcher.dart | 2 +- 16 files changed, 927 insertions(+), 828 deletions(-) diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index ed2bba1..41ef922 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -1,5 +1,5 @@ -import 'package:hmg_patient_app_new/core/enums.dart'; import 'package:amazon_payfort/amazon_payfort.dart'; +import 'package:hmg_patient_app_new/core/enums.dart'; var MAX_SMALL_SCREEN = 660; final OPENTOK_API_KEY = '46209962'; @@ -570,7 +570,8 @@ var GET_CUSTOMER_INFO = "VerifyCustomer"; //Pharmacy -var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; +var GET_PHARMACY_CATEGORISE = + 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0'; var GET_OFFERS_CATEGORISE = 'discountcategories'; var GET_OFFERS_PRODUCTS = 'offerproducts/'; var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id='; @@ -722,14 +723,14 @@ const DEACTIVATE_ACCOUNT = 'Services/Patients.svc/REST/PatientAppleActivation_In //family Files -const FAMILY_FILES= 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; +const FAMILY_FILES = 'Services/Authentication.svc/REST/GetAllSharedRecordsByStatus'; var GET_PRESCRIPTION_INSTRUCTIONS_PDF = 'Services/ChatBot_Service.svc/REST/Chatbot_SendMedicationInstructionByWhatsApp'; 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 @@ -789,7 +790,6 @@ class ApiConsts { RCBaseUrl = 'https://rc.hmg.com/test/'; break; case AppEnvironmentTypeEnum.preProd: - baseUrl = "https://webservices.hmg.com/"; payFortEnvironment = FortEnvironment.production; applePayMerchantId = "merchant.com.hmgwebservices"; @@ -833,7 +833,7 @@ class ApiConsts { static final String getUserAgreementContent = 'Services/Patients.svc/REST/GetUsageAgreementText'; static final String checkPatientForRegistration = 'Services/Authentication.svc/REST/CheckPatientForRegisteration'; - static final String checkUserStatus= 'Services/NHIC.svc/REST/GetPatientInfo'; + static final String checkUserStatus = 'Services/NHIC.svc/REST/GetPatientInfo'; static final String insertPatientDeviceIMEIData = 'Services/Patients.svc/REST/Patient_INSERTDeviceIMEI'; static final String insertPatientMobileData = 'Services/MobileNotifications.svc/REST/Insert_PatientMobileDeviceInfo'; diff --git a/lib/core/utils/size_utils.dart b/lib/core/utils/size_utils.dart index 6566641..fdd0d30 100644 --- a/lib/core/utils/size_utils.dart +++ b/lib/core/utils/size_utils.dart @@ -216,6 +216,7 @@ class SizeUtils { log("longerSide: $longerSide"); log("shorterSide: $shorterSide"); log("isTablet: $isTablet"); + log("isFoldable: $isFoldable"); } } diff --git a/lib/presentation/appointments/appointment_details_page.dart b/lib/presentation/appointments/appointment_details_page.dart index f5b5b7e..5d583af 100644 --- a/lib/presentation/appointments/appointment_details_page.dart +++ b/lib/presentation/appointments/appointment_details_page.dart @@ -37,9 +37,9 @@ import '../../core/dependencies.dart'; import '../medical_file/widgets/medical_file_card.dart'; class AppointmentDetailsPage extends StatefulWidget { - AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel}); + const AppointmentDetailsPage({super.key, required this.patientAppointmentHistoryResponseModel}); - PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; @override State createState() => _AppointmentDetailsPageState(); @@ -115,7 +115,7 @@ class _AppointmentDetailsPageState extends State { Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, - borderRadius: 20.h, + borderRadius: 20.r, hasShadow: false, ), child: Padding( @@ -138,7 +138,7 @@ class _AppointmentDetailsPageState extends State { ? Row( children: [ Utils.buildSvgWithAssets(icon: AppAssets.livecare_clinic_icon, width: 40.h, height: 40.h), - SizedBox(width: 12.h), + SizedBox(width: 12.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -155,7 +155,8 @@ class _AppointmentDetailsPageState extends State { children: [ ClipRRect( clipBehavior: Clip.hardEdge, - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(24.r), + // Todo: what is this???? Api Key??? 😲 child: Image.network( "https://maps.googleapis.com/maps/api/staticmap?center=${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&zoom=14&size=350x165&maptype=roadmap&markers=color:red%7C${widget.patientAppointmentHistoryResponseModel.latitude},${widget.patientAppointmentHistoryResponseModel.longitude}&key=AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng", fit: BoxFit.contain, @@ -173,19 +174,19 @@ class _AppointmentDetailsPageState extends State { double.parse(widget.patientAppointmentHistoryResponseModel.longitude!), widget.patientAppointmentHistoryResponseModel.projectName); }, - backgroundColor: AppColors.textColor.withOpacity(0.8), - borderColor: - AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction) - .withOpacity(0.01), + backgroundColor: AppColors.textColor.withValues(alpha: 0.8), + borderColor: AppointmentType.getNextActionButtonColor( + widget.patientAppointmentHistoryResponseModel.nextAction) + .withValues(alpha: 0.01), textColor: AppColors.whiteColor, fontSize: 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + padding: EdgeInsets.symmetric(horizontal: 10.w), height: 40.h, icon: AppAssets.directions_icon, iconColor: AppColors.whiteColor, - iconSize: 13.h, + iconSize: 14.h, ).paddingAll(12.h), ), ), @@ -199,7 +200,7 @@ class _AppointmentDetailsPageState extends State { Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, - borderRadius: 20.h, + borderRadius: 20.r, hasShadow: false, ), child: Row( @@ -211,12 +212,14 @@ class _AppointmentDetailsPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.setReminder.tr(context: context).toText13(isBold: true), - "Notify me before the appointment".needTranslation.toText11(color: AppColors.textColorLight, weight: FontWeight.w500), + "Notify me before the appointment" + .needTranslation + .toText11(color: AppColors.textColorLight, weight: FontWeight.w500), ], ), const Spacer(), Switch( - activeColor: AppColors.successColor, + activeThumbColor: AppColors.successColor, activeTrackColor: AppColors.successColor.withValues(alpha: .15), value: widget.patientAppointmentHistoryResponseModel.hasReminder!, onChanged: (newValue) { @@ -237,8 +240,12 @@ class _AppointmentDetailsPageState extends State { "Lab & Radiology".needTranslation.toText18(isBold: true), SizedBox(height: 16.h), GridView( + padding: EdgeInsets.zero, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, crossAxisSpacing: 13.h, mainAxisSpacing: 13.h, childAspectRatio: 7 / 6), + crossAxisCount: isTablet || isFoldable ? 3 : 2, + crossAxisSpacing: 13.w, + mainAxisSpacing: 13.w, + ), physics: NeverScrollableScrollPhysics(), shrinkWrap: true, children: [ @@ -247,19 +254,36 @@ class _AppointmentDetailsPageState extends State { textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.lab_result_icon, - iconSize: 40, + iconSize: 40.w, isLargeText: true, ), MedicalFileCard( - label: LocaleKeys.radiology.tr(context: context), + label: "Radiology Results".needTranslation, textColor: AppColors.blackColor, backgroundColor: AppColors.whiteColor, svgIcon: AppAssets.radiology_icon, - iconSize: 40, + iconSize: 40.w, + isLargeText: true, + ), + MedicalFileCard( + label: LocaleKeys.labResults.tr(context: context), + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.lab_result_icon, + iconSize: 40.w, + isLargeText: true, + ), + MedicalFileCard( + label: "Radiology Results".needTranslation, + textColor: AppColors.blackColor, + backgroundColor: AppColors.whiteColor, + svgIcon: AppAssets.radiology_icon, + iconSize: 40.w, isLargeText: true, ), ], ), + SizedBox(height: 16.h), LocaleKeys.prescriptions.tr().toText18(isBold: true), SizedBox(height: 16.h), Consumer(builder: (context, prescriptionVM, child) { @@ -268,10 +292,10 @@ class _AppointmentDetailsPageState extends State { : Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: Colors.white, - borderRadius: 20.h, + borderRadius: 20.r, ), child: Padding( - padding: EdgeInsets.all(16.h), + padding: EdgeInsets.all(16.w), child: Column( children: [ ListView.separated( @@ -300,7 +324,7 @@ class _AppointmentDetailsPageState extends State { Column( children: [ SizedBox( - width: 150.h, + width: 150.w, child: prescriptionVM.prescriptionDetailsList[index].itemDescription! .toText12(isBold: true, maxLine: 1)), SizedBox( @@ -309,17 +333,19 @@ class _AppointmentDetailsPageState extends State { "Prescribed By: ${widget.patientAppointmentHistoryResponseModel.doctorTitle} ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}" .needTranslation .toText10( - weight: FontWeight.w500, color: AppColors.greyTextColor, letterSpacing: -0.4), + weight: FontWeight.w500, + color: AppColors.greyTextColor, + letterSpacing: -0.4), ), ], ), - SizedBox(width: 68.h), + SizedBox(width: 68.w), Transform.flip( flipX: appState.isArabic(), child: Utils.buildSvgWithAssets( icon: AppAssets.forward_arrow_icon, iconColor: AppColors.blackColor, - width: 18.h, + width: 18.w, height: 13.h, fit: BoxFit.contain, ), @@ -363,6 +389,35 @@ class _AppointmentDetailsPageState extends State { // ), // ), // SizedBox(width: 16.h), + Expanded( + child: CustomButton( + text: "Refill & Delivery".needTranslation, + onPressed: () { + Navigator.of(context) + .push( + CustomPageRoute( + page: PrescriptionsListPage(), + ), + ) + .then((val) { + prescriptionsViewModel.setPrescriptionsDetailsLoading(); + prescriptionsViewModel.getPrescriptionDetails(getPrescriptionRequestModel()); + }); + }, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + height: 40.h, + icon: AppAssets.requests, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ), + ), + + SizedBox(width: 16.w), Expanded( child: CustomButton( text: "All Prescriptions".needTranslation, @@ -381,9 +436,9 @@ class _AppointmentDetailsPageState extends State { backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12.h, + borderRadius: 12.r, height: 40.h, icon: AppAssets.requests, iconColor: AppColors.primaryRedColor, @@ -400,21 +455,22 @@ class _AppointmentDetailsPageState extends State { ], ), ], - ).paddingSymmetrical(24.h, 24.h), + ).paddingAll(24.w), ), ), ), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, - borderRadius: 24.h, + borderRadius: 24.r, hasShadow: true, ), child: SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20) + if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || + widget.patientAppointmentHistoryResponseModel.nextAction == 20) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -423,7 +479,9 @@ class _AppointmentDetailsPageState extends State { children: [ "Amount before tax".needTranslation.toText18(isBold: true), Utils.getPaymentAmountWithSymbol( - widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13, + widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), + AppColors.blackColor, + 13, isSaudiCurrency: true), ], ), @@ -432,8 +490,9 @@ class _AppointmentDetailsPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: - LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)), + child: LocaleKeys.upcomingPaymentNow + .tr(context: context) + .toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor)), "VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})" .needTranslation .toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -2), @@ -470,10 +529,10 @@ class _AppointmentDetailsPageState extends State { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - fontSize: 16, + fontSize: 16.f, fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), height: 50.h, icon: AppAssets.add_icon, iconColor: AppColors.whiteColor, @@ -486,13 +545,14 @@ class _AppointmentDetailsPageState extends State { handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction); }, backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction), - borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), + borderColor: + AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : AppColors.whiteColor, - fontSize: 16, + fontSize: 16.f, fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 50.h, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: 56.h, icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), iconColor: AppColors.whiteColor, iconSize: 18.h, diff --git a/lib/presentation/appointments/widgets/appointment_card.dart b/lib/presentation/appointments/widgets/appointment_card.dart index 1451bcb..c1a79aa 100644 --- a/lib/presentation/appointments/widgets/appointment_card.dart +++ b/lib/presentation/appointments/widgets/appointment_card.dart @@ -23,339 +23,313 @@ 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:hmg_patient_app_new/widgets/transitions/fade_page.dart'; -import 'package:smooth_corner/smooth_corner.dart'; -class AppointmentCard extends StatefulWidget { - AppointmentCard( - {super.key, - required this.patientAppointmentHistoryResponseModel, - required this.myAppointmentsViewModel, - required this.bookAppointmentsViewModel, - this.isLoading = false, - this.isFromHomePage = false, - this.isFromMedicalReport = false, - this.medicalFileViewModel}); +class AppointmentCard extends StatelessWidget { + final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + final MyAppointmentsViewModel myAppointmentsViewModel; + final bool isLoading; + final bool isFromHomePage; + final bool isFromMedicalReport; + final MedicalFileViewModel? medicalFileViewModel; + final BookAppointmentsViewModel bookAppointmentsViewModel; - PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; - MyAppointmentsViewModel myAppointmentsViewModel; - bool isLoading; - bool isFromHomePage; - bool isFromMedicalReport; - MedicalFileViewModel? medicalFileViewModel; - BookAppointmentsViewModel bookAppointmentsViewModel; + const AppointmentCard({ + super.key, + required this.patientAppointmentHistoryResponseModel, + required this.myAppointmentsViewModel, + required this.bookAppointmentsViewModel, + this.isLoading = false, + this.isFromHomePage = false, + this.isFromMedicalReport = false, + this.medicalFileViewModel, + }); - @override - State createState() => _AppointmentCardState(); -} - -class _AppointmentCardState extends State { @override Widget build(BuildContext context) { - AppState appState = getIt.get(); + final appState = getIt.get(); return InkWell( - onTap: () { - Navigator.of(context) - .push( - CustomPageRoute( - page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), - ), - ) - .then((val) { - widget.myAppointmentsViewModel.initAppointmentsViewModel(); - widget.myAppointmentsViewModel.getPatientAppointments(true, false); - }); - }, + onTap: () => _goToDetails(context), child: Padding( padding: EdgeInsets.all(14.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Wrap( - alignment: WrapAlignment.start, - direction: Axis.horizontal, - spacing: 6.h, - runSpacing: 6.h, - children: [ - AppCustomChipWidget( - icon: widget.isLoading - ? AppAssets.walkin_appointment_icon - : (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon), - iconColor: widget.isLoading - ? AppColors.textColor - : !widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! - ? AppColors.textColor - : AppColors.whiteColor, - labelText: widget.isLoading - ? "Walk In" - : widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! - ? LocaleKeys.livecare.tr(context: context) - : "Walk In".needTranslation, - backgroundColor: - widget.isLoading ? AppColors.greyColor : (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor), - textColor: widget.isLoading ? AppColors.textColor : (!widget.patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor), - ).toShimmer2(isShow: widget.isLoading), - AppCustomChipWidget( - labelText: widget.isLoading - ? "OutPatient" - : appState.isArabic() - ? widget.patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! - : widget.patientAppointmentHistoryResponseModel.isInOutPatientDescription!, - backgroundColor: AppColors.primaryRedColor.withOpacity(0.1), - textColor: AppColors.primaryRedColor, - ).toShimmer2(isShow: widget.isLoading), - AppCustomChipWidget( - labelText: widget.isLoading ? "Booked" : AppointmentType.getAppointmentStatusType(widget.patientAppointmentHistoryResponseModel.patientStatusType!), - backgroundColor: AppColors.successColor.withOpacity(0.1), - textColor: AppColors.successColor, - ).toShimmer2(isShow: widget.isLoading), - ], - ).toShimmer2(isShow: widget.isLoading), - ), - // TODO: Implement the logic to enable/disable the switch based on reminder status - // AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) - // ? SizedBox().toShimmer2(isShow: widget.isLoading) - // : Switch( - // activeColor: AppColors.successColor, - // activeTrackColor: AppColors.successColor.withValues(alpha: .15), - // thumbIcon: WidgetStateProperty.resolveWith( - // (Set states) { - // if (states.contains(WidgetState.selected)) { - // return const Icon(Icons.check); // Icon when switch is ON - // } - // return const Icon(Icons.close); // Icon when switch is OFF - // }, - // ), - // value: widget.isLoading ? false : widget.patientAppointmentHistoryResponseModel.hasReminder!, - // onChanged: (newValue) { - // setState(() { - // widget.myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel); - // }); - // }, - // ).toShimmer2(isShow: widget.isLoading), - ], - ), + _buildHeader(context, appState), SizedBox(height: 16.h), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.network( - widget.isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : widget.patientAppointmentHistoryResponseModel.doctorImageURL!, - width: 63.h, - height: 63.h, - fit: BoxFit.cover, - ).circle(100).toShimmer2(isShow: widget.isLoading), - SizedBox(width: 16.h), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - (widget.isLoading ? "https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png" : widget.patientAppointmentHistoryResponseModel.doctorNameObj!) - .toText16(isBold: true, maxlines: 1) - .toShimmer2(isShow: widget.isLoading), - SizedBox(height: 8.h), - Wrap( - direction: Axis.horizontal, - spacing: 3.h, - runSpacing: 4.h, - children: [ - widget.isFromHomePage - ? SizedBox.shrink() - : AppCustomChipWidget(labelText: widget.isLoading ? "Cardiology" : widget.patientAppointmentHistoryResponseModel.clinicName!).toShimmer2(isShow: widget.isLoading), - widget.isFromHomePage - ? SizedBox.shrink() - : AppCustomChipWidget(labelText: widget.isLoading ? "Olaya" : widget.patientAppointmentHistoryResponseModel.projectName!).toShimmer2(isShow: widget.isLoading), - AppCustomChipWidget( - icon: AppAssets.appointment_calendar_icon, - labelText: - widget.isLoading ? "Cardiology" : DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)) - .toShimmer2(isShow: widget.isLoading), - widget.isFromMedicalReport - ? SizedBox.shrink() - : AppCustomChipWidget( - icon: AppAssets.appointment_time_icon, - labelText: widget.isLoading - ? "Cardiology" - : DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate), false)) - .toShimmer2(isShow: widget.isLoading), - ], - ), - ], - ), - ), - ], - ), + _buildDoctorRow(context), SizedBox(height: 16.h), - widget.isFromMedicalReport - ? CustomButton( - text: "Select appointment".needTranslation, - onPressed: () { - widget.medicalFileViewModel!.setSelectedMedicalReportAppointment(widget.patientAppointmentHistoryResponseModel); - Navigator.pop(context, false); - }, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.checkmark_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ) - : Row( - children: [ - Expanded( - flex: 6, - child: AppointmentType.isArrived(widget.patientAppointmentHistoryResponseModel) - ? getArrivedAppointmentButton().toShimmer2(isShow: widget.isLoading) - : CustomButton( - text: AppointmentType.getNextActionText(widget.patientAppointmentHistoryResponseModel.nextAction), - onPressed: () { - Navigator.of(context) - .push(CustomPageRoute( - page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), - )) - .then((val) { - widget.myAppointmentsViewModel.initAppointmentsViewModel(); - widget.myAppointmentsViewModel.getPatientAppointments(true, false); - }); - }, - backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.15), - borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01), - textColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppointmentType.getNextActionIcon(widget.patientAppointmentHistoryResponseModel.nextAction), - iconColor: AppointmentType.getNextActionTextColor(widget.patientAppointmentHistoryResponseModel.nextAction), - iconSize: 15.h, - ).toShimmer2(isShow: widget.isLoading), - ), - SizedBox(width: 8.h), - Expanded( - flex: 1, - child: Container( - height: 40.h, - width: 40.h, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration( - color: AppColors.textColor, - borderRadius: 10.h, - ), - child: Transform.flip( - flipX: appState.isArabic(), - child: Utils.buildSvgWithAssets( - icon: AppAssets.forward_arrow_icon, - iconColor: AppColors.whiteColor, - width: 40.h, - height: 40.h, - fit: BoxFit.cover, - ), - ), - ).toShimmer2(isShow: widget.isLoading).onPress(() { - Navigator.of(context) - .push( - CustomPageRoute( - page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel), - ), - ) - .then((val) { - widget.myAppointmentsViewModel.initAppointmentsViewModel(); - widget.myAppointmentsViewModel.getPatientAppointments(true, false); - }); - }), - ), - ], - ), + _buildActionArea(context, appState), ], ), ), ); } - Widget getArrivedAppointmentButton() { - return DateTime.now().difference(DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15 - ? CustomButton( - text: LocaleKeys.askDoctor.tr(context: context), - onPressed: () {}, - backgroundColor: AppColors.secondaryLightRedColor, - borderColor: AppColors.secondaryLightRedColor, - textColor: AppColors.primaryRedColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.ask_doctor_icon, - iconColor: AppColors.primaryRedColor, - iconSize: 16.h, - ) - : CustomButton( - text: "Rebook with same doctor".needTranslation, - onPressed: () { - openDoctorScheduleCalendar(); - }, - backgroundColor: AppColors.greyColor, - borderColor: AppColors.greyColor, - textColor: AppColors.blackColor, - fontSize: 14, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), - height: 40.h, - icon: AppAssets.rebook_appointment_icon, - iconColor: AppColors.blackColor, - iconSize: 16.h, - ); + Widget _buildHeader(BuildContext context, AppState appState) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: _buildChips(context, appState)), + // Placeholder for future toggle / switch + ], + ); } - openDoctorScheduleCalendar() async { - DoctorsListResponseModel doctor = DoctorsListResponseModel( - clinicID: widget.patientAppointmentHistoryResponseModel.clinicID, - projectID: widget.patientAppointmentHistoryResponseModel.projectID, - doctorID: widget.patientAppointmentHistoryResponseModel.doctorID, - doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL, - doctorTitle: widget.patientAppointmentHistoryResponseModel.doctorTitle, - name: widget.patientAppointmentHistoryResponseModel.doctorNameObj, - nationalityFlagURL: "https://hmgwebservices.com/Images/flag/SYR.png", - speciality: [], - clinicName: widget.patientAppointmentHistoryResponseModel.clinicName, - projectName: widget.patientAppointmentHistoryResponseModel.projectName, + Widget _buildChips(BuildContext context, AppState appState) { + final isLiveCare = !isLoading && patientAppointmentHistoryResponseModel.isLiveCareAppointment!; + + return Wrap( + alignment: WrapAlignment.start, + direction: Axis.horizontal, + spacing: 6.h, + runSpacing: 6.h, + children: [ + AppCustomChipWidget( + icon: isLoading ? AppAssets.walkin_appointment_icon : (isLiveCare ? AppAssets.small_livecare_icon : AppAssets.walkin_appointment_icon), + iconColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor), + labelText: isLoading ? 'Walk In'.needTranslation : (isLiveCare ? LocaleKeys.livecare.tr(context: context) : 'Walk In'.needTranslation), + backgroundColor: isLoading ? AppColors.greyColor : (isLiveCare ? AppColors.successColor : AppColors.greyColor), + textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor), + ).toShimmer2(isShow: isLoading), + AppCustomChipWidget( + labelText: isLoading + ? 'OutPatient'.needTranslation + : (appState.isArabic() + ? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! + : patientAppointmentHistoryResponseModel.isInOutPatientDescription!), + backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1), + textColor: AppColors.primaryRedColor, + ).toShimmer2(isShow: isLoading), + AppCustomChipWidget( + labelText: isLoading + ? 'Booked'.needTranslation + : AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!), + backgroundColor: AppColors.successColor.withValues(alpha: 0.1), + textColor: AppColors.successColor, + ).toShimmer2(isShow: isLoading), + ], + ).toShimmer2(isShow: isLoading); + } + + Widget _buildDoctorRow(BuildContext context) { + return Row( + 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, + ).circle(100).toShimmer2(isShow: isLoading), + SizedBox(width: 16.h), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (isLoading + ? 'https://hmgwebservices.com/Images/MobileImages/DUBAI/unkown_female.png' + : patientAppointmentHistoryResponseModel.doctorNameObj!) + .toText16(isBold: true, maxlines: 1) + .toShimmer2(isShow: isLoading), + SizedBox(height: 8.h), + Wrap( + direction: Axis.horizontal, + spacing: 3.h, + runSpacing: 4.h, + children: [ + if (!isFromHomePage) + AppCustomChipWidget(labelText: isLoading ? 'Cardiology' : patientAppointmentHistoryResponseModel.clinicName!) + .toShimmer2(isShow: isLoading), + if (!isFromHomePage) + AppCustomChipWidget(labelText: isLoading ? 'Olaya' : patientAppointmentHistoryResponseModel.projectName!) + .toShimmer2(isShow: isLoading), + AppCustomChipWidget( + icon: AppAssets.appointment_calendar_icon, + labelText: isLoading + ? 'Cardiology' + : DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false), + ).toShimmer2(isShow: isLoading), + if (!isFromMedicalReport) + AppCustomChipWidget( + icon: AppAssets.appointment_time_icon, + labelText: isLoading + ? 'Cardiology' + : DateUtil.formatDateToTimeLang( + DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false), + ).toShimmer2(isShow: isLoading), + ], + ), + ], + ), + ), + ], ); - widget.bookAppointmentsViewModel.setSelectedDoctor(doctor); - LoaderBottomSheet.showLoader(); - await widget.bookAppointmentsViewModel.getDoctorFreeSlots( - isBookingForLiveCare: false, - onSuccess: (dynamic respData) async { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - title: "Pick a Date".needTranslation, - context, - child: AppointmentCalendar(), - isFullScreen: false, - isCloseButtonVisible: true, - callBackFunc: () {}, - ); + } + + Widget _buildActionArea(BuildContext context, AppState appState) { + if (isFromMedicalReport) { + return CustomButton( + text: 'Select appointment'.needTranslation, + onPressed: () { + medicalFileViewModel!.setSelectedMedicalReportAppointment(patientAppointmentHistoryResponseModel); + Navigator.pop(context, false); }, - onError: (err) { - LoaderBottomSheet.hideLoader(); - showCommonBottomSheetWithoutHeight( - context, - child: Utils.getErrorWidget(loadingText: err), - callBackFunc: () {}, - isFullScreen: false, - isCloseButtonVisible: true, - ); - }); + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isTablet || isFoldable ? 46.h : 40.h, + icon: AppAssets.checkmark_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ); + } + + return Row( + children: [ + Expanded( + flex: 6, + child: (AppointmentType.isArrived(patientAppointmentHistoryResponseModel) + ? _getArrivedButton(context) + : CustomButton( + text: AppointmentType.getNextActionText(patientAppointmentHistoryResponseModel.nextAction), + onPressed: () => _goToDetails(context), + backgroundColor: + AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.15), + borderColor: + AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withValues(alpha: 0.01), + textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), + fontSize: 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isTablet || isFoldable ? 46.h : 40.h, + icon: AppointmentType.getNextActionIcon(patientAppointmentHistoryResponseModel.nextAction), + iconColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), + iconSize: 15.h, + )) + .toShimmer2(isShow: isLoading), + ), + SizedBox(width: 8.h), + Expanded( + flex: 1, + child: Container( + height: (isFoldable || isTablet) ? 50.h : 40.h, + decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.textColor, borderRadius: 10.h), + child: Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, + iconColor: AppColors.whiteColor, + width: 24.w, + height: 24.h, + fit: BoxFit.contain, + ), + ), + ).toShimmer2(isShow: isLoading).onPress(() { + _goToDetails(context); + }), + ), + ], + ); + } + + Widget _getArrivedButton(BuildContext context) { + final isRecent = DateTime.now().difference(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)).inDays <= 15; + + if (isRecent) { + return CustomButton( + text: LocaleKeys.askDoctor.tr(context: context), + onPressed: () {}, + backgroundColor: AppColors.secondaryLightRedColor, + borderColor: AppColors.secondaryLightRedColor, + textColor: AppColors.primaryRedColor, + fontSize: 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isTablet || isFoldable ? 46.h : 40.h, + icon: AppAssets.ask_doctor_icon, + iconColor: AppColors.primaryRedColor, + iconSize: 16.h, + ); + } + + return CustomButton( + text: 'Rebook with same doctor'.needTranslation, + onPressed: () => openDoctorScheduleCalendar(context), + backgroundColor: AppColors.greyColor, + borderColor: AppColors.greyColor, + textColor: AppColors.blackColor, + fontSize: 14.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isTablet || isFoldable ? 46.h : 40.h, + icon: AppAssets.rebook_appointment_icon, + iconColor: AppColors.blackColor, + iconSize: 16.h, + ); + } + + void _goToDetails(BuildContext context) { + Navigator.of(context) + .push( + CustomPageRoute( + page: AppointmentDetailsPage(patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel), + ), + ) + .then((_) { + myAppointmentsViewModel.initAppointmentsViewModel(); + myAppointmentsViewModel.getPatientAppointments(true, false); + }); } - void performAppointmentNextAction(nextAction) {} + void openDoctorScheduleCalendar(BuildContext context) async { + final doctor = DoctorsListResponseModel( + clinicID: patientAppointmentHistoryResponseModel.clinicID, + projectID: patientAppointmentHistoryResponseModel.projectID, + doctorID: patientAppointmentHistoryResponseModel.doctorID, + doctorImageURL: patientAppointmentHistoryResponseModel.doctorImageURL, + doctorTitle: patientAppointmentHistoryResponseModel.doctorTitle, + name: patientAppointmentHistoryResponseModel.doctorNameObj, + nationalityFlagURL: 'https://hmgwebservices.com/Images/flag/SYR.png', + speciality: [], + clinicName: patientAppointmentHistoryResponseModel.clinicName, + projectName: patientAppointmentHistoryResponseModel.projectName, + ); + + bookAppointmentsViewModel.setSelectedDoctor(doctor); + LoaderBottomSheet.showLoader(); + + await bookAppointmentsViewModel.getDoctorFreeSlots( + isBookingForLiveCare: false, + onSuccess: (respData) async { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: AppointmentCalendar(), + callBackFunc: () {}, + title: 'Pick a Date'.needTranslation, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + onError: (err) { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: err), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }, + ); + } } diff --git a/lib/presentation/appointments/widgets/appointment_doctor_card.dart b/lib/presentation/appointments/widgets/appointment_doctor_card.dart index efc5a6b..2ea75d1 100644 --- a/lib/presentation/appointments/widgets/appointment_doctor_card.dart +++ b/lib/presentation/appointments/widgets/appointment_doctor_card.dart @@ -13,12 +13,17 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; class AppointmentDoctorCard extends StatelessWidget { - AppointmentDoctorCard({super.key, required this.patientAppointmentHistoryResponseModel, required this.onRescheduleTap, required this.onCancelTap, required this.onAskDoctorTap}); + AppointmentDoctorCard( + {super.key, + required this.patientAppointmentHistoryResponseModel, + required this.onRescheduleTap, + required this.onCancelTap, + required this.onAskDoctorTap}); - PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; - late Function onRescheduleTap; - late Function onCancelTap; - late Function onAskDoctorTap; + final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; + final VoidCallback onRescheduleTap; + final VoidCallback onCancelTap; + final VoidCallback onAskDoctorTap; @override Widget build(BuildContext context) { @@ -38,11 +43,11 @@ class AppointmentDoctorCard extends StatelessWidget { children: [ Image.network( patientAppointmentHistoryResponseModel.doctorImageURL!, - width: 63.h, + width: 63.w, height: 63.h, fit: BoxFit.cover, - ).circle(100), - SizedBox(width: 16.h), + ).circle(100.r), + SizedBox(width: 16.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -50,23 +55,41 @@ class AppointmentDoctorCard extends StatelessWidget { patientAppointmentHistoryResponseModel.doctorNameObj!.toText16(isBold: true), Wrap( direction: Axis.horizontal, - spacing: 3.h, - runSpacing: 4.h, + spacing: 6.w, + runSpacing: 6.h, children: [ - AppCustomChipWidget(labelText: patientAppointmentHistoryResponseModel.clinicName!), - AppCustomChipWidget(labelText: patientAppointmentHistoryResponseModel.projectName!), AppCustomChipWidget( - icon: AppAssets.doctor_calendar_icon, - labelText: - "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}, ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}"), + labelText: patientAppointmentHistoryResponseModel.clinicName!, + labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w), + ), + AppCustomChipWidget( + labelText: patientAppointmentHistoryResponseModel.projectName!, + labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), + ), AppCustomChipWidget( - icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppAssets.walkin_appointment_icon : AppAssets.small_livecare_icon, + icon: AppAssets.doctor_calendar_icon, + labelText: + "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}, ${DateUtil.formatDateToTimeLang( + DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), + false, + )}", + ), + AppCustomChipWidget( + icon: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! + ? AppAssets.walkin_appointment_icon + : AppAssets.small_livecare_icon, iconColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor, - labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? LocaleKeys.livecare.tr(context: context) : "Walk In".needTranslation, - backgroundColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor, + labelText: patientAppointmentHistoryResponseModel.isLiveCareAppointment! + ? LocaleKeys.livecare.tr(context: context) + : "Walk In".needTranslation, + backgroundColor: + !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.greyColor : AppColors.successColor, textColor: !patientAppointmentHistoryResponseModel.isLiveCareAppointment! ? AppColors.textColor : AppColors.whiteColor, ), - AppCustomChipWidget(icon: AppAssets.rating_icon, iconColor: AppColors.ratingColorYellow, labelText: "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}"), + AppCustomChipWidget( + icon: AppAssets.rating_icon, + iconColor: AppColors.ratingColorYellow, + labelText: "Rating: ${patientAppointmentHistoryResponseModel.decimalDoctorRate}"), ], ), ], @@ -93,10 +116,10 @@ class AppointmentDoctorCard extends StatelessWidget { backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, iconSize: 16.h, icon: AppAssets.ask_doctor_icon, @@ -110,10 +133,10 @@ class AppointmentDoctorCard extends StatelessWidget { backgroundColor: AppColors.greyColor, borderColor: AppColors.greyColor, textColor: AppColors.blackColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), height: 40.h, icon: AppAssets.rebook_appointment_icon, iconColor: AppColors.blackColor, @@ -129,9 +152,9 @@ class AppointmentDoctorCard extends StatelessWidget { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12.h, + borderRadius: 12.r, height: 40.h, icon: AppAssets.cancel, iconColor: AppColors.whiteColor, @@ -148,9 +171,9 @@ class AppointmentDoctorCard extends StatelessWidget { backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12.h, + borderRadius: 12.r, height: 40.h, icon: AppAssets.appointment_calendar_icon, iconColor: AppColors.primaryRedColor, @@ -167,9 +190,9 @@ class AppointmentDoctorCard extends StatelessWidget { backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, - fontSize: 14, + fontSize: 14.f, fontWeight: FontWeight.w500, - borderRadius: 12.h, + borderRadius: 12.r, height: 40.h, icon: AppAssets.cancel, iconColor: AppColors.whiteColor, diff --git a/lib/presentation/authentication/saved_login_screen.dart b/lib/presentation/authentication/saved_login_screen.dart index cfa4437..93b26c7 100644 --- a/lib/presentation/authentication/saved_login_screen.dart +++ b/lib/presentation/authentication/saved_login_screen.dart @@ -1,6 +1,5 @@ import 'package:easy_localization/easy_localization.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'; @@ -12,7 +11,6 @@ import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/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/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/app_bar_widget.dart'; @@ -21,7 +19,7 @@ import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:provider/provider.dart'; class SavedLogin extends StatefulWidget { - const SavedLogin({Key? key}) : super(key: key); + const SavedLogin({super.key}); @override _SavedLogin createState() => _SavedLogin(); @@ -65,248 +63,255 @@ class _SavedLogin extends State { body: SafeArea( child: Padding( padding: EdgeInsets.symmetric(horizontal: 24.h), - child: appState.getSelectDeviceByImeiRespModelElement != null ? Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(flex: 2), - // Welcome back text - LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor), - SizedBox(height: 16.h), - appState.getSelectDeviceByImeiRespModelElement != null - ? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase.toText26(isBold: true, height: 26 / 36, color: AppColors.textColor) - : SizedBox(), - SizedBox(height: 24.h), - Container( - padding: EdgeInsets.all(16.h), - decoration: BoxDecoration( - color: AppColors.whiteColor, - border: Border.all(color: AppColors.whiteColor), - borderRadius: BorderRadius.circular(24.h), - boxShadow: [ - BoxShadow(color: Color(0x0D000000), blurRadius: 16, offset: Offset(0, 0), spreadRadius: 5), - ], - ), - child: Column( + child: appState.getSelectDeviceByImeiRespModelElement != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - // Last login info - - ("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}").toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1), + const Spacer(flex: 2), + // Welcome back text + LocaleKeys.welcomeBack.tr().toText16(color: AppColors.inputLabelTextColor), + SizedBox(height: 16.h), appState.getSelectDeviceByImeiRespModelElement != null - ? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null - ? DateUtil.getFormattedDate(DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), "d MMMM, y 'at' HH:mm") - : '--') - .toText16(isBold: true, color: AppColors.textColor) + ? appState.getSelectDeviceByImeiRespModelElement!.name!.toCamelCase + .toText26(isBold: true, height: 26 / 36, color: AppColors.textColor) : SizedBox(), + SizedBox(height: 24.h), + Container( + padding: EdgeInsets.all(16.h), + decoration: BoxDecoration( + color: AppColors.whiteColor, + border: Border.all(color: AppColors.whiteColor), + borderRadius: BorderRadius.circular(24.h), + boxShadow: [ + BoxShadow(color: Color(0x0D000000), blurRadius: 16.h, offset: Offset(0, 0), spreadRadius: 5.h), + ], + ), + child: Column( + children: [ + // Last login info - appState.getSelectDeviceByImeiRespModelElement != null - ? Container( - margin: EdgeInsets.all(16.h), - child: Utils.buildSvgWithAssets( - icon: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!), - height: 54, - width: 54, - iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)) - : SizedBox(), - // Face ID login button - SizedBox( - height: 45, - child: CustomButton( - text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}", - onPressed: () { - if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { - authVm.loginWithFingerPrintFace(() {}); - } else { - authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); - } - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(0, 10, 0, 10), - icon: getTypeIcons(loginType.toInt), - //loginType == LoginTypeEnum.sms ? AppAssets.sms :AppAssets.whatsapp, - iconColor: loginType != LoginTypeEnum.whatsapp ? Colors.white : null, + ("${LocaleKeys.lastLoginBy.tr()} ${loginType.displayName}") + .toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -1), + appState.getSelectDeviceByImeiRespModelElement != null + ? (appState.getSelectDeviceByImeiRespModelElement!.createdOn != null + ? DateUtil.getFormattedDate( + DateUtil.convertStringToDate(appState.getSelectDeviceByImeiRespModelElement!.createdOn!), + "d MMMM, y 'at' HH:mm") + : '--') + .toText16(isBold: true, color: AppColors.textColor) + : SizedBox(), + + appState.getSelectDeviceByImeiRespModelElement != null + ? Container( + margin: EdgeInsets.all(16.h), + child: Utils.buildSvgWithAssets( + icon: getTypeIcons(appState.getSelectDeviceByImeiRespModelElement!.logInType!), + height: 54.h, + width: 54.w, + iconColor: loginType.toInt == 4 ? null : AppColors.primaryRedColor)) + : SizedBox(), + // Face ID login button + CustomButton( + text: "${LocaleKeys.loginBy.tr()} ${loginType.displayName}", + onPressed: () { + if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { + authVm.loginWithFingerPrintFace(() {}); + } else { + authVm.checkUserAuthentication(otpTypeEnum: loginType == LoginTypeEnum.sms ? OTPTypeEnum.sms : OTPTypeEnum.whatsapp); + } + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: Colors.white, + fontSize: 12.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + height: 40.h, + padding: EdgeInsets.symmetric(vertical: 10.h), + icon: getTypeIcons(loginType.toInt), + //loginType == LoginTypeEnum.sms ? AppAssets.sms :AppAssets.whatsapp, + iconColor: loginType != LoginTypeEnum.whatsapp ? Colors.white : null, + ), + ], ), ), - ], - ), - ), - const SizedBox(height: 24), - Padding( - padding: EdgeInsets.symmetric(horizontal: 16.0), - child: Text( - LocaleKeys.oR.tr(), - style: context.dynamicTextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - ), - const SizedBox(height: 24), - // OTP login button - loginType.toInt != 1 - ? Column( - children: [ - loginType.toInt != 1 - ? CustomButton( - text: LocaleKeys.loginByOTP.tr(), - onPressed: () { - showModalBottomSheet( - context: context, - isScrollControlled: true, - isDismissible: false, - useSafeArea: true, - backgroundColor: Colors.transparent, - enableDrag: false, - // Prevent dragging to avoid focus conflicts - builder: (bottomSheetContext) => StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) { - return Padding( - padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom), - child: SingleChildScrollView( - child: GenericBottomSheet( - countryCode: "966", - initialPhoneNumber: "", - textController: TextEditingController(), - isFromSavedLogin: true, - isEnableCountryDropdown: true, - onCountryChange: (value) {}, - onChange: (String? value) {}, - buttons: [ - Padding( - padding: EdgeInsets.only(bottom: 10.h), - child: CustomButton( - text: LocaleKeys.sendOTPSMS.tr(), - onPressed: () { - Navigator.of(context).pop(); - loginType = LoginTypeEnum.sms; - authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); - }, - backgroundColor: AppColors.primaryRedColor, - borderColor: AppColors.primaryRedColor, - textColor: AppColors.whiteColor, - icon: AppAssets.sms), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding(padding: EdgeInsets.symmetric(horizontal: 8.h), child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)), - ], - ), - Padding( - padding: const EdgeInsets.only(bottom: 10, top: 10), - child: CustomButton( - text: LocaleKeys.sendOTPWHATSAPP.tr(), - onPressed: () { - Navigator.of(context).pop(); - loginType = LoginTypeEnum.whatsapp; - authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); - }, - backgroundColor: AppColors.transparent, - borderColor: AppColors.textColor, - textColor: AppColors.textColor, - icon: AppAssets.whatsapp, - iconColor: null, + SizedBox(height: 24.h), + Padding( + padding: EdgeInsets.symmetric(horizontal: 16.w), + child: Text( + LocaleKeys.oR.tr(), + style: context.dynamicTextStyle(fontSize: 16.f, fontWeight: FontWeight.w500), + ), + ), + SizedBox(height: 24.h), + // OTP login button + loginType.toInt != 1 + ? Column( + children: [ + loginType.toInt != 1 + ? CustomButton( + text: LocaleKeys.loginByOTP.tr(), + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + useSafeArea: true, + backgroundColor: Colors.transparent, + enableDrag: false, + // Prevent dragging to avoid focus conflicts + builder: (bottomSheetContext) => + StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) { + return Padding( + padding: EdgeInsets.only(bottom: MediaQuery.of(bottomSheetContext).viewInsets.bottom), + child: SingleChildScrollView( + child: GenericBottomSheet( + countryCode: "966", + initialPhoneNumber: "", + textController: TextEditingController(), + isFromSavedLogin: true, + isEnableCountryDropdown: true, + onCountryChange: (value) {}, + onChange: (String? value) {}, + buttons: [ + Padding( + padding: EdgeInsets.only(bottom: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPSMS.tr(), + onPressed: () { + Navigator.of(context).pop(); + loginType = LoginTypeEnum.sms; + authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.sms); + }, + backgroundColor: AppColors.primaryRedColor, + borderColor: AppColors.primaryRedColor, + textColor: AppColors.whiteColor, + icon: AppAssets.sms), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.h), + child: (LocaleKeys.oR.tr()).toText16(color: AppColors.textColor)), + ], + ), + Padding( + padding: EdgeInsets.only(bottom: 10.h, top: 10.h), + child: CustomButton( + text: LocaleKeys.sendOTPWHATSAPP.tr(), + onPressed: () { + Navigator.of(context).pop(); + loginType = LoginTypeEnum.whatsapp; + authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); + }, + backgroundColor: AppColors.transparent, + borderColor: AppColors.textColor, + textColor: AppColors.textColor, + icon: AppAssets.whatsapp, + iconColor: null, + ), + ), + ], ), ), - ], - ), - ), - ); - }), - ); - }, - backgroundColor: AppColors.whiteColor, - borderColor: AppColors.borderOnlyColor, - textColor: AppColors.textColor, - borderWidth: 2, - padding: EdgeInsets.fromLTRB(0, 14, 0, 14), - icon: AppAssets.sms, - iconColor: AppColors.textColor, - ) - : Container(), + ); + }), + ); + }, + backgroundColor: AppColors.whiteColor, + borderColor: AppColors.borderOnlyColor, + textColor: AppColors.textColor, + borderWidth: 2, + padding: EdgeInsets.fromLTRB(0, 14.h, 0, 14.h), + icon: AppAssets.sms, + iconColor: AppColors.textColor, + ) + : Container(), + SizedBox( + height: 20.h, + ), + ], + ) + : CustomButton( + text: "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}", + icon: AppAssets.whatsapp, + iconColor: null, + onPressed: () { + if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { + authVm.loginWithFingerPrintFace(() {}); + } else { + loginType = LoginTypeEnum.whatsapp; + authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); + } + }, + backgroundColor: AppColors.whiteColor, + borderColor: Color(0xFF2E3039), + textColor: Color(0xFF2E3039), + borderWidth: 2.w, + padding: EdgeInsets.fromLTRB(0, 14.h, 0, 14.h), + ), + const Spacer(flex: 2), + // OR divider + + SizedBox(height: 24.h), + // Guest and Switch account + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: SizedBox( + height: 56.h, + child: CustomButton( + text: LocaleKeys.guest.tr(), + onPressed: () { + Navigator.of(context).pushReplacement( + MaterialPageRoute(builder: (BuildContext context) => LandingNavigation()), + ); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 16.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h), + // icon: "assets/images/svg/apple-finder.svg", + ), + ), + ), SizedBox( - height: 20, + width: MediaQuery.of(context).size.width * 0.05, + ), + Expanded( + child: SizedBox( + height: 56.h, + child: CustomButton( + text: LocaleKeys.switchAccount.tr(), + onPressed: () async { + await authVm.clearDefaultInputValues(); + Navigator.of(context).push( + MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), + ); + }, + backgroundColor: Color(0xffFEE9EA), + borderColor: Color(0xffFEE9EA), + textColor: Color(0xffED1C2B), + fontSize: 15.f, + fontWeight: FontWeight.w500, + borderRadius: 12.r, + padding: EdgeInsets.fromLTRB(0, 10.h, 0, 10.h), + // icon: "assets/images/svg/apple-finder.svg", + ), + ), ), ], - ) - : CustomButton( - text: "${LocaleKeys.loginBy.tr()} ${LoginTypeEnum.whatsapp.displayName}", - icon: AppAssets.whatsapp, - iconColor: null, - onPressed: () { - if (loginType == LoginTypeEnum.fingerprint || loginType == LoginTypeEnum.face) { - authVm.loginWithFingerPrintFace(() {}); - } else { - loginType = LoginTypeEnum.whatsapp; - authVm.checkUserAuthentication(otpTypeEnum: OTPTypeEnum.whatsapp); - } - }, - backgroundColor: AppColors.whiteColor, - borderColor: Color(0xFF2E3039), - textColor: Color(0xFF2E3039), - borderWidth: 2, - padding: EdgeInsets.fromLTRB(0, 14, 0, 14), ), - const Spacer(flex: 2), - // OR divider - - const SizedBox(height: 24), - // Guest and Switch account - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: SizedBox( - height: 56, - child: CustomButton( - text: LocaleKeys.guest.tr(), - onPressed: () { - Navigator.of(context).pushReplacement( - MaterialPageRoute(builder: (BuildContext context) => LandingNavigation()), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 16, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(0, 10, 0, 10), - // icon: "assets/images/svg/apple-finder.svg", - ), - ), - ), - SizedBox( - width: MediaQuery.of(context).size.width * 0.05, - ), - Expanded( - child: SizedBox( - height: 56, - child: CustomButton( - text: LocaleKeys.switchAccount.tr(), - onPressed: () async { - await authVm.clearDefaultInputValues(); - Navigator.of(context).push( - MaterialPageRoute(builder: (BuildContext context) => LoginScreen()), - ); - }, - backgroundColor: Color(0xffFEE9EA), - borderColor: Color(0xffFEE9EA), - textColor: Color(0xffED1C2B), - fontSize: 15, - fontWeight: FontWeight.w500, - borderRadius: 12, - padding: EdgeInsets.fromLTRB(0, 10, 0, 10), - // icon: "assets/images/svg/apple-finder.svg", - ), - ), - ), - ], - ), - const SizedBox(height: 20), - ], - ) : SizedBox.shrink(), + SizedBox(height: 20.h), + ], + ) + : SizedBox.shrink(), ), ), ); diff --git a/lib/presentation/book_appointment/book_appointment_page.dart b/lib/presentation/book_appointment/book_appointment_page.dart index b39c51e..02f9f22 100644 --- a/lib/presentation/book_appointment/book_appointment_page.dart +++ b/lib/presentation/book_appointment/book_appointment_page.dart @@ -13,7 +13,6 @@ import 'package:hmg_patient_app_new/features/authentication/authentication_view_ 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/features/my_appointments/appointment_via_region_viewmodel.dart'; -import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/doctor_list_api_response.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; @@ -21,14 +20,13 @@ import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immed 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'; import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart'; -import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.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/common_bottom_sheet.dart' show showCommonBottomSheetWithoutHeight; import 'package:hmg_patient_app_new/widgets/custom_tab_bar.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/transitions/fade_page.dart'; import 'package:provider/provider.dart'; import '../appointments/widgets/hospital_bottom_sheet/hospital_bottom_sheet_body.dart'; @@ -130,7 +128,9 @@ class _BookAppointmentPageState extends State { ], ), Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), ], ).onPress(() { bookAppointmentsViewModel.setIsClinicsListLoading(true); @@ -163,7 +163,9 @@ class _BookAppointmentPageState extends State { ], ), Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), ], ).onPress(() { bookAppointmentsViewModel.setIsDoctorSearchByNameStarted(false); @@ -194,7 +196,9 @@ class _BookAppointmentPageState extends State { ], ), Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), ], ).onPress(() { bookAppointmentsViewModel.setProjectID(null); @@ -214,115 +218,121 @@ class _BookAppointmentPageState extends State { Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, - borderRadius: 24.h, - hasShadow: false, - ), - child: Padding( - padding: EdgeInsets.all(16.h), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h), - SizedBox(width: 12.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), - "Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), - ], - ), - ], - ), - Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), - ], - ).onPress(() async { - //TODO Implement API to check for existing LiveCare Requests + borderRadius: 24.h, + hasShadow: false, + ), + child: Padding( + padding: EdgeInsets.all(16.h), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.search_by_clinic_icon, width: 40.h, height: 40.h), + SizedBox(width: 12.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Immediate Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), + "Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + ], + ), + ], + ), + Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + ], + ).onPress(() async { + //TODO Implement API to check for existing LiveCare Requests - LoaderBottomSheet.showLoader(); - await immediateLiveCareViewModel.getPatientLiveCareHistory(); - LoaderBottomSheet.hideLoader(); + LoaderBottomSheet.showLoader(); + await immediateLiveCareViewModel.getPatientLiveCareHistory(); + LoaderBottomSheet.hideLoader(); - if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) { - Navigator.of(context).push( - CustomPageRoute( - page: ImmediateLiveCarePendingRequestPage(), - ), - ); - } else { - Navigator.of(context).push( - CustomPageRoute( - page: SelectImmediateLiveCareClinicPage(), - ), - ); - } - }), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h), - SizedBox(width: 12.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), - "Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), - ], - ), - ], - ), - Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), - ], - ).onPress(() { - bookAppointmentsViewModel.setIsClinicsListLoading(true); - bookAppointmentsViewModel.setIsLiveCareSchedule(true); - Navigator.of(context).push( - CustomPageRoute( - page: SelectClinicPage(), - ), - ); - }), - SizedBox(height: 16.h), - Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), - SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h), - SizedBox(width: 12.h), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), - "".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), - ], - ), - ], - ), - Transform.flip( - flipX: appState.isArabic(), child: Utils.buildSvgWithAssets(icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), - ], - ).onPress(() { - openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION); - }), - ], - ), - ), - ), - ], + if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) { + Navigator.of(context).push( + CustomPageRoute( + page: ImmediateLiveCarePendingRequestPage(), + ), + ); + } else { + Navigator.of(context).push( + CustomPageRoute( + page: SelectImmediateLiveCareClinicPage(), + ), + ); + } + }), + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.search_by_doctor_icon, width: 40.h, height: 40.h), + SizedBox(width: 12.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Scheduled Consultation".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), + "Tap to select clinic".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + ], + ), + ], + ), + Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + ], + ).onPress(() { + bookAppointmentsViewModel.setIsClinicsListLoading(true); + bookAppointmentsViewModel.setIsLiveCareSchedule(true); + Navigator.of(context).push( + CustomPageRoute( + page: SelectClinicPage(), + ), + ); + }), + SizedBox(height: 16.h), + Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h), + SizedBox(height: 16.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Utils.buildSvgWithAssets(icon: AppAssets.search_by_region_icon, width: 40.h, height: 40.h), + SizedBox(width: 12.h), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Pharma LiveCare".needTranslation.toText14(color: AppColors.textColor, weight: FontWeight.w500), + "".needTranslation.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), + ], + ), + ], + ), + Transform.flip( + flipX: appState.isArabic(), + child: Utils.buildSvgWithAssets( + icon: AppAssets.forward_arrow_icon, iconColor: AppColors.textColor, width: 40.h, height: 40.h)), + ], + ).onPress(() { + openRegionListBottomSheet(context, RegionBottomSheetType.FOR_REGION); + }), + ], + ), + ), + ), + ], ).paddingSymmetrical(24.h, 0.h) : getLiveCareNotLoggedInUI(); default: @@ -335,8 +345,10 @@ class _BookAppointmentPageState extends State { regionalViewModel.flush(); regionalViewModel.setBottomSheetType(type); // AppointmentViaRegionViewmodel? viewmodel = null; - showCommonBottomSheetWithoutHeight(context, title: "", titleWidget: Consumer(builder: (_, data, __) => getTitle(data)), isDismissible: false, - child: Consumer(builder: (_, data, __) { + showCommonBottomSheetWithoutHeight(context, + title: "", + titleWidget: Consumer(builder: (_, data, __) => getTitle(data)), + isDismissible: false, child: Consumer(builder: (_, data, __) { return getRegionalSelectionWidget(data); }), callBackFunc: () {}); } @@ -395,7 +407,9 @@ class _BookAppointmentPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Immediate service".needTranslation.toText18(color: AppColors.textColor, isBold: true), - "No need to wait, you will get medical consultation immediately via video call".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + "No need to wait, you will get medical consultation immediately via video call" + .needTranslation + .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), @@ -427,7 +441,9 @@ class _BookAppointmentPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Doctor will contact".needTranslation.toText18(color: AppColors.textColor, isBold: true), - "A specialised doctor will contact you and will be able to view your medical history".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + "A specialised doctor will contact you and will be able to view your medical history" + .needTranslation + .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), @@ -443,7 +459,9 @@ class _BookAppointmentPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ "Free medicine delivery".needTranslation.toText18(color: AppColors.textColor, isBold: true), - "Offers free medicine delivery for the LiveCare appointment".needTranslation.toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), + "Offers free medicine delivery for the LiveCare appointment" + .needTranslation + .toText14(color: AppColors.greyTextColor, weight: FontWeight.w500), ], ), ), diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index fe8f025..4046023 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -263,15 +263,17 @@ class _LandingPageState extends State { ) : Container( width: double.infinity, - decoration: - RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), + decoration: RoundedRectangleBorder() + .toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Padding( padding: EdgeInsets.all(12.h), child: Column( children: [ Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), SizedBox(height: 12.h), - "You do not have any upcoming appointment. Please book an appointment".needTranslation.toText12(isCenter: true), + "You do not have any upcoming appointment. Please book an appointment" + .needTranslation + .toText12(isCenter: true), SizedBox(height: 12.h), CustomButton( text: LocaleKeys.bookAppo.tr(context: context), @@ -286,7 +288,7 @@ class _LandingPageState extends State { padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), icon: AppAssets.add_icon, iconColor: AppColors.primaryRedColor, - height: (isFoldable || isTablet) ? 56.h : 46.h, + height: 46.h, ), ], ), diff --git a/lib/presentation/medical_file/medical_file_page.dart b/lib/presentation/medical_file/medical_file_page.dart index 07bd7f3..472884f 100644 --- a/lib/presentation/medical_file/medical_file_page.dart +++ b/lib/presentation/medical_file/medical_file_page.dart @@ -174,7 +174,8 @@ class _MedicalFilePageState extends State { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Image.asset(appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, width: 56.w, height: 56.h), + Image.asset(appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.male_img : AppAssets.femaleImg, + width: 56.w, height: 56.h), SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -343,7 +344,9 @@ class _MedicalFilePageState extends State { }), SizedBox(height: 16.h), Consumer(builder: (context, myAppointmentsVM, child) { + // Provide an explicit height so the horizontal ListView has a bounded height return SizedBox( + height: 140.h, child: myAppointmentsVM.isMyAppointmentsLoading ? MedicalFileAppointmentCard( patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), @@ -355,7 +358,8 @@ class _MedicalFilePageState extends State { ? Container( padding: EdgeInsets.all(12.w), width: MediaQuery.of(context).size.width, - decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, hasShadow: true), + decoration: + RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 12.r, hasShadow: true), child: Column( children: [ Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), @@ -377,8 +381,8 @@ class _MedicalFilePageState extends State { fontSize: 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, - padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 0), - height: isFoldable ? 50.h : 40.h, + padding: EdgeInsets.symmetric(horizontal: 10.w), + height: isFoldable || isTablet ? 50.h : 40.h, icon: AppAssets.add_icon, iconColor: AppColors.primaryRedColor, ), @@ -501,11 +505,13 @@ class _MedicalFilePageState extends State { spacing: 3.w, runSpacing: 4.w, children: [ - AppCustomChipWidget(labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!), + AppCustomChipWidget( + labelText: prescriptionVM.patientPrescriptionOrders[index].clinicDescription!), AppCustomChipWidget( icon: AppAssets.doctor_calendar_icon, labelText: DateUtil.formatDateToDate( - DateUtil.convertStringToDate(prescriptionVM.patientPrescriptionOrders[index].appointmentDate), + DateUtil.convertStringToDate( + prescriptionVM.patientPrescriptionOrders[index].appointmentDate), false, ), ), @@ -528,7 +534,8 @@ class _MedicalFilePageState extends State { prescriptionVM.setPrescriptionsDetailsLoading(); Navigator.of(context).push( CustomPageRoute( - page: PrescriptionDetailPage(prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]), + page: PrescriptionDetailPage( + prescriptionsResponseModel: prescriptionVM.patientPrescriptionOrders[index]), ), ); }), @@ -638,7 +645,10 @@ class _MedicalFilePageState extends State { 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), + ("Dr. John Smith Smith Smith") + .toString() + .toText12(fontWeight: FontWeight.w500, isCenter: true, maxLine: 2) + .toShimmer2(isShow: true), ], ) : myAppointmentsVM.patientMyDoctorsList.isEmpty @@ -810,10 +820,14 @@ class _MedicalFilePageState extends State { text: "${LocaleKeys.updateInsurance.tr(context: context)} ${LocaleKeys.updateInsuranceSubtitle.tr(context: context)}", onPressed: () { insuranceViewModel.setIsInsuranceUpdateDetailsLoading(true); - insuranceViewModel.getPatientInsuranceDetailsForUpdate( - appState.getAuthenticatedUser()!.patientId.toString(), appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); + insuranceViewModel.getPatientInsuranceDetailsForUpdate(appState.getAuthenticatedUser()!.patientId.toString(), + appState.getAuthenticatedUser()!.patientIdentificationNo.toString()); showCommonBottomSheetWithoutHeight(context, - child: PatientInsuranceCardUpdateCard(), callBackFunc: () {}, title: "", isCloseButtonVisible: false, isFullScreen: false); + child: PatientInsuranceCardUpdateCard(), + callBackFunc: () {}, + title: "", + isCloseButtonVisible: false, + isFullScreen: false); }, backgroundColor: AppColors.bgGreenColor.withOpacity(0.20), borderColor: AppColors.bgGreenColor.withOpacity(0.0), diff --git a/lib/presentation/onboarding/onboarding_screen.dart b/lib/presentation/onboarding/onboarding_screen.dart index c1e714e..265559b 100644 --- a/lib/presentation/onboarding/onboarding_screen.dart +++ b/lib/presentation/onboarding/onboarding_screen.dart @@ -81,15 +81,15 @@ class _OnboardingScreenState extends State { duration: const Duration(milliseconds: 250), height: 6.h, width: selectedIndex == 0 ? 18.w : 6.w, - decoration: - BoxDecoration(color: selectedIndex == 0 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30.r)), + decoration: BoxDecoration( + color: selectedIndex == 0 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30.r)), ), AnimatedContainer( duration: const Duration(milliseconds: 250), height: 6.h, width: selectedIndex == 1 ? 18.w : 6.w, - decoration: - BoxDecoration(color: selectedIndex == 1 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30.r)), + decoration: BoxDecoration( + color: selectedIndex == 1 ? AppColors.textColor : AppColors.inputLabelTextColor, borderRadius: BorderRadius.circular(30.r)), ), ], ).paddingOnly(left: 24.w, right: 24.w), @@ -146,7 +146,7 @@ class _OnboardingScreenState extends State { ), ), ], - ).paddingOnly(bottom: 10.h), + ).paddingOnly(bottom: (isFoldable || isTablet) ? 20.h : 10.h), ], ), ), diff --git a/lib/widgets/appbar/app_bar_widget.dart b/lib/widgets/appbar/app_bar_widget.dart index 2c180ce..b3bc3eb 100644 --- a/lib/widgets/appbar/app_bar_widget.dart +++ b/lib/widgets/appbar/app_bar_widget.dart @@ -43,13 +43,13 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { quarterTurns: 90, child: Utils.buildSvgWithAssets( icon: AppAssets.arrow_back, - width: 32.h, + width: 32.w, height: 32.h, ), ) : Utils.buildSvgWithAssets( icon: AppAssets.arrow_back, - width: 32.h, + width: 32.w, height: 32.h, ), ), @@ -57,11 +57,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { ), // Logo - if (!hideLogoAndLang) - Utils.buildSvgWithAssets( - icon: AppAssets.habiblogo, - height: 24.h, - ), + if (!hideLogoAndLang) Utils.buildSvgWithAssets(icon: AppAssets.habiblogo, height: 24.h), if (!hideLogoAndLang) Expanded( diff --git a/lib/widgets/appbar/collapsing_list_view.dart b/lib/widgets/appbar/collapsing_list_view.dart index 1574a0a..f6db2f4 100644 --- a/lib/widgets/appbar/collapsing_list_view.dart +++ b/lib/widgets/appbar/collapsing_list_view.dart @@ -110,14 +110,18 @@ class CollapsingListView extends StatelessWidget { color: AppColors.blackColor, letterSpacing: -0.5), ).expanded, - if (logout != null) actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!), - if (report != null) actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(report!), + if (logout != null) + actionButton(context, t, title: "Logout".needTranslation, icon: AppAssets.logout).onPress(logout!), + if (report != null) + actionButton(context, t, title: "Report".needTranslation, icon: AppAssets.report_icon).onPress(report!), if (history != null) - actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(history!), + actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon) + .onPress(history!), if (instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(instructions!), if (requests != null) - actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(requests!), + actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon) + .onPress(requests!), if (search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(search!).paddingOnly(right: 24), if (trailing != null) trailing!, ], @@ -151,7 +155,7 @@ class CollapsingListView extends StatelessWidget { margin: EdgeInsets.only(right: 24.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.secondaryLightRedColor, - borderRadius: 12.r, + borderRadius: 10.r, ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/widgets/buttons/custom_button.dart b/lib/widgets/buttons/custom_button.dart index 6f33eda..f236bd9 100644 --- a/lib/widgets/buttons/custom_button.dart +++ b/lib/widgets/buttons/custom_button.dart @@ -56,7 +56,11 @@ class CustomButton extends StatelessWidget { return GestureDetector( onTap: isDisabled ? null : onPressed, child: Container( - height: height ?? (56.h), + height: height == null + ? 56.h + : (isFoldable || isTablet) + ? height! + 10.h + : height, width: width, padding: padding, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( diff --git a/lib/widgets/chip/app_custom_chip_widget.dart b/lib/widgets/chip/app_custom_chip_widget.dart index d720151..9ad7dbf 100644 --- a/lib/widgets/chip/app_custom_chip_widget.dart +++ b/lib/widgets/chip/app_custom_chip_widget.dart @@ -48,63 +48,62 @@ class AppCustomChipWidget extends StatelessWidget { final iconS = iconSize ?? 12.w; return GestureDetector( onTap: onChipTap, - child: SizedBox( - child: ChipTheme( - data: ChipThemeData( - padding: EdgeInsets.zero, - shape: SmoothRectangleBorder( - side: BorderSide( - width: 10.w, - color: Colors.transparent, // Crucially, set color to transparent - style: BorderStyle.none, - ), - borderRadius: BorderRadius.circular(8.r), // Apply a border radius of 16.0 + child: ChipTheme( + data: ChipThemeData( + padding: EdgeInsets.zero, + shape: SmoothRectangleBorder( + side: BorderSide( + width: 10.w, + color: Colors.transparent, // Crucially, set color to transparent + style: BorderStyle.none, ), + borderRadius: BorderRadius.circular(isFoldable || isTablet ? 6.r : 8.r), ), - child: icon.isNotEmpty - ? Chip( - avatar: icon.isNotEmpty - ? Utils.buildSvgWithAssets(icon: icon, width: iconS, height: iconS, iconColor: iconHasColor ? iconColor : null, fit: BoxFit.contain) - : SizedBox.shrink(), - label: richText ?? labelText!.toText10(weight: FontWeight.w500, letterSpacing: 0, color: textColor), - padding: padding, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - labelPadding: labelPadding ?? EdgeInsetsDirectional.only(start: 2.w, end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w), - backgroundColor: backgroundColor, - shape: shape ?? - SmoothRectangleBorder( - borderRadius: BorderRadius.circular(8.r), - smoothness: 10, - side: BorderSide(color: AppColors.transparent, width: 1.5), - ), - deleteIcon: deleteIcon?.isNotEmpty == true - ? Utils.buildSvgWithAssets( - icon: deleteIcon!, - width: iconS, - height: iconS, - iconColor: deleteIconHasColor ? deleteIconColor : null, - ) - : null, - onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null, - ) - : Chip( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - label: richText ?? labelText!.toText10(weight: FontWeight.w500, letterSpacing: 0, color: textColor), - padding: EdgeInsets.zero, - backgroundColor: backgroundColor, - shape: shape ?? - SmoothRectangleBorder( - borderRadius: BorderRadius.circular(8.r), - smoothness: 10, - side: BorderSide(color: AppColors.transparent, width: 1.5), - ), - labelPadding: labelPadding ?? EdgeInsetsDirectional.only(start: 2.w, end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w), - deleteIcon: deleteIcon?.isNotEmpty == true - ? Utils.buildSvgWithAssets(icon: deleteIcon!, width: iconS, height: iconS, iconColor: deleteIconHasColor ? deleteIconColor : null) - : null, - onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null, - ), ), + child: icon.isNotEmpty + ? Chip( + avatar: icon.isNotEmpty + ? Utils.buildSvgWithAssets( + icon: icon, width: iconS, height: iconS, iconColor: iconHasColor ? iconColor : null, fit: BoxFit.contain) + : SizedBox.shrink(), + label: richText ?? labelText!.toText10(weight: FontWeight.w500, letterSpacing: 0, color: textColor), + padding: padding, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + labelPadding: labelPadding ?? EdgeInsetsDirectional.only(start: 2.w, end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w), + backgroundColor: backgroundColor, + shape: shape ?? + SmoothRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + smoothness: 10, + side: BorderSide(color: AppColors.transparent, width: 1.5), + ), + deleteIcon: deleteIcon?.isNotEmpty == true + ? Utils.buildSvgWithAssets( + icon: deleteIcon!, + width: iconS, + height: iconS, + iconColor: deleteIconHasColor ? deleteIconColor : null, + ) + : null, + onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null, + ) + : Chip( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + label: richText ?? labelText!.toText10(weight: FontWeight.w500, letterSpacing: 0, color: textColor), + padding: EdgeInsets.zero, + backgroundColor: backgroundColor, + shape: shape ?? + SmoothRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + smoothness: 10, + side: BorderSide(color: AppColors.transparent, width: 1.5), + ), + labelPadding: labelPadding ?? EdgeInsetsDirectional.only(start: 2.w, end: deleteIcon?.isNotEmpty == true ? 2.w : 8.w), + deleteIcon: deleteIcon?.isNotEmpty == true + ? Utils.buildSvgWithAssets(icon: deleteIcon!, width: iconS, height: iconS, iconColor: deleteIconHasColor ? deleteIconColor : null) + : null, + onDeleted: deleteIcon?.isNotEmpty == true ? () {} : null, + ), ), ); } diff --git a/lib/widgets/custom_tab_bar.dart b/lib/widgets/custom_tab_bar.dart index 6f8c47f..9269e59 100644 --- a/lib/widgets/custom_tab_bar.dart +++ b/lib/widgets/custom_tab_bar.dart @@ -75,7 +75,6 @@ class CustomTabBarState extends State { } return Container( - height: 62.h, padding: EdgeInsets.all(4.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, @@ -87,7 +86,7 @@ class CustomTabBarState extends State { Widget myTab(CustomTabBarModel tabBar, int currentIndex) { bool isSelected = selectedIndex == currentIndex; return Container( - height: 54.h, + height: (isTablet || isFoldable) ? 60.h : 54.h, padding: EdgeInsets.only(top: 4.h, bottom: 4.h, left: 14.w, right: 14.w), alignment: Alignment.center, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( diff --git a/lib/widgets/language_switcher.dart b/lib/widgets/language_switcher.dart index ee54015..91e45b2 100644 --- a/lib/widgets/language_switcher.dart +++ b/lib/widgets/language_switcher.dart @@ -42,7 +42,7 @@ class _LanguageSelectorState extends State { return Stack(clipBehavior: Clip.none, children: [ Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular((12.r)), + borderRadius: BorderRadius.circular((10.r)), color: AppColors.secondaryLightRedColor, ), child: InkWell(