import 'dart:async'; import 'dart:developer'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:get_it/get_it.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/cache_consts.dart'; import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/int_extensions.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/hospital/hospital_selection_view_model.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/insurance/insurance_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/appointments/appointment_queue_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/my_appointments_page.dart'; import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart'; import 'package:hmg_patient_app_new/presentation/authentication/quick_login.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart'; import 'package:hmg_patient_app_new/presentation/book_appointment/livecare/immediate_livecare_pending_request_page.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/contact_us.dart'; import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart'; import 'package:hmg_patient_app_new/presentation/hmg_services/services_page.dart'; import 'package:hmg_patient_app_new/presentation/home/data/landing_page_data.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/habib_wallet_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/large_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/small_service_card.dart'; import 'package:hmg_patient_app_new/presentation/home/widgets/welcome_widget.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/medical_file_page.dart'; import 'package:hmg_patient_app_new/presentation/notifications/notifications_list_page.dart'; import 'package:hmg_patient_app_new/presentation/profile_settings/profile_settings.dart'; import 'package:hmg_patient_app_new/presentation/rate_appointment/rate_appointment_doctor.dart'; import 'package:hmg_patient_app_new/presentation/todo_section/ancillary_procedures_details_page.dart'; import 'package:hmg_patient_app_new/presentation/todo_section/widgets/ancillary_orders_list.dart'; import 'package:hmg_patient_app_new/routes/app_routes.dart'; import 'package:hmg_patient_app_new/services/cache_service.dart'; import 'package:hmg_patient_app_new/services/zoom_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/countdown_timer.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/spring_page_route_builder.dart'; import 'package:provider/provider.dart'; import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); @override State createState() => _LandingPageState(); } class _LandingPageState extends State { late final AuthenticationViewModel authVM; bool isDone = false; late final HabibWalletViewModel habibWalletVM; late AppState appState; late MyAppointmentsViewModel myAppointmentsViewModel; final CacheService cacheService = GetIt.instance(); late AppointmentRatingViewModel appointmentRatingViewModel; late InsuranceViewModel insuranceViewModel; late ImmediateLiveCareViewModel immediateLiveCareViewModel; late BookAppointmentsViewModel bookAppointmentsViewModel; late EmergencyServicesViewModel emergencyServicesViewModel; late TodoSectionViewModel todoSectionViewModel; late NotificationsViewModel notificationsViewModel; final SwiperController _controller = SwiperController(); final ScrollController _horizontalScrollController = ScrollController(); @override void dispose() { _horizontalScrollController.dispose(); super.dispose(); } @override void initState() { authVM = context.read(); habibWalletVM = context.read(); appointmentRatingViewModel = context.read(); authVM.savePushTokenToAppState(); if (mounted) { authVM.checkLastLoginStatus(() { showQuickLogin(context); }); } scheduleMicrotask(() { if (appState.isAuthenticated) { habibWalletVM.initHabibWalletProvider(); habibWalletVM.getPatientBalanceAmount(); todoSectionViewModel.initializeTodoSectionViewModel(); immediateLiveCareViewModel.initImmediateLiveCare(); immediateLiveCareViewModel.getPatientLiveCareHistory(); myAppointmentsViewModel.initAppointmentsViewModel(); myAppointmentsViewModel.getPatientAppointments(true, false); emergencyServicesViewModel.checkPatientERAdvanceBalance(); // myAppointmentsViewModel.getPatientAppointmentQueueDetails(); notificationsViewModel.initNotificationsViewModel(); // Commented as per new requirement to remove rating popup from the app // if(!appState.isRatedVisible) { // appointmentRatingViewModel.getLastRatingAppointment(onSuccess: (response) { // if (appointmentRatingViewModel.appointmentRatedList.isNotEmpty) { // appointmentRatingViewModel.getAppointmentDetails(appointmentRatingViewModel.appointmentRatedList.last.appointmentNo!, appointmentRatingViewModel.appointmentRatedList.last.projectID!, // onSuccess: ((response) { // appointmentRatingViewModel.setClinicOrDoctor(false); // appointmentRatingViewModel.setTitle("Rate Doctor".needTranslation); // appointmentRatingViewModel.setSubTitle("How was your last visit with doctor?".needTranslation); // openLastRating(); // appState.setRatedVisible(true); // }), // ); // } // }, // ); // } } }); super.initState(); } @override Widget build(BuildContext context) { bookAppointmentsViewModel = Provider.of(context, listen: false); myAppointmentsViewModel = Provider.of(context, listen: false); insuranceViewModel = Provider.of(context, listen: false); immediateLiveCareViewModel = Provider.of(context, listen: false); emergencyServicesViewModel = Provider.of(context, listen: false); todoSectionViewModel = Provider.of(context, listen: false); notificationsViewModel = Provider.of(context, listen: false); appState = getIt.get(); return PopScope( canPop: false, child: Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: SingleChildScrollView( padding: EdgeInsets.only(top: kToolbarHeight + 0.h, bottom: 24), child: Column( spacing: 16.h, children: [ Row( spacing: 8.h, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ appState.isAuthenticated ? WelcomeWidget( onTap: () { Navigator.of(context).push(springPageRoute(ProfileSettings())); }, name: ('${appState.getAuthenticatedUser()!.firstName!} ${appState.getAuthenticatedUser()!.lastName!}'), imageUrl: appState.getAuthenticatedUser()?.gender == 1 ? AppAssets.maleImg : AppAssets.femaleImg, ).expanded : CustomButton( text: LocaleKeys.loginOrRegister.tr(context: context), onPressed: () async { await authVM.onLoginPressed(); // Navigator.pushReplacementNamed( // // context, // context, // AppRoutes.zoomCallPage, // // arguments: CallArguments(appointmentID, "111", "Patient", "40", "1", true, 1), // arguments: CallArguments("test123", "123", "Patient", "40", "0", true, 1), // // arguments: CallArguments("SmallDailyStandup9875", "123", "Patient", "40", "0", false, int.parse(widget.incomingCallData!.appointmentNo!)), // ); }, backgroundColor: AppColors.secondaryLightRedColor, borderColor: AppColors.secondaryLightRedColor, textColor: AppColors.primaryRedColor, fontSize: 14.f, fontWeight: FontWeight.w500, borderRadius: 12.r, padding: EdgeInsets.fromLTRB(12.h, 0, 12.h, 0), height: 40.h, ), Consumer(builder: (context, todoSectionVM, child) { return Row( mainAxisSize: MainAxisSize.min, spacing: 18.h, children: [ Stack(children: [ if (appState.isAuthenticated) Utils.buildSvgWithAssets(icon: AppAssets.bell, height: 24.h, width: 24.h).onPress(() async { if (appState.isAuthenticated) { notificationsViewModel.setNotificationStatusID(2); notificationsViewModel.getAllNotifications(); Navigator.of(context).push( CustomPageRoute( page: NotificationsListPage(), // page: LoginScreen(), ), ); } else { await authVM.onLoginPressed(); } }), (appState.isAuthenticated && (int.parse(todoSectionVM.notificationsCount ?? "0") > 0)) ? Positioned( right: 0, top: 0, child: Container( width: 8.w, height: 8.h, padding: EdgeInsets.all(4), decoration: BoxDecoration( color: AppColors.primaryRedColor, borderRadius: BorderRadius.circular(20.r), ), child: Text( "", style: TextStyle( color: Colors.white, fontSize: 8.f, ), textAlign: TextAlign.center, ), ), ) : SizedBox.shrink(), ]), Utils.buildSvgWithAssets(icon: AppAssets.indoor_nav_icon, height: 24.h, width: 24.w).onPress(() { openIndoorNavigationBottomSheet(context); }), Utils.buildSvgWithAssets(icon: AppAssets.contact_icon, height: 24.h, width: 24.h).onPress(() { showCommonBottomSheetWithoutHeight( context, title: LocaleKeys.contactUs.tr(), child: ContactUs(), callBackFunc: () {}, isFullScreen: false, ); }), !appState.isAuthenticated ? Utils.buildSvgWithAssets(icon: AppAssets.changeLanguageHomePageIcon, height: 24.h, width: 24.h).onPress(() { context.setLocale(appState.isArabic() ? Locale('en', 'US') : Locale('ar', 'SA')); }) : SizedBox.shrink() ], ); }), ], ).paddingSymmetrical(24.h, 0.h), !appState.isAuthenticated ? Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false, ), child: Padding( padding: EdgeInsets.all(16.h), child: Row( children: [ Utils.buildSvgWithAssets( width: 50.w, height: 60.h, icon: AppAssets.symptomCheckerIcon, fit: BoxFit.contain, ), SizedBox(width: 12.w), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.howAreYouFeelingToday.tr(context: context).toText14(weight: FontWeight.w600), LocaleKeys.checkYourSymptomsWithScale.tr(context: context).toText12(fontWeight: FontWeight.w500), SizedBox(height: 14.h), CustomButton( text: LocaleKeys.checkYourSymptoms.tr(context: context), onPressed: () async { context.navigateWithName(AppRoutes.userInfoSelection); }, padding: EdgeInsetsGeometry.zero, backgroundColor: Color(0xFF2B353E), borderColor: Color(0xFF2B353E), textColor: AppColors.whiteColor, fontSize: 14.f, fontWeight: FontWeight.w600, borderRadius: 12.r, height: 40.h, ), ], ).expanded ], ), ), ).paddingSymmetrical(24.w, 0.h) : SizedBox.shrink(), appState.isAuthenticated ? Column( children: [ SizedBox(height: 12.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.appointmentsAndVisits.tr(context: context).toText16(weight: FontWeight.w600), Row( children: [ LocaleKeys.viewAll.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), ], ), ], ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push(CustomPageRoute(page: MyAppointmentsPage())); }), SizedBox(height: 16.h), Consumer3( builder: (context, myAppointmentsVM, immediateLiveCareVM, todoSectionVM, child) { return myAppointmentsVM.isMyAppointmentsLoading ? Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, ), child: AppointmentCard( patientAppointmentHistoryResponseModel: PatientAppointmentHistoryResponseModel(), myAppointmentsViewModel: myAppointmentsViewModel, bookAppointmentsViewModel: bookAppointmentsViewModel, isLoading: true, isFromHomePage: true, ), ).paddingSymmetrical(24.h, 0.h) : myAppointmentsVM.patientAppointmentsHistoryList.isNotEmpty ? myAppointmentsVM.patientAppointmentsHistoryList.length == 1 ? Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, ), child: AppointmentCard( patientAppointmentHistoryResponseModel: myAppointmentsVM.patientAppointmentsHistoryList.first, myAppointmentsViewModel: myAppointmentsViewModel, bookAppointmentsViewModel: bookAppointmentsViewModel, isLoading: false, isFromHomePage: true, ), ).paddingSymmetrical(24.h, 0.h) : isTablet ? SizedBox( height: isFoldable ? 290.h : 255.h, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: 3, shrinkWrap: true, padding: EdgeInsets.only(left: 16.h, right: 16.h), itemBuilder: (context, index) { return SizedBox( height: 255.h, width: 250.w, child: getIndexSwiperCard(index), ); // return AnimationConfiguration.staggeredList( // position: index, // duration: const Duration(milliseconds: 1000), // child: SlideAnimation( // horizontalOffset: 100.0, // child: FadeInAnimation( // child: SizedBox( // height: 255.h, // width: 250.w, // child: getIndexSwiperCard(index), // ), // ), // ), // ); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox( width: 10.w, ), ), ) : Swiper( itemCount: myAppointmentsVM.isMyAppointmentsLoading ? 3 : myAppointmentsVM.patientAppointmentsHistoryList.length < 3 ? myAppointmentsVM.patientAppointmentsHistoryList.length : 3, layout: SwiperLayout.STACK, loop: true, itemWidth: MediaQuery.of(context).size.width - 48.h, indicatorLayout: PageIndicatorLayout.COLOR, axisDirection: AxisDirection.right, controller: _controller, itemHeight: 255.h, pagination: SwiperPagination( alignment: Alignment.bottomCenter, margin: EdgeInsets.only(top: 240.h + 8 + 24), builder: DotSwiperPaginationBuilder(color: Color(0xffD9D9D9), activeColor: AppColors.blackBgColor), ), itemBuilder: (BuildContext context, int index) { return getIndexSwiperCard(index); }, ) : Container( width: double.infinity, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true), child: Padding( padding: EdgeInsets.all(16.h), child: Column( children: [ Utils.buildSvgWithAssets(icon: AppAssets.home_calendar_icon, width: 32.h, height: 32.h), SizedBox(height: 12.h), LocaleKeys.noUpcomingAppointmentPleaseBook.tr(context: context).toText12(isCenter: true), SizedBox(height: 12.h), CustomButton( text: LocaleKeys.bookAppo.tr(context: context), onPressed: () { getIt.get().onTabChanged(0); Navigator.of(context).push(CustomPageRoute(page: BookAppointmentPage())); }, backgroundColor: Color(0xffFEE9EA), borderColor: Color(0xffFEE9EA), textColor: Color(0xffED1C2B), fontSize: 14.f, fontWeight: FontWeight.w500, padding: EdgeInsets.fromLTRB(10.h, 0, 10.h, 0), icon: AppAssets.add_icon, iconColor: AppColors.primaryRedColor, height: 40.h, ), ], ), ), ).paddingSymmetrical(24.h, 0.h); }, ), // Consumer for ER Online Check-In pending request Consumer( builder: (context, emergencyServicesVM, child) { return emergencyServicesVM.patientHasAdvanceERBalance ? Column( children: [ SizedBox(height: 16.h), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true, side: BorderSide(color: AppColors.primaryRedColor, width: 3.h), ), width: double.infinity, child: Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget( labelText: LocaleKeys.erOnlineCheckInRequest.tr(context: context), backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.10), textColor: AppColors.primaryRedColor, ), Utils.buildSvgWithAssets(icon: AppAssets.appointment_checkin_icon, width: 24.h, height: 24.h, iconColor: AppColors.primaryRedColor), ], ), SizedBox(height: 8.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.youHaveEROnlineCheckInRequest.tr(context: context).toText12(isBold: true), Transform.flip( flipX: getIt.get().isArabic(), child: Utils.buildSvgWithAssets( icon: AppAssets.forward_arrow_icon_small, iconColor: AppColors.blackColor, width: 20.h, height: 15.h, fit: BoxFit.contain, ), ), ], ), ], ), ), ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push(CustomPageRoute(page: ErOnlineCheckinHome())); // context.read().navigateToEROnlineCheckIn(); }), SizedBox(height: 12.h), ], ) : SizedBox(height: 0.h); }, ), SizedBox(height: 16.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.quickLinks.tr(context: context).toText16(weight: FontWeight.w600), Row( children: [ LocaleKeys.viewMedicalFile.tr(context: context).toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), ], ), ], ).paddingSymmetrical(24.h, 0.h).onPress(() { Navigator.of(context).push(CustomPageRoute(page: MedicalFilePage())); }), SizedBox(height: 16.h), Container( // height: 121.h, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), child: Column( children: [ SizedBox( height: 92.h + 32.h - 4.h, child: RawScrollbar( controller: _horizontalScrollController, thumbVisibility: true, radius: Radius.circular(10.0), thumbColor: AppColors.primaryRedColor, trackVisibility: true, trackColor: Color(0xffD9D9D9), trackBorderColor: Colors.transparent, trackRadius: Radius.circular(10.0), padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35), child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: LandingPageData.getLoggedInServiceCardsList.length, shrinkWrap: true, controller: _horizontalScrollController, padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h), itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 1000), child: SlideAnimation( horizontalOffset: 100.0, child: FadeInAnimation( child: SmallServiceCard( icon: LandingPageData.getLoggedInServiceCardsList[index].icon, title: LandingPageData.getLoggedInServiceCardsList[index].title, subtitle: LandingPageData.getLoggedInServiceCardsList[index].subtitle, iconColor: LandingPageData.getLoggedInServiceCardsList[index].iconColor!, textColor: LandingPageData.getLoggedInServiceCardsList[index].textColor, backgroundColor: LandingPageData.getLoggedInServiceCardsList[index].backgroundColor, isBold: LandingPageData.getLoggedInServiceCardsList[index].isBold, serviceName: LandingPageData.getLoggedInServiceCardsList[index].serviceName, ), ), ), ); }, separatorBuilder: (BuildContext cxt, int index) => 10.width, ), ), ), SizedBox(height: 16.h), ], ), ).paddingSymmetrical(24.h, 0.h), ], ) : Container( // height: 141.h, decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r), child: Column( children: [ SizedBox( height: 92.h + 32.h - 4.h, child: RawScrollbar( controller: _horizontalScrollController, thumbVisibility: true, radius: Radius.circular(10.0), thumbColor: AppColors.primaryRedColor, trackVisibility: true, trackColor: Color(0xffD9D9D9), trackBorderColor: Colors.transparent, trackRadius: Radius.circular(10.0), padding: EdgeInsets.only(top: 92.h + 32.h, left: MediaQuery.sizeOf(context).width / 2 - 35, right: MediaQuery.sizeOf(context).width / 2 - 35), child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: LandingPageData.getNotLoggedInServiceCardsList.length, shrinkWrap: true, controller: _horizontalScrollController, padding: EdgeInsets.only(left: 16.h, right: 16.h, top: 16.h, bottom: 12.h), // padding: EdgeInsets.zero, itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 1000), child: SlideAnimation( horizontalOffset: 100.0, child: FadeInAnimation( child: SmallServiceCard( serviceName: LandingPageData.getNotLoggedInServiceCardsList[index].serviceName, icon: LandingPageData.getNotLoggedInServiceCardsList[index].icon, title: LandingPageData.getNotLoggedInServiceCardsList[index].title, subtitle: LandingPageData.getNotLoggedInServiceCardsList[index].subtitle, iconColor: LandingPageData.getNotLoggedInServiceCardsList[index].iconColor!, textColor: LandingPageData.getNotLoggedInServiceCardsList[index].textColor, backgroundColor: LandingPageData.getNotLoggedInServiceCardsList[index].backgroundColor, isBold: LandingPageData.getNotLoggedInServiceCardsList[index].isBold, ), ), ), ); }, separatorBuilder: (BuildContext cxt, int index) => 0.width, ), ), ), SizedBox(height: 16.h), ], ), ).paddingSymmetrical(24.h, 0.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.services2.tr(context: context).toText18(weight: FontWeight.w600), Row( children: [ LocaleKeys.viewAllServices.tr(context: context).toText14(color: AppColors.primaryRedColor, weight: FontWeight.w500), SizedBox(width: 2.h), Icon(Icons.arrow_forward_ios, color: AppColors.primaryRedColor, size: 14.h), ], ).onPress(() { Navigator.of(context).push(CustomPageRoute(page: ServicesPage())); }), ], ).paddingSymmetrical(24.w, 0.h), SizedBox( height: 431.h, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: LandingPageData.getServiceCardsList.length, shrinkWrap: true, padding: EdgeInsets.only(left: 24.w, right: 24.w), itemBuilder: (context, index) { return AnimationConfiguration.staggeredList( position: index, duration: const Duration(milliseconds: 1000), child: SlideAnimation( horizontalOffset: 100.0, child: FadeInAnimation( child: FadedLargeServiceCard( serviceCardData: LandingPageData.getServiceCardsList[index], image: LandingPageData.getServiceCardsList[index].icon, title: LandingPageData.getServiceCardsList[index].title, subtitle: LandingPageData.getServiceCardsList[index].subtitle, icon: LandingPageData.getServiceCardsList[index].largeCardIcon, ), ), ), ); }, separatorBuilder: (BuildContext cxt, int index) => SizedBox(width: 16.w), ), ), appState.isAuthenticated ? HabibWalletCard() : SizedBox(), ], ), ), ), ); } // Main card selector based on index and priority Widget getIndexSwiperCard(int index) { // Index 0: Priority cards (Queue > LiveCare > Upcoming Appointment > History) if (index == 0) { return _buildFirstCardSlot(); } // Index 1: Secondary cards based on first card type if (index == 1) { return _buildSecondCardSlot(); } // Index 2: Tertiary cards if (index == 2) { return _buildThirdCardSlot(); } return Container(); } // First slot: Shows highest priority card Widget _buildFirstCardSlot() { if (myAppointmentsViewModel.isPatientHasQueueAppointment) { return _buildQueueCard(); } if (immediateLiveCareViewModel.patientHasPendingLiveCareRequest) { return _buildLiveCareRequestCard(); } if (myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.isNotEmpty) { return _buildAppointmentCardWrapper( myAppointmentsViewModel.patientUpcomingAppointmentsHistoryList.first, ); } return _buildAppointmentCardWrapper( myAppointmentsViewModel.patientAppointmentsHistoryList[0], ); } // Second slot: Shows appointment or ancillary orders Widget _buildSecondCardSlot() { final hasQueueOrLiveCare = myAppointmentsViewModel.isPatientHasQueueAppointment || immediateLiveCareViewModel.patientHasPendingLiveCareRequest; if (hasQueueOrLiveCare) { return _buildAppointmentCardWrapper( myAppointmentsViewModel.patientAppointmentsHistoryList.first, ); } if (todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty) { return _buildAncillaryOrderCardWrapper( todoSectionViewModel.patientAncillaryOrdersList.first, ); } return _buildAppointmentCardWrapper( myAppointmentsViewModel.patientAppointmentsHistoryList[1], ); } // Third slot: Shows ancillary orders or appointment Widget _buildThirdCardSlot() { final hasQueueOrLiveCare = myAppointmentsViewModel.isPatientHasQueueAppointment || immediateLiveCareViewModel.patientHasPendingLiveCareRequest; final hasAncillaryOrders = todoSectionViewModel.patientAncillaryOrdersList.isNotEmpty; if (hasQueueOrLiveCare && hasAncillaryOrders) { return _buildAncillaryOrderCardWrapper( todoSectionViewModel.patientAncillaryOrdersList.first, ); } return _buildAppointmentCardWrapper( myAppointmentsViewModel.patientAppointmentsHistoryList[2], ); } // Queue Card Widget Widget _buildQueueCard() { final currentQueue = myAppointmentsViewModel.currentPatientQueueDetails; final currentStatus = myAppointmentsViewModel.currentQueueStatus; return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.h, hasShadow: false, side: BorderSide( color: Utils.getCardBorderColor(currentStatus), width: 2.w, ), ), child: Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildQueueHeader(currentStatus), SizedBox(height: 8.h), _buildQueueGreeting(), SizedBox(height: 2.h), LocaleKeys.thankYouForPatience.tr().toText12( fontWeight: FontWeight.w500, color: AppColors.textColorLight, ), SizedBox(height: 8.h), currentQueue.queueNo!.toText28(isBold: true), SizedBox(height: 6.h), _buildServingNowSection(), SizedBox(height: 5.h), _buildQueueActionButton(currentStatus, currentQueue.roomNo ?? ""), ], ), ), ).onPress(() { Navigator.of(context).push( CustomPageRoute(page: AppointmentQueuePage()), ); }); } // Queue Card: Header with status chip and icon Widget _buildQueueHeader(int currentStatus) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AppCustomChipWidget( labelText: currentStatus == 0 ? LocaleKeys.inQueue.tr() : LocaleKeys.yourTurn.tr(), backgroundColor: Utils.getCardBorderColor(currentStatus).withValues(alpha: 0.20), textColor: Utils.getCardBorderColor(currentStatus), ), Utils.buildSvgWithAssets( icon: AppAssets.waiting_icon, width: 24.h, height: 24.h, ), ], ); } // Queue Card: Greeting text Widget _buildQueueGreeting() { return LocaleKeys.halaFirstName.tr(namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}).toText16(isBold: true); } // Queue Card: Currently serving section Widget _buildServingNowSection() { if (myAppointmentsViewModel.patientQueueDetailsList.isEmpty) { return SizedBox(height: 12.h); } final servingQueue = myAppointmentsViewModel.patientQueueDetailsList.first; final isVitalCall = servingQueue.callType == 1; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ "${LocaleKeys.servingNow.tr()}: ".toText14(isBold: true), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ servingQueue.queueNo!.toText12(isBold: true), SizedBox(width: 8.w), AppCustomChipWidget( deleteIcon: isVitalCall ? AppAssets.call_for_vitals : AppAssets.call_for_doctor, labelText: isVitalCall ? LocaleKeys.callForVitalSigns.tr() : LocaleKeys.callForDoctor.tr(), iconColor: isVitalCall ? AppColors.primaryRedColor : AppColors.successColor, textColor: isVitalCall ? AppColors.primaryRedColor : AppColors.successColor, iconSize: 14.w, backgroundColor: isVitalCall ? AppColors.primaryRedColor.withValues(alpha: 0.1) : AppColors.successColor.withValues(alpha: 0.1), labelPadding: EdgeInsetsDirectional.only( start: 8.h, end: -2.h, ), ), ], ), ], ); } // Queue Card: Action button Widget _buildQueueActionButton(int currentStatus, String roomNo) { return CustomButton( text: Utils.getCardButtonText(currentStatus, roomNo), onPressed: () {}, backgroundColor: Utils.getCardButtonColor(currentStatus), borderColor: Utils.getCardButtonColor(currentStatus).withValues(alpha: 0.01), textColor: Utils.getCardButtonTextColor(currentStatus), fontSize: 12.f, fontWeight: FontWeight.w600, borderRadius: 12.r, padding: EdgeInsets.symmetric(horizontal: 10.w), height: 40.h, iconColor: AppColors.whiteColor, iconSize: 18.h, ); } // LiveCare Request Card Widget Widget _buildLiveCareRequestCard() { final liveCareData = immediateLiveCareViewModel.patientLiveCareHistoryList[0]; return Column( children: [ SizedBox(height: 12.h), Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.r, hasShadow: true, side: BorderSide(color: AppColors.ratingColorYellow, width: 3.h), ), child: Padding( padding: EdgeInsets.all(16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ LocaleKeys.immediateLiveCareRequest.tr(context: context).toText16(isBold: true), SizedBox(height: 10.h), _buildLiveCareHeader(liveCareData), SizedBox(height: 10.h), _buildLiveCareGreeting(), SizedBox(height: 8.h), _buildLiveCareQueueInfo(liveCareData.patCount), SizedBox(height: 8.h), _buildLiveCareWaitingTime(), ], ), ), ).paddingSymmetrical(0.h, 0.h).onPress(() { Navigator.of(context).push( CustomPageRoute(page: ImmediateLiveCarePendingRequestPage()), ); }), SizedBox(height: 12.h), ], ); } // LiveCare Card: Header with status and date Widget _buildLiveCareHeader(liveCareData) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ AppCustomChipWidget( labelText: liveCareData.stringCallStatus, backgroundColor: AppColors.warningColorYellow.withValues(alpha: 0.20), textColor: AppColors.alertColor, ), SizedBox(width: 8.w), AppCustomChipWidget( icon: AppAssets.appointment_calendar_icon, labelText: DateUtil.formatDateToDate( DateUtil.convertStringToDate(liveCareData.arrivalTime), false, ), ), ], ), Utils.buildSvgWithAssets( icon: AppAssets.waiting_icon, width: 24.h, height: 24.h, ), ], ); } // LiveCare Card: Greeting Widget _buildLiveCareGreeting() { return LocaleKeys.halaFirstName.tr( namedArgs: {'firstName': appState.getAuthenticatedUser()!.firstName!}, context: context, ).toText16(isBold: true); } // LiveCare Card: Queue position info Widget _buildLiveCareQueueInfo(int? patCount) { return LocaleKeys.yourTurnIsAfterPatients.tr( namedArgs: {'count': (patCount ?? 0).toString()}, context: context, ).toText14(isBold: true); } // LiveCare Card: Waiting time counter Widget _buildLiveCareWaitingTime() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "${LocaleKeys.waitingTime.tr()}: ".toText12(isBold: true), SizedBox(height: 7.h), ValueListenableBuilder( valueListenable: immediateLiveCareViewModel.durationNotifier, builder: (context, duration, child) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ buildTime(duration), ], ); }, ), ], ); } // Appointment Card Wrapper (reusable) Widget _buildAppointmentCardWrapper(appointment) { return Container( decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: true, ), child: AppointmentCard( patientAppointmentHistoryResponseModel: appointment, myAppointmentsViewModel: myAppointmentsViewModel, bookAppointmentsViewModel: bookAppointmentsViewModel, isLoading: false, isFromHomePage: true, ), ); } // Ancillary Order Card Wrapper (reusable) Widget _buildAncillaryOrderCardWrapper(order) { return AncillaryOrderCard( order: order, isLoading: false, isOrdersList: false, onCheckIn: () { log("Check-in for order: ${order.orderNo}"); }, onViewDetails: () { Navigator.of(context).push( CustomPageRoute( page: AncillaryOrderDetailsList( appointmentNoVida: order.appointmentNo ?? 0, orderNo: order.orderNo ?? 0, projectID: order.projectID ?? 0, projectName: order.projectName ?? "", ), ), ); }, ); } void showQuickLogin(BuildContext context) { showCommonBottomSheetWithoutHeight( context, // title: "", isCloseButtonVisible: false, child: StatefulBuilder( builder: (context, setState) { return QuickLogin( isDone: isDone, onPressed: () { // sharedPref.setBool(HAS_ENABLED_QUICK_LOGIN, true); authVM.loginWithFingerPrintFace(() async { isDone = true; cacheService.saveBool(key: CacheConst.quickLoginEnabled, value: true); setState(() {}); await Future.delayed(Duration(milliseconds: 2000)).then((value) { if (mounted) Navigator.pop(context); }); }); }, ); }, ), // height: isDone == false ? ResponsiveExtension.screenHeight * 0.5 : ResponsiveExtension.screenHeight * 0.3, isFullScreen: false, callBackFunc: () { isDone = true; setState(() {}); }, ); } openLastRating() { showCommonBottomSheetWithoutHeight( context, titleWidget: Selector( selector: (_, vm) => vm.title, builder: (context, title, child) { final displayTitle = title ?? ''; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ displayTitle.toText20(weight: FontWeight.w600), (context.select((vm) => vm.subTitle) ?? '').toText12(), ], ); }, ), isCloseButtonVisible: true, child: StatefulBuilder( builder: (context, setState) { return RateAppointmentDoctor(); }, ), isFullScreen: false, ); } void openIndoorNavigationBottomSheet(BuildContext context) { showCommonBottomSheetWithoutHeight( title: LocaleKeys.selectHospital.tr(), context, child: ChangeNotifierProvider( create: (context) => HospitalSelectionBottomSheetViewModel(getIt()), child: Consumer( builder: (_, vm, __) => HospitalBottomSheetBody( searchText: vm.searchController, displayList: vm.displayList, onFacilityClicked: (value) { vm.setSelectedFacility(value); vm.getDisplayList(); }, onHospitalClicked: (hospital) { Navigator.pop(context); vm.openPenguin(hospital); }, onHospitalSearch: (value) { vm.searchHospitals(value ?? ""); }, selectedFacility: vm.selectedFacility, hmcCount: vm.hmcCount, hmgCount: vm.hmgCount, ), ), ), isFullScreen: false, isCloseButtonVisible: true, hasBottomPadding: false, backgroundColor: AppColors.bottomSheetBgColor, callBackFunc: () { context.read().clearSearchText(); }, ); } }