Compare commits
	
		
			18 Commits 
		
	
	
		
			a79dcad221
			...
			192d617350
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 192d617350 | 1 month ago | 
|  | e48e98d61b | 1 month ago | 
|  | d3978de92e | 1 month ago | 
|  | 92c3033087 | 1 month ago | 
|  | 5151997c7f | 1 month ago | 
|  | e5f4da4e16 | 1 month ago | 
|  | 1125437a56 | 1 month ago | 
|  | 4974121061 | 1 month ago | 
|  | 836a72ec22 | 1 month ago | 
|  | ba2785496d | 1 month ago | 
|  | 97038f1a25 | 1 month ago | 
|  | db880760c3 | 1 month ago | 
|  | 3e95999bf3 | 1 month ago | 
|  | f9bfc131a8 | 1 month ago | 
|  Haroon Amjad | 1c2564a1e2 | 1 month ago | 
|  | 6048b3b5f1 | 1 month ago | 
|  Haroon Amjad | a4854bbe4a | 1 month ago | 
|  Haroon Amjad | bdde6c224d | 1 month ago | 
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								| After Width: | Height: | Size: 83 KiB | 
| @ -0,0 +1,14 @@ | |||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ///class used to provide value for the [DynamicResultChart] to plot the values | ||||||
|  | class DataPoint { | ||||||
|  |   ///values that is displayed on the graph and dot is plotted on this | ||||||
|  |   final double value; | ||||||
|  |   ///label shown on the bottom of the graph | ||||||
|  |   String label; | ||||||
|  | 
 | ||||||
|  |   DataPoint( | ||||||
|  |       {required this.value, | ||||||
|  |         required this.label, | ||||||
|  |       }); | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | import 'dart:ui' show Color; | ||||||
|  | 
 | ||||||
|  | class ThresholdRange { | ||||||
|  |   final String label; | ||||||
|  |   final double value; | ||||||
|  |   final Color color; | ||||||
|  |   final Color lineColor; | ||||||
|  |   final String? actualValue; | ||||||
|  | 
 | ||||||
|  |   ThresholdRange( | ||||||
|  |       {required this.label, | ||||||
|  |       required this.value, | ||||||
|  |       required this.color, | ||||||
|  |       required this.lineColor, | ||||||
|  |       this.actualValue}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() { | ||||||
|  |     return 'ThresholdRange(label: $label, value: $value, color: ${color.value.toRadixString(16)}, lineColor: ${lineColor.value.toRadixString(16)})'; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,57 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  | 
 | ||||||
|  | class FamilyFileRequest { | ||||||
|  |   int? sharedPatientId; | ||||||
|  |   String? sharedPatientIdentificationId; | ||||||
|  |   int? searchType; | ||||||
|  |   String? sharedPatientMobileNumber; | ||||||
|  |   String? zipCode; | ||||||
|  |   bool? isRegister; | ||||||
|  |   int? patientStatus; | ||||||
|  |   bool? isDentalAllowedBackend; | ||||||
|  |   bool? isPatientExcluded; | ||||||
|  |   int? responseID; | ||||||
|  | 
 | ||||||
|  |   FamilyFileRequest({ | ||||||
|  |     this.sharedPatientId, | ||||||
|  |     this.sharedPatientIdentificationId, | ||||||
|  |     this.searchType, | ||||||
|  |     this.sharedPatientMobileNumber, | ||||||
|  |     this.zipCode, | ||||||
|  |     this.isRegister, | ||||||
|  |     this.patientStatus, | ||||||
|  |     this.isDentalAllowedBackend, | ||||||
|  |     this.isPatientExcluded, | ||||||
|  |     this.responseID, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   factory FamilyFileRequest.fromRawJson(String str) => FamilyFileRequest.fromJson(json.decode(str)); | ||||||
|  | 
 | ||||||
|  |   String toRawJson() => json.encode(toJson()); | ||||||
|  | 
 | ||||||
|  |   factory FamilyFileRequest.fromJson(Map<String, dynamic> json) => FamilyFileRequest( | ||||||
|  |         sharedPatientId: json["sharedPatientID"], | ||||||
|  |         sharedPatientIdentificationId: json["sharedPatientIdentificationID"], | ||||||
|  |         searchType: json["searchType"], | ||||||
|  |         sharedPatientMobileNumber: json["sharedPatientMobileNumber"], | ||||||
|  |         zipCode: json["zipCode"], | ||||||
|  |         isRegister: json["isRegister"], | ||||||
|  |         patientStatus: json["patientStatus"], | ||||||
|  |         isDentalAllowedBackend: json["isDentalAllowedBackend"], | ||||||
|  |         isPatientExcluded: json["IsPatientExcluded"], | ||||||
|  |         responseID: json["ReponseID"], | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |   Map<String, dynamic> toJson() => { | ||||||
|  |         "SharedPatientID": sharedPatientId, | ||||||
|  |         "SharedPatientIdentificationID": sharedPatientIdentificationId, | ||||||
|  |         "SearchType": searchType, | ||||||
|  |         "SharedPatientMobileNumber": sharedPatientMobileNumber, | ||||||
|  |         "zipCode": zipCode, | ||||||
|  |         "isRegister": isRegister, | ||||||
|  |         "PatientStatus": patientStatus, | ||||||
|  |         "isDentalAllowedBackend": isDentalAllowedBackend, | ||||||
|  |         "IsPatientExcluded": isPatientExcluded, | ||||||
|  |         "ReponseID": responseID, | ||||||
|  |       }; | ||||||
|  | } | ||||||
| @ -0,0 +1,430 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | import 'dart:developer'; | ||||||
|  | import 'dart:io'; | ||||||
|  | 
 | ||||||
|  | import 'package:easy_localization/easy_localization.dart'; | ||||||
|  | import 'package:flutter/material.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/enums.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/utils/utils.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/theme/colors.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/in_app_browser/InAppBrowser.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | 
 | ||||||
|  | class WalletPaymentConfirmPage extends StatefulWidget { | ||||||
|  |   const WalletPaymentConfirmPage({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<WalletPaymentConfirmPage> createState() => _WalletPaymentConfirmPageState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _WalletPaymentConfirmPageState extends State<WalletPaymentConfirmPage> { | ||||||
|  |   late PayfortViewModel payfortViewModel; | ||||||
|  |   late AppState appState; | ||||||
|  |   late HabibWalletViewModel habibWalletVM; | ||||||
|  | 
 | ||||||
|  |   MyInAppBrowser? browser; | ||||||
|  |   String selectedPaymentMethod = ""; | ||||||
|  | 
 | ||||||
|  |   String transID = ""; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     scheduleMicrotask(() { | ||||||
|  |       payfortViewModel.initPayfortViewModel(); | ||||||
|  |     }); | ||||||
|  |     super.initState(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     appState = getIt.get<AppState>(); | ||||||
|  |     habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false); | ||||||
|  |     payfortViewModel = Provider.of<PayfortViewModel>(context, listen: false); | ||||||
|  |     return Scaffold( | ||||||
|  |       backgroundColor: AppColors.bgScaffoldColor, | ||||||
|  |       body: Column( | ||||||
|  |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |         children: [ | ||||||
|  |           Expanded( | ||||||
|  |             child: CollapsingListView( | ||||||
|  |               title: "Select Payment Method", | ||||||
|  |               child: SingleChildScrollView( | ||||||
|  |                 child: Column( | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     SizedBox(height: 24.h), | ||||||
|  |                     Container( | ||||||
|  |                       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||||
|  |                         color: AppColors.whiteColor, | ||||||
|  |                         borderRadius: 20.h, | ||||||
|  |                         hasShadow: false, | ||||||
|  |                       ), | ||||||
|  |                       child: Row( | ||||||
|  |                         mainAxisSize: MainAxisSize.max, | ||||||
|  |                         children: [ | ||||||
|  |                           Column( | ||||||
|  |                             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                             children: [ | ||||||
|  |                               Image.asset(AppAssets.mada, width: 72.h, height: 25.h).toShimmer2(isShow: false), | ||||||
|  |                               SizedBox(height: 16.h), | ||||||
|  |                               "Mada".needTranslation.toText16(isBold: true).toShimmer2(isShow: false), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           SizedBox(width: 8.h), | ||||||
|  |                           const Spacer(), | ||||||
|  |                           Transform.flip( | ||||||
|  |                             flipX: appState.isArabic() ? true : false, | ||||||
|  |                             child: Utils.buildSvgWithAssets( | ||||||
|  |                               icon: AppAssets.forward_arrow_icon, | ||||||
|  |                               iconColor: AppColors.blackColor, | ||||||
|  |                               width: 18.h, | ||||||
|  |                               height: 13.h, | ||||||
|  |                               fit: BoxFit.contain, | ||||||
|  |                             ).toShimmer2(isShow: false), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ).paddingSymmetrical(16.h, 16.h), | ||||||
|  |                     ).paddingSymmetrical(24.h, 0.h).onPress(() { | ||||||
|  |                       selectedPaymentMethod = "MADA"; | ||||||
|  |                       openPaymentURL("mada"); | ||||||
|  |                     }), | ||||||
|  |                     SizedBox(height: 16.h), | ||||||
|  |                     Container( | ||||||
|  |                       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||||
|  |                         color: AppColors.whiteColor, | ||||||
|  |                         borderRadius: 20.h, | ||||||
|  |                         hasShadow: false, | ||||||
|  |                       ), | ||||||
|  |                       child: Row( | ||||||
|  |                         mainAxisSize: MainAxisSize.max, | ||||||
|  |                         children: [ | ||||||
|  |                           Column( | ||||||
|  |                             crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                             children: [ | ||||||
|  |                               Row( | ||||||
|  |                                 children: [ | ||||||
|  |                                   Image.asset(AppAssets.visa, width: 40.h, height: 40.h), | ||||||
|  |                                   SizedBox(width: 8.h), | ||||||
|  |                                   Image.asset(AppAssets.Mastercard, width: 40.h, height: 40.h), | ||||||
|  |                                 ], | ||||||
|  |                               ).toShimmer2(isShow: false), | ||||||
|  |                               SizedBox(height: 16.h), | ||||||
|  |                               "Visa or Mastercard".needTranslation.toText16(isBold: true).toShimmer2(isShow: false), | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                           SizedBox(width: 8.h), | ||||||
|  |                           const Spacer(), | ||||||
|  |                           Transform.flip( | ||||||
|  |                             flipX: appState.isArabic() ? true : false, | ||||||
|  |                             child: Utils.buildSvgWithAssets( | ||||||
|  |                               icon: AppAssets.forward_arrow_icon, | ||||||
|  |                               iconColor: AppColors.blackColor, | ||||||
|  |                               width: 18.h, | ||||||
|  |                               height: 13.h, | ||||||
|  |                               fit: BoxFit.contain, | ||||||
|  |                             ).toShimmer2(isShow: false), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ).paddingSymmetrical(16.h, 16.h), | ||||||
|  |                     ).paddingSymmetrical(24.h, 0.h).onPress(() { | ||||||
|  |                       selectedPaymentMethod = "VISA"; | ||||||
|  |                       openPaymentURL("visa"); | ||||||
|  |                     }), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           Container( | ||||||
|  |             // height: 200.h, | ||||||
|  |             width: MediaQuery.of(context).size.width, | ||||||
|  |             decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||||
|  |               color: AppColors.whiteColor, | ||||||
|  |               borderRadius: 24.h, | ||||||
|  |               hasShadow: true, | ||||||
|  |             ), | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |               children: [ | ||||||
|  |                 SizedBox(height: 24.h), | ||||||
|  |                 habibWalletVM.depositorName.toText18(isBold: true).paddingSymmetrical(24.h, 0.h), | ||||||
|  |                 SizedBox(height: 12.h), | ||||||
|  |                 Wrap( | ||||||
|  |                   direction: Axis.horizontal, | ||||||
|  |                   spacing: 4.h, | ||||||
|  |                   runSpacing: 4.h, | ||||||
|  |                   children: [ | ||||||
|  |                     AppCustomChipWidget(labelText: "${LocaleKeys.fileno.tr(context: context)}.: ${habibWalletVM.fileNumber}"), | ||||||
|  |                     AppCustomChipWidget(labelText: "${LocaleKeys.mobileNumber.tr(context: context)}: ${habibWalletVM.mobileNumber}"), | ||||||
|  |                     AppCustomChipWidget(labelText: "${habibWalletVM.selectedHospital!.name}"), | ||||||
|  |                   ], | ||||||
|  |                 ).paddingSymmetrical(24.h, 0.h), | ||||||
|  |                 SizedBox(height: 16.h), | ||||||
|  |                 Divider(color: AppColors.borderOnlyColor.withValues(alpha: 0.1), height: 1.h).paddingSymmetrical(24.h, 0.h), | ||||||
|  |                 SizedBox(height: 16.h), | ||||||
|  |                 Row( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                   children: [ | ||||||
|  |                     "Total amount to pay".needTranslation.toText16(isBold: true), | ||||||
|  |                     Utils.getPaymentAmountWithSymbol(habibWalletVM.walletRechargeAmount.toString().toText24(isBold: true), AppColors.blackColor, 15.h, isSaudiCurrency: true), | ||||||
|  |                   ], | ||||||
|  |                 ).paddingSymmetrical(24.h, 0.h), | ||||||
|  |                 SizedBox(height: 12.h), | ||||||
|  |                 Platform.isIOS | ||||||
|  |                     ? Utils.buildSvgWithAssets( | ||||||
|  |                         icon: AppAssets.apple_pay_button, | ||||||
|  |                         width: 200.h, | ||||||
|  |                         height: 56.h, | ||||||
|  |                         fit: BoxFit.contain, | ||||||
|  |                       ).paddingSymmetrical(24.h, 0.h).onPress(() { | ||||||
|  |                         if (Utils.havePrivilege(103)) { | ||||||
|  |                           startApplePay(); | ||||||
|  |                         } else { | ||||||
|  |                           openPaymentURL("ApplePay"); | ||||||
|  |                         } | ||||||
|  |                       }) | ||||||
|  |                     : SizedBox(height: 12.h), | ||||||
|  |                 SizedBox(height: 32.h), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   startApplePay() async { | ||||||
|  |     LoaderBottomSheet.showLoader(); | ||||||
|  |     ApplePayInsertRequest applePayInsertRequest = ApplePayInsertRequest(); | ||||||
|  | 
 | ||||||
|  |     transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber)); | ||||||
|  | 
 | ||||||
|  |     await payfortViewModel.getPayfortConfigurations(serviceId: ServiceTypeEnum.advancePayment.getIdFromServiceEnum(), projectId: habibWalletVM.selectedHospital!.iD!, integrationId: 2); | ||||||
|  | 
 | ||||||
|  |     applePayInsertRequest.clientRequestID = transID; | ||||||
|  |     applePayInsertRequest.clinicID = 0; | ||||||
|  | 
 | ||||||
|  |     applePayInsertRequest.currency = appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED"; | ||||||
|  |     applePayInsertRequest.customerEmail = "CustID_${habibWalletVM.fileNumber.toString()}@HMG.com"; | ||||||
|  |     applePayInsertRequest.customerID = habibWalletVM.fileNumber.toString(); | ||||||
|  |     applePayInsertRequest.customerName = "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}"; | ||||||
|  | 
 | ||||||
|  |     applePayInsertRequest.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken); | ||||||
|  |     applePayInsertRequest.voipToken = await Utils.getStringFromPrefs(CacheConst.voipToken); | ||||||
|  |     applePayInsertRequest.doctorID = 0; | ||||||
|  |     applePayInsertRequest.projectID = habibWalletVM.selectedHospital!.iD!.toString(); | ||||||
|  |     applePayInsertRequest.serviceID = ServiceTypeEnum.appointmentPayment.getIdFromServiceEnum().toString(); | ||||||
|  |     applePayInsertRequest.channelID = 3; | ||||||
|  |     applePayInsertRequest.patientID = habibWalletVM.fileNumber.toString(); | ||||||
|  |     applePayInsertRequest.patientTypeID = appState.getAuthenticatedUser()!.patientType; | ||||||
|  |     applePayInsertRequest.patientOutSA = appState.getAuthenticatedUser()!.outSa; | ||||||
|  |     applePayInsertRequest.appointmentDate = null; | ||||||
|  |     applePayInsertRequest.appointmentNo = 0; | ||||||
|  |     applePayInsertRequest.orderDescription = "Advance Payment"; | ||||||
|  |     applePayInsertRequest.liveServiceID = "0"; | ||||||
|  |     applePayInsertRequest.latitude = "0.0"; | ||||||
|  |     applePayInsertRequest.longitude = "0.0"; | ||||||
|  |     applePayInsertRequest.amount = habibWalletVM.walletRechargeAmount.toString(); | ||||||
|  |     applePayInsertRequest.isSchedule = "0"; | ||||||
|  |     applePayInsertRequest.language = appState.isArabic() ? 'ar' : 'en'; | ||||||
|  |     applePayInsertRequest.languageID = appState.isArabic() ? 1 : 2; | ||||||
|  |     applePayInsertRequest.userName = int.parse(habibWalletVM.fileNumber); | ||||||
|  |     applePayInsertRequest.responseContinueURL = "http://hmg.com/Documents/success.html"; | ||||||
|  |     applePayInsertRequest.backClickUrl = "http://hmg.com/Documents/success.html"; | ||||||
|  |     applePayInsertRequest.paymentOption = "ApplePay"; | ||||||
|  | 
 | ||||||
|  |     applePayInsertRequest.isMobSDK = true; | ||||||
|  |     applePayInsertRequest.merchantReference = transID; | ||||||
|  |     applePayInsertRequest.merchantIdentifier = payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier; | ||||||
|  |     applePayInsertRequest.commandType = "PURCHASE"; | ||||||
|  |     applePayInsertRequest.signature = payfortViewModel.payfortProjectDetailsRespModel!.signature; | ||||||
|  |     applePayInsertRequest.accessCode = payfortViewModel.payfortProjectDetailsRespModel!.accessCode; | ||||||
|  |     applePayInsertRequest.shaRequestPhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaRequest; | ||||||
|  |     applePayInsertRequest.shaResponsePhrase = payfortViewModel.payfortProjectDetailsRespModel!.shaResponse; | ||||||
|  |     applePayInsertRequest.returnURL = ""; | ||||||
|  | 
 | ||||||
|  |     //TODO: Need to pass dynamic params to the Apple Pay instead of static values | ||||||
|  |     await payfortViewModel.applePayRequestInsert(applePayInsertRequest: applePayInsertRequest).then((value) { | ||||||
|  |       payfortViewModel.paymentWithApplePay( | ||||||
|  |         customerName: "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", | ||||||
|  |         // customerEmail: projectViewModel.authenticatedUserObject.user.emailAddress, | ||||||
|  |         customerEmail: "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com", | ||||||
|  |         orderDescription: "Appointment Payment", | ||||||
|  |         orderAmount: double.parse(habibWalletVM.walletRechargeAmount.toString()), | ||||||
|  |         merchantReference: transID, | ||||||
|  |         merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier, | ||||||
|  |         applePayAccessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode, | ||||||
|  |         applePayShaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest, | ||||||
|  |         currency: appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", | ||||||
|  |         onFailed: (failureResult) async { | ||||||
|  |           log("failureResult: ${failureResult.message.toString()}"); | ||||||
|  |           showCommonBottomSheetWithoutHeight( | ||||||
|  |             context, | ||||||
|  |             child: Utils.getErrorWidget(loadingText: failureResult.message.toString()), | ||||||
|  |             callBackFunc: () {}, | ||||||
|  |             isFullScreen: false, | ||||||
|  |             isCloseButtonVisible: true, | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |         onSucceeded: (successResult) async { | ||||||
|  |           log("successResult: ${successResult.responseMessage.toString()}"); | ||||||
|  |           selectedPaymentMethod = successResult.paymentOption ?? "VISA"; | ||||||
|  |           checkPaymentStatus(); | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void checkPaymentStatus() async { | ||||||
|  |     LoaderBottomSheet.showLoader(); | ||||||
|  |     await payfortViewModel.checkPaymentStatus( | ||||||
|  |       transactionID: transID, | ||||||
|  |       onSuccess: (apiResponse) async { | ||||||
|  |         print(apiResponse.data); | ||||||
|  |         if (payfortViewModel.payfortCheckPaymentStatusResponseModel!.responseMessage!.toLowerCase() == "success") { | ||||||
|  |           await habibWalletVM.HISCreateAdvancePayment( | ||||||
|  |               paymentMethodName: selectedPaymentMethod, | ||||||
|  |               paidAmount: habibWalletVM.walletRechargeAmount, | ||||||
|  |               paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, | ||||||
|  |               patientID: habibWalletVM.fileNumber, | ||||||
|  |               projectID: habibWalletVM.selectedHospital!.iD!, | ||||||
|  |               depositorName: habibWalletVM.depositorName, | ||||||
|  |               onSuccess: (value) async { | ||||||
|  |                 await habibWalletVM.addAdvanceNumberRequest( | ||||||
|  |                     advanceNumber: Utils.isVidaPlusProject(habibWalletVM.selectedHospital!.iD) | ||||||
|  |                         ? value.data['OnlineCheckInAppointments'][0]['AdvanceNumber_VP'].toString() | ||||||
|  |                         : value.data['OnlineCheckInAppointments'][0]['AdvanceNumber'].toString(), | ||||||
|  |                     paymentReference: payfortViewModel.payfortCheckPaymentStatusResponseModel!.fortId!, | ||||||
|  |                     onSuccess: (value) { | ||||||
|  |                       LoaderBottomSheet.hideLoader(); | ||||||
|  |                       showCommonBottomSheetWithoutHeight( | ||||||
|  |                         context, | ||||||
|  |                         child: Utils.getSuccessWidget(loadingText: "Payment Successful!".needTranslation), | ||||||
|  |                         callBackFunc: () { | ||||||
|  |                           Navigator.of(context).pop(); | ||||||
|  |                           Navigator.of(context).pop(); | ||||||
|  |                         }, | ||||||
|  |                         isFullScreen: false, | ||||||
|  |                         isCloseButtonVisible: true, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                     onError: (err) { | ||||||
|  |                       LoaderBottomSheet.hideLoader(); | ||||||
|  |                       showCommonBottomSheetWithoutHeight( | ||||||
|  |                         context, | ||||||
|  |                         child: Utils.getErrorWidget(loadingText: "Payment Failed - ${err}".needTranslation), | ||||||
|  |                         callBackFunc: () {}, | ||||||
|  |                         isFullScreen: false, | ||||||
|  |                         isCloseButtonVisible: true, | ||||||
|  |                       ); | ||||||
|  |                     }); | ||||||
|  |               }, | ||||||
|  |               onError: (err) {}); | ||||||
|  |         } else { | ||||||
|  |           LoaderBottomSheet.hideLoader(); | ||||||
|  |           showCommonBottomSheetWithoutHeight( | ||||||
|  |             context, | ||||||
|  |             child: Utils.getErrorWidget(loadingText: "Payment Failed! Please try again.".needTranslation), | ||||||
|  |             callBackFunc: () {}, | ||||||
|  |             isFullScreen: false, | ||||||
|  |             isCloseButtonVisible: true, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onBrowserLoadStart(String url) { | ||||||
|  |     print("onBrowserLoadStart"); | ||||||
|  |     print(url); | ||||||
|  | 
 | ||||||
|  |     if (selectedPaymentMethod == "tamara") { | ||||||
|  |       if (Platform.isAndroid) { | ||||||
|  |         Uri uri = new Uri.dataFromString(url); | ||||||
|  |         // tamaraPaymentStatus = uri.queryParameters['status']!; | ||||||
|  |         // tamaraOrderID = uri.queryParameters['AuthorizePaymentId']!; | ||||||
|  |       } else { | ||||||
|  |         Uri uri = new Uri.dataFromString(url); | ||||||
|  |         // tamaraPaymentStatus = uri.queryParameters['paymentStatus']!; | ||||||
|  |         // tamaraOrderID = uri.queryParameters['orderId']!; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // if(selectedPaymentMethod != "TAMARA") { | ||||||
|  |     MyInAppBrowser.successURLS.forEach((element) { | ||||||
|  |       if (url.contains(element)) { | ||||||
|  |         browser?.close(); | ||||||
|  |         MyInAppBrowser.isPaymentDone = true; | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     // } | ||||||
|  | 
 | ||||||
|  |     // if(selectedPaymentMethod != "TAMARA") { | ||||||
|  |     MyInAppBrowser.errorURLS.forEach((element) { | ||||||
|  |       if (url.contains(element)) { | ||||||
|  |         browser?.close(); | ||||||
|  |         MyInAppBrowser.isPaymentDone = false; | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     // } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onBrowserExit(bool isPaymentMade) async { | ||||||
|  |     print("onBrowserExit Called!!!!"); | ||||||
|  |     if (selectedPaymentMethod == "TAMARA") { | ||||||
|  |       // checkTamaraPaymentStatus(transID!, appo); | ||||||
|  |       // if (tamaraPaymentStatus != null && tamaraPaymentStatus.toLowerCase() == "approved") { | ||||||
|  |       //   updateTamaraRequestStatus("success", "14", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo); | ||||||
|  |       // } else { | ||||||
|  |       //   updateTamaraRequestStatus("Failed", "00", Utils.getAppointmentTransID(appo.projectID, appo.clinicID, appo.appointmentNo), tamaraOrderID, num.parse(selectedInstallments), appo); | ||||||
|  |       // } | ||||||
|  |     } else { | ||||||
|  |       checkPaymentStatus(); | ||||||
|  |       // checkPaymentStatus(appo); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   openPaymentURL(String paymentMethod) { | ||||||
|  |     browser = MyInAppBrowser(onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart, context: context); | ||||||
|  |     transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber)); | ||||||
|  | 
 | ||||||
|  |     browser?.openPaymentBrowser( | ||||||
|  |         habibWalletVM.walletRechargeAmount, | ||||||
|  |         "Advance Payment", | ||||||
|  |         transID, | ||||||
|  |         habibWalletVM.selectedHospital!.iD!.toString(), | ||||||
|  |         "CustID_${habibWalletVM.fileNumber.toString()}@HMG.com", | ||||||
|  |         selectedPaymentMethod, | ||||||
|  |         appState.getAuthenticatedUser()!.patientType.toString(), | ||||||
|  |         habibWalletVM.depositorName, | ||||||
|  |         habibWalletVM.fileNumber.toString(), | ||||||
|  |         appState.getAuthenticatedUser()!, | ||||||
|  |         browser!, | ||||||
|  |         false, | ||||||
|  |         "3", | ||||||
|  |         "0", | ||||||
|  |         context, | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "3"); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,106 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/app_assets.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/app_export.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/app_state.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/dependencies.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/utils/utils.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||||
|  | 
 | ||||||
|  | class HospitalListItemAdvancePayment extends StatelessWidget { | ||||||
|  |   final HospitalsModel hospitalModel; | ||||||
|  |   final bool isLocationEnabled; | ||||||
|  | 
 | ||||||
|  |   late AppState appState; | ||||||
|  | 
 | ||||||
|  |   HospitalListItemAdvancePayment({super.key, required this.hospitalModel, required this.isLocationEnabled}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     appState = getIt.get<AppState>(); | ||||||
|  |     return DecoratedBox( | ||||||
|  |       decoration: RoundedRectangleBorder().toSmoothCornerDecoration( | ||||||
|  |         color: AppColors.whiteColor, | ||||||
|  |         borderRadius: 20.h, | ||||||
|  |         hasShadow: false, | ||||||
|  |       ), | ||||||
|  |       child: Row( | ||||||
|  |         mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |         children: [ | ||||||
|  |           Expanded( | ||||||
|  |             child: Column( | ||||||
|  |               crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |               spacing: 8.h, | ||||||
|  |               children: [hospitalName], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           Transform.flip( | ||||||
|  |             flipX: appState.isArabic() ? true : false, | ||||||
|  |             child: Utils.buildSvgWithAssets( | ||||||
|  |               icon: AppAssets.forward_arrow_icon, | ||||||
|  |               iconColor: AppColors.blackColor, | ||||||
|  |               width: 18, | ||||||
|  |               height: 13, | ||||||
|  |               fit: BoxFit.contain, | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ).paddingSymmetrical(16.h, 16.h), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget get hospitalName => Row( | ||||||
|  |         children: [ | ||||||
|  |           Utils.buildSvgWithAssets( | ||||||
|  |             icon: (hospitalModel.isHMC == true) ? AppAssets.hmc : AppAssets.hmg, | ||||||
|  |           ).paddingOnly(right: 10), | ||||||
|  |           Expanded( | ||||||
|  |             child: Text( | ||||||
|  |               hospitalModel.name ?? "", | ||||||
|  |               style: TextStyle( | ||||||
|  |                 fontWeight: FontWeight.w600, | ||||||
|  |                 fontSize: 16, | ||||||
|  |                 color: AppColors.blackColor, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  | // Widget get distanceInfo => Row( | ||||||
|  | //   children: [ | ||||||
|  | //     Visibility( | ||||||
|  | //       visible: (hospitalModel.distanceInKMs != "0"), | ||||||
|  | //       child: AppCustomChipWidget( | ||||||
|  | //         labelText: "${hospitalData?.distanceInKMs ?? ""} km".needTranslation, | ||||||
|  | //         deleteIcon: AppAssets.location_red, | ||||||
|  | //         deleteIconSize: Size(9, 12), | ||||||
|  | //         backgroundColor: AppColors.secondaryLightRedColor, | ||||||
|  | //         textColor: AppColors.errorColor, | ||||||
|  | //       ), | ||||||
|  | //     ), | ||||||
|  | //     Visibility( | ||||||
|  | //         visible: (hospitalData?.distanceInKMs == "0"), | ||||||
|  | //         child: Row( | ||||||
|  | //           children: [ | ||||||
|  | //             AppCustomChipWidget( | ||||||
|  | //               labelText: "Distance not available".needTranslation, | ||||||
|  | //               textColor: AppColors.blackColor, | ||||||
|  | //             ), | ||||||
|  | //             SizedBox( | ||||||
|  | //               width: 8.h, | ||||||
|  | //             ) | ||||||
|  | //           ], | ||||||
|  | //         )), | ||||||
|  | //     Visibility( | ||||||
|  | //         visible: !isLocationEnabled, | ||||||
|  | //         child: AppCustomChipWidget( | ||||||
|  | //           labelText: "Location turned off".needTranslation, | ||||||
|  | //           deleteIcon: AppAssets.location_unavailable, | ||||||
|  | //           deleteIconSize: Size(9, 12), | ||||||
|  | //           textColor: AppColors.blackColor, | ||||||
|  | //         )), | ||||||
|  | //   ], | ||||||
|  | // ); | ||||||
|  | } | ||||||
| @ -0,0 +1,96 @@ | |||||||
|  | import 'package:easy_localization/easy_localization.dart' show tr, StringTranslateExtension; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/enums.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_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/facility_selection.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/hospital_list_items.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/appointments/widgets/hospital_bottom_sheet/type_selection_widget.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/habib_wallet/widgets/hospital_list_item.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/lab/collapsing_list_view.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/theme/colors.dart' show AppColors; | ||||||
|  | import 'package:hmg_patient_app_new/widgets/input_widget.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | 
 | ||||||
|  | class SelectHospitalBottomSheet extends StatelessWidget { | ||||||
|  |   late HabibWalletViewModel habibWalletVM; | ||||||
|  |   final TextEditingController searchText = TextEditingController(); | ||||||
|  | 
 | ||||||
|  |   SelectHospitalBottomSheet({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     habibWalletVM = Provider.of<HabibWalletViewModel>(context, listen: false); | ||||||
|  |     return Column( | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |       children: [ | ||||||
|  |         // Text( | ||||||
|  |         //   LocaleKeys.selectHospital.tr(), | ||||||
|  |         //   style: TextStyle( | ||||||
|  |         //     fontSize: 21, | ||||||
|  |         //     fontWeight: FontWeight.w600, | ||||||
|  |         //     color: AppColors.blackColor, | ||||||
|  |         //   ), | ||||||
|  |         // ), | ||||||
|  |         Text( | ||||||
|  |           "Please select the hospital you want to make an advance payment for.".needTranslation, | ||||||
|  |           style: TextStyle( | ||||||
|  |             fontSize: 16, | ||||||
|  |             fontWeight: FontWeight.w500, | ||||||
|  |             color: AppColors.greyTextColor, | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         SizedBox(height: 16.h), | ||||||
|  |         // TextInputWidget( | ||||||
|  |         //   labelText: LocaleKeys.search.tr(), | ||||||
|  |         //   hintText: "Search Hospital".tr(), | ||||||
|  |         //   controller: searchText, | ||||||
|  |         //   onChange: (value) { | ||||||
|  |         //     // appointmentsViewModel.filterHospitalListByString(value, regionalViewModel.selectedRegionId , regionalViewModel.selectedFacilityType == | ||||||
|  |         //     //     FacilitySelection.HMG.name); | ||||||
|  |         //   }, | ||||||
|  |         //   isEnable: true, | ||||||
|  |         //   prefix: null, | ||||||
|  |         //   autoFocus: false, | ||||||
|  |         //   isBorderAllowed: false, | ||||||
|  |         //   keyboardType: TextInputType.text, | ||||||
|  |         //   isAllowLeadingIcon: true, | ||||||
|  |         //   selectionType: SelectionTypeEnum.search, | ||||||
|  |         //   padding: EdgeInsets.symmetric( | ||||||
|  |         //     vertical: ResponsiveExtension(10).h, | ||||||
|  |         //     horizontal: ResponsiveExtension(15).h, | ||||||
|  |         //   ), | ||||||
|  |         // ), | ||||||
|  |         // SizedBox(height: 24.h), | ||||||
|  |         // TypeSelectionWidget( | ||||||
|  |         //   hmcCount: "0", | ||||||
|  |         //   hmgCount: "0", | ||||||
|  |         // ), | ||||||
|  |         // SizedBox(height: 21.h), | ||||||
|  |         SizedBox( | ||||||
|  |           height: MediaQuery.sizeOf(context).height * .4, | ||||||
|  |           child: ListView.separated( | ||||||
|  |               itemBuilder: (_, index) { | ||||||
|  |                 return HospitalListItemAdvancePayment( | ||||||
|  |                   hospitalModel: habibWalletVM.advancePaymentHospitals[index], | ||||||
|  |                   isLocationEnabled: false, | ||||||
|  |                 ).onPress(() { | ||||||
|  |                   habibWalletVM.setSelectedHospital(habibWalletVM.advancePaymentHospitals[index]); | ||||||
|  |                   Navigator.of(context).pop(); | ||||||
|  |                 }); | ||||||
|  |               }, | ||||||
|  |               separatorBuilder: (_, __) => SizedBox( | ||||||
|  |                     height: 16.h, | ||||||
|  |                   ), | ||||||
|  |               itemCount: habibWalletVM.advancePaymentHospitals.length), | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,287 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:fl_chart/fl_chart.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/common_models/data_points.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||||
|  | /// | ||||||
|  | /// CustomGraph(dataPoints: sampleData, scrollDirection: Axis.horizontal,height: 200,maxY: 100, maxX:2.5, | ||||||
|  | ///               leftLabelFormatter: (value){ | ||||||
|  | ///                 Widget buildLabel(String label) { | ||||||
|  | ///                   return Padding( | ||||||
|  | ///                     padding: const EdgeInsets.only(right: 8), | ||||||
|  | ///                     child: Text( | ||||||
|  | ///                       label, | ||||||
|  | ///                       style: TextStyle( | ||||||
|  | ///                           fontSize: 8.fSize, color: AppColors.textColor, | ||||||
|  | ///                       fontFamily: | ||||||
|  | ///                       FontUtils.getFontFamilyForLanguage(false) | ||||||
|  | ///                       ), | ||||||
|  | ///                       textAlign: TextAlign.right, | ||||||
|  | ///                     ), | ||||||
|  | ///                   ); | ||||||
|  | ///                 } | ||||||
|  | ///                 switch (value.toInt()) { | ||||||
|  | /// | ||||||
|  | ///                   case 20: | ||||||
|  | ///                     return buildLabel("Critical Low"); | ||||||
|  | ///                   case 40: | ||||||
|  | ///                     return buildLabel("Low"); | ||||||
|  | ///                   case 60: | ||||||
|  | ///                     return buildLabel("Normal"); | ||||||
|  | ///                   case 80: | ||||||
|  | ///                     return buildLabel("High"); | ||||||
|  | ///                   case 100: | ||||||
|  | ///                     return buildLabel("Critical High"); | ||||||
|  | ///                 } | ||||||
|  | ///                 return const SizedBox.shrink(); | ||||||
|  | ///               }, | ||||||
|  | /// | ||||||
|  | ///             ), | ||||||
|  | class CustomGraph extends StatelessWidget { | ||||||
|  |   final List<DataPoint> dataPoints; | ||||||
|  |   final double? width; | ||||||
|  |   final double height; | ||||||
|  |   final double? maxY; | ||||||
|  |   final double? maxX; | ||||||
|  |   final Color spotColor; | ||||||
|  |   final Color graphColor; | ||||||
|  |   final Color graphShadowColor; | ||||||
|  |   final Color graphGridColor; | ||||||
|  |   final Color bottomLabelColor; | ||||||
|  |   final double? bottomLabelSize; | ||||||
|  |   final FontWeight? bottomLabelFontWeight; | ||||||
|  | 
 | ||||||
|  |   ///creates the left label and provide it to the chart as it will be used  by other part of the application so the label will be different for every chart | ||||||
|  |   final Widget Function(double value) leftLabelFormatter; | ||||||
|  | 
 | ||||||
|  |   final Axis scrollDirection; | ||||||
|  |   final bool showBottomTitleDates; | ||||||
|  |   final bool isFullScreeGraph; | ||||||
|  | 
 | ||||||
|  |   const CustomGraph({ | ||||||
|  |     super.key, | ||||||
|  |     required this.dataPoints, | ||||||
|  |     required this.leftLabelFormatter, | ||||||
|  |     this.width, | ||||||
|  |     required this.scrollDirection, | ||||||
|  |     required this.height, | ||||||
|  |     this.maxY, | ||||||
|  |     this.maxX, | ||||||
|  |     this.showBottomTitleDates = true, | ||||||
|  |     this.isFullScreeGraph = false, | ||||||
|  |     this.spotColor = AppColors.bgGreenColor, | ||||||
|  |     this.graphColor = AppColors.bgGreenColor, | ||||||
|  |     this.graphShadowColor = AppColors.graphGridColor, | ||||||
|  |     this.graphGridColor = AppColors.graphGridColor, | ||||||
|  |     this.bottomLabelColor = AppColors.textColor, | ||||||
|  |     this.bottomLabelFontWeight = FontWeight.w500, | ||||||
|  |     this.bottomLabelSize, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     // var maxY = 0.0; | ||||||
|  |     double interval = 20; | ||||||
|  |     if ((maxY ?? 0) > 10 && (maxY ?? 0) <= 20) { | ||||||
|  |       interval = 2; | ||||||
|  |     } else if ((maxY ?? 0) > 5 && (maxY ?? 0) <= 10) { | ||||||
|  |       interval = 1; | ||||||
|  |     } else if ((maxY ?? 0) >= 0 && (maxY ?? 0) <= 5) { | ||||||
|  |       interval = .4; | ||||||
|  |     } | ||||||
|  |     return Material( | ||||||
|  |         color: Colors.white, | ||||||
|  |         child: SizedBox( | ||||||
|  |           width: width, | ||||||
|  |           height: height, | ||||||
|  |           child: Padding( | ||||||
|  |             padding: const EdgeInsets.only(top: 8.0, bottom: 8), | ||||||
|  |             child: LineChart( | ||||||
|  |               LineChartData( | ||||||
|  |                 minY: 0, | ||||||
|  |                 maxY: | ||||||
|  |                     ((maxY?.ceilToDouble() ?? 0.0) + interval).floorToDouble(), | ||||||
|  |                 // minX: dataPoints.first.labelValue - 1, | ||||||
|  |                 maxX: maxX, | ||||||
|  |                 minX: -0.2, | ||||||
|  |                 lineTouchData: LineTouchData( | ||||||
|  |                   getTouchLineEnd: (_, __) => 0, | ||||||
|  |                   getTouchedSpotIndicator: (barData, indicators) { | ||||||
|  |                     // Only show custom marker for touched spot | ||||||
|  |                     return indicators.map((int index) { | ||||||
|  |                       return TouchedSpotIndicatorData( | ||||||
|  |                         FlLine(color: Colors.transparent), | ||||||
|  |                         FlDotData( | ||||||
|  |                           show: true, | ||||||
|  |                           getDotPainter: (spot, percent, barData, idx) { | ||||||
|  |                             return FlDotCirclePainter( | ||||||
|  |                               radius: 8, | ||||||
|  |                               color: spotColor, | ||||||
|  |                               strokeWidth: 2, | ||||||
|  |                               strokeColor: Colors.white, | ||||||
|  |                             ); | ||||||
|  |                           }, | ||||||
|  |                         ), | ||||||
|  |                       ); | ||||||
|  |                     }).toList(); | ||||||
|  |                   }, | ||||||
|  |                   enabled: true, | ||||||
|  |                   touchTooltipData: LineTouchTooltipData( | ||||||
|  |                     getTooltipColor: (_) => Colors.white, | ||||||
|  |                     getTooltipItems: (touchedSpots) { | ||||||
|  |                       if (touchedSpots.isEmpty) return []; | ||||||
|  |                       // Only show tooltip for the first touched spot, hide others | ||||||
|  |                       return touchedSpots.map((spot) { | ||||||
|  |                         if (spot == touchedSpots.first) { | ||||||
|  |                           final dataPoint = dataPoints[spot.x.toInt()]; | ||||||
|  | 
 | ||||||
|  |                           return LineTooltipItem( | ||||||
|  |                             // '${dataPoint.label} ${spot.y.toStringAsFixed(2)}', | ||||||
|  |                             '${dataPoint.value} ', | ||||||
|  |                             TextStyle( | ||||||
|  |                                 color: Colors.black, | ||||||
|  |                                 fontSize: 12.fSize, | ||||||
|  |                                 fontWeight: FontWeight.w500), | ||||||
|  |                           ); | ||||||
|  |                         } | ||||||
|  |                         return null; // hides the rest | ||||||
|  |                       }).toList(); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |                 titlesData: FlTitlesData( | ||||||
|  |                   leftTitles: AxisTitles( | ||||||
|  |                     sideTitles: SideTitles( | ||||||
|  |                       showTitles: true, | ||||||
|  |                       reservedSize: 77, | ||||||
|  |                       interval: .1, // Let fl_chart handle it | ||||||
|  |                       getTitlesWidget: (value, _) { | ||||||
|  |                         return leftLabelFormatter(value); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   bottomTitles: AxisTitles( | ||||||
|  |                     axisNameSize: 60, | ||||||
|  |                     sideTitles: SideTitles( | ||||||
|  |                       showTitles: showBottomTitleDates, | ||||||
|  |                       reservedSize: 50, | ||||||
|  |                       getTitlesWidget: (value, _) { | ||||||
|  |                         if ((value.toDouble() >= 0) && | ||||||
|  |                             (value.toDouble() < (maxX ?? dataPoints.length))) { | ||||||
|  |                           var label = dataPoints[value.toInt()].label; | ||||||
|  | 
 | ||||||
|  |                           return buildBottomLabel(label); | ||||||
|  |                         } | ||||||
|  |                         return const SizedBox.shrink(); | ||||||
|  |                       }, | ||||||
|  |                       interval: 1, // ensures 1:1 mapping with spots | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                   topTitles: AxisTitles(), | ||||||
|  |                   rightTitles: AxisTitles(), | ||||||
|  |                 ), | ||||||
|  |                 borderData: FlBorderData( | ||||||
|  |                   show: true, | ||||||
|  |                   border: const Border( | ||||||
|  |                     bottom: BorderSide.none, | ||||||
|  |                     left: BorderSide(color: Colors.grey, width: .5), | ||||||
|  |                     right: BorderSide.none, | ||||||
|  |                     top: BorderSide.none, | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |                 lineBarsData: _buildColoredLineSegments(dataPoints), | ||||||
|  |                 gridData: FlGridData( | ||||||
|  |                   show: true, | ||||||
|  |                   drawVerticalLine: false, | ||||||
|  |                   horizontalInterval: 20, | ||||||
|  |                   checkToShowHorizontalLine: (value) => | ||||||
|  |                       value >= 0 && value <= 100, | ||||||
|  |                   getDrawingHorizontalLine: (value) { | ||||||
|  |                     return FlLine( | ||||||
|  |                       color: AppColors.graphGridColor, | ||||||
|  |                       strokeWidth: 1, | ||||||
|  |                       dashArray: [5, 5], | ||||||
|  |                     ); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         )); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   List<LineChartBarData> _buildColoredLineSegments(List<DataPoint> dataPoints) { | ||||||
|  |     final List<FlSpot> allSpots = dataPoints.asMap().entries.map((entry) { | ||||||
|  |       return FlSpot(entry.key.toDouble(), entry.value.value); | ||||||
|  |     }).toList(); | ||||||
|  | 
 | ||||||
|  |     var data = [ | ||||||
|  |       LineChartBarData( | ||||||
|  |         spots: allSpots, | ||||||
|  |         isCurved: true, | ||||||
|  |         isStrokeCapRound: true, | ||||||
|  |         isStrokeJoinRound: true, | ||||||
|  |         barWidth: 4, | ||||||
|  |         gradient: LinearGradient( | ||||||
|  |           colors: [graphColor, graphColor], | ||||||
|  |           begin: Alignment.centerLeft, | ||||||
|  |           end: Alignment.centerRight, | ||||||
|  |         ), | ||||||
|  |         dotData: FlDotData( | ||||||
|  |           show: false, | ||||||
|  |         ), | ||||||
|  |         belowBarData: BarAreaData( | ||||||
|  |           show: true, | ||||||
|  |           gradient: LinearGradient( | ||||||
|  |             colors: [ | ||||||
|  |               graphShadowColor, | ||||||
|  |               Colors.transparent, | ||||||
|  |             ], | ||||||
|  |             begin: Alignment.topCenter, | ||||||
|  |             end: Alignment.bottomCenter, | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ) | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     return data; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Widget buildLabel(String label) { | ||||||
|  |   //   return Padding( | ||||||
|  |   //     padding: const EdgeInsets.only(right: 8), | ||||||
|  |   //     child: Text( | ||||||
|  |   //       label, | ||||||
|  |   //       style: TextStyle( | ||||||
|  |   //           fontSize: leftLabelSize ?? 8.fSize, color: leftLabelColor), | ||||||
|  |   //       textAlign: TextAlign.right, | ||||||
|  |   //     ), | ||||||
|  |   //   ); | ||||||
|  |   // } | ||||||
|  | 
 | ||||||
|  |   Widget buildBottomLabel(String label) { | ||||||
|  |     return Padding( | ||||||
|  |       padding: const EdgeInsets.all(8.0), | ||||||
|  |       child: Text( | ||||||
|  |         label, | ||||||
|  |         style: TextStyle( | ||||||
|  |             fontSize: bottomLabelSize ?? 8.fSize, color: bottomLabelColor), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | final List<DataPoint> sampleData = [ | ||||||
|  |   DataPoint( | ||||||
|  |     value: 20, | ||||||
|  |     label: 'Jan 2024', | ||||||
|  |   ), | ||||||
|  |   DataPoint( | ||||||
|  |     value: 36, | ||||||
|  |     label: 'Feb 2024', | ||||||
|  |   ), | ||||||
|  |   DataPoint( | ||||||
|  |     value: 80, | ||||||
|  |     label: 'This result', | ||||||
|  |   ), | ||||||
|  | ]; | ||||||
					Loading…
					
					
				
		Reference in New Issue