diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index b2ea0470..e4e65227 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -86,3 +86,6 @@ @com.peng.bus.PISubscribe ; } -keep class com.peng.pennavmap.models.bus.BackButtonEventBusData { *; } + +-keep interface com.payfort.fortpaymentsdk.** {*;} +-keep class com.payfort.fortpaymentsdk.** {*;} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ba1f830e..70a68707 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -163,7 +163,7 @@ android:enabled="true" android:exported="true" android:hardwareAccelerated="true" - android:launchMode="singleInstance" + android:launchMode="singleTop" android:showOnLockScreen="true" android:theme="@style/LaunchTheme" android:windowSoftInputMode="adjustResize" diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 9f3bb907..fbab6486 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -1,10 +1,11 @@ import 'package:amazon_payfort/amazon_payfort.dart'; +import 'package:flutter_amazonpaymentservices/environment_type.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; 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 @@ -23,6 +24,7 @@ class ApiConsts { static var payFortEnvironment = FortEnvironment.production; static var applePayMerchantId = "merchant.com.hmgwebservices"; + static var payFortEnvironmentType = EnvironmentType.production; static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE // static String SERVICE_URL = 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT @@ -47,6 +49,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.prod: baseUrl = "https://hmgwebservices.com/"; payFortEnvironment = FortEnvironment.production; + payFortEnvironmentType = EnvironmentType.production; applePayMerchantId = "merchant.com.hmgwebservices"; SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; @@ -62,6 +65,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.dev: baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; + payFortEnvironmentType = EnvironmentType.sandbox; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -78,6 +82,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.uat: baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; + payFortEnvironmentType = EnvironmentType.sandbox; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -94,6 +99,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.preProd: baseUrl = "https://webservices.hmg.com/"; payFortEnvironment = FortEnvironment.production; + payFortEnvironmentType = EnvironmentType.production; applePayMerchantId = "merchant.com.hmgwebservices"; SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -110,6 +116,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.qa: baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; + payFortEnvironmentType = EnvironmentType.sandbox; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -126,6 +133,7 @@ class ApiConsts { case AppEnvironmentTypeEnum.staging: baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; + payFortEnvironmentType = EnvironmentType.sandbox; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index aae2d03b..3369ef49 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -48,9 +48,16 @@ class AppState { bool isPaytabsEnabled = false; + bool isPayfortHostedPageEnabled = true; + void setIsPaytabsEnabled(bool value) { - isPaytabsEnabled = value; - // isPaytabsEnabled = false; + // isPaytabsEnabled = value; + isPaytabsEnabled = false; + } + + void setIsPayfortHostedPageEnabled(bool value) { + isPayfortHostedPageEnabled = value; + // isPayfortHostedPageEnabled = false; } int? _superUserID; diff --git a/lib/features/payfort/payfort_view_model.dart b/lib/features/payfort/payfort_view_model.dart index 4b0e2c26..73692058 100644 --- a/lib/features/payfort/payfort_view_model.dart +++ b/lib/features/payfort/payfort_view_model.dart @@ -1,8 +1,13 @@ +import 'dart:convert'; import 'dart:developer'; import 'package:amazon_payfort/amazon_payfort.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_amazonpaymentservices/flutter_amazonpaymentservices.dart'; import 'package:hmg_patient_app_new/core/api_consts.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/core/dependencies.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/get_tamara_installments_details_response_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/models/payfort_check_payment_status_response_model.dart'; @@ -12,6 +17,7 @@ import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:network_info_plus/network_info_plus.dart'; +import 'package:crypto/crypto.dart'; class PayfortViewModel extends ChangeNotifier { PayfortRepo payfortRepo; @@ -27,6 +33,8 @@ class PayfortViewModel extends ChangeNotifier { GetTamaraInstallmentsDetailsResponseModel? getTamaraInstallmentsDetailsResponseModel; bool isTamaraDetailsLoading = false; + SdkTokenResponse? sdkTokenResponse; + PayfortViewModel({required this.payfortRepo, required this.errorHandlerService}); setIsApplePayConfigurationLoading(bool value) { @@ -142,6 +150,99 @@ class PayfortViewModel extends ChangeNotifier { ); } + String buildManualPayfortSignature({ + required String accessCode, + required String deviceId, + required String merchantIdentifier, + required String amount, + required String currency, + required String merchantReference, + required String shaRequestPhrase, // Your secret Sandbox phrase + }) { + // 1. Map all properties in strict ALPHABETICAL order by native key names + // Notice that "amount" and "currency" must come first alphabetically + final parameters = { + "access_code": accessCode, + "device_id": deviceId, + "language": "en", + "merchant_identifier": merchantIdentifier, + "service_command": "SDK_TOKEN", + }; + + // 2. Concatenate into a single continuous string wrapped in your SHA Phrase + StringBuffer buffer = StringBuffer(); + buffer.write(shaRequestPhrase); + + parameters.forEach((key, value) { + buffer.write('$key=$value'); + }); + buffer.write(shaRequestPhrase); + + // 3. Convert string to SHA-256 hex signature + var bytes = utf8.encode(buffer.toString()); + return sha256.convert(bytes).toString(); + } + + Future generateSdkResponseForNormalPayment({ + String? accessCode, + String? merchantIdentifier, + String? shaType, + String? shaRequestPhrase, + String? merchantReference, + String? amount, + }) async { + SdkTokenResponse? sdkTokenResponse; + try { + // String? deviceId = await _payfort.getDeviceId(); + String? deviceId = await FlutterAmazonpaymentservices.getUDID; + + /// Step 2: Generate the Signature + SdkTokenRequest tokenRequest = SdkTokenRequest( + accessCode: accessCode!, + deviceId: deviceId ?? '', + merchantIdentifier: merchantIdentifier!, + ); + + // String? signature = await _payfort.generateSignature( + // shaType: shaType!, + // concatenatedString: tokenRequest.toConcatenatedString(shaRequestPhrase!), + // ); + + String? signature = buildManualPayfortSignature( + accessCode: accessCode, + deviceId: deviceId!, + merchantIdentifier: merchantIdentifier, + amount: "10000", + currency: "SAR", + merchantReference: merchantReference!, + shaRequestPhrase: shaRequestPhrase!, + ); + + tokenRequest = tokenRequest.copyWith(signature: signature); + + this.sdkTokenResponse = SdkTokenResponse(); + + /// Step 3: Generate the SDK Token + final result = await payfortRepo.generateSdkSignatureFromAPI(tokenRequest: tokenRequest); + result.fold( + (failure) async => await errorHandlerService.handleError(failure: failure), + (apiResponse) { + if (apiResponse.messageStatus == 2) { + // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {}); + } else if (apiResponse.messageStatus == 1) { + // payfortProjectDetailsRespModel = apiResponse.data!; + sdkTokenResponse = apiResponse.data; + this.sdkTokenResponse = sdkTokenResponse; + notifyListeners(); + } + }, + ); + } catch (e) { + log("Error here: ${e.toString()}"); + } + return sdkTokenResponse; + } + Future _generateSdkResponse({ String? applePayAccessCode, String? merchantIdentifier, @@ -187,6 +288,73 @@ class PayfortViewModel extends ChangeNotifier { return sdkTokenResponse; } + Future initiatePaymentWithCard( // var request, { + { + SucceededCallback? onSucceeded, + FailedCallback? onFailed, + String countryIsoCode = "SA", + String transactionID = "", + String amount = "0", + String fileNumber = "0", + }) async { + dynamic paymentResult; + + try { + await generateSdkResponseForNormalPayment( + accessCode: payfortProjectDetailsRespModel!.accessCode, + merchantIdentifier: payfortProjectDetailsRespModel!.merchantIdentifier, + shaRequestPhrase: payfortProjectDetailsRespModel!.shaRequest, + shaType: "SHA-256", + merchantReference: transactionID, + amount: amount); + + // Force a 100ms microtask buffer to isolate the UI rendering channel + await Future.delayed(const Duration(milliseconds: 350)); + + var request = { + "command": "PURCHASE", + "merchant_reference": transactionID, // Completely alphanumeric testing reference + "amount": (num.parse(amount) * 100).toInt(), + "currency": getIt.get().getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", + "language": "en", + "customer_email": "CustID_$fileNumber@HMG.com", + "sdk_token": sdkTokenResponse!.sdkToken, + "customer_name": "${getIt.get().getAuthenticatedUser()!.firstName} ${getIt.get().getAuthenticatedUser()!.lastName}", + }; + + LoaderBottomSheet.hideLoader(); + + paymentResult = await FlutterAmazonpaymentservices.normalPay(request, ApiConsts.payFortEnvironmentType, isShowResponsePage: false); + final paymentMap = Map.from(paymentResult); + String responseCode = paymentMap['response_code'] ?? ""; + print("Payment Success Data: ${paymentMap.toString()}"); + + if (responseCode.startsWith("14") || responseCode == "20064") { + if (onSucceeded != null) { + onSucceeded(PayFortResult.fromMap(paymentMap)); + } + } else if (responseCode == "13000") { + // Push user to 3D Secure Web View + } else { + // Treat as a payment rejection/technical failure + if (onFailed != null) { + onFailed(PayFortFailureResult.fromMap(paymentMap)); + } + } + } on PlatformException catch (e) { + // If the error is the MethodChannel duplicate reply bug, handle it safely + if (e.message != null && e.message!.contains("Reply already submitted")) { + print("Swallowed native channel race-condition crash safely."); + return; + } + + // Process real payment rejection errors here + print("Actual Payment Failure: ${e.details.toString()}"); + } catch (error) { + print("Generic Error: $error"); + } + } + Future paymentWithApplePay({ SucceededCallback? onSucceeded, FailedCallback? onFailed, diff --git a/lib/presentation/appointments/appointment_payment_page.dart b/lib/presentation/appointments/appointment_payment_page.dart index ff0b8012..bd80bd59 100644 --- a/lib/presentation/appointments/appointment_payment_page.dart +++ b/lib/presentation/appointments/appointment_payment_page.dart @@ -337,6 +337,7 @@ class _AppointmentPaymentPageState extends State { ); }); } else { + openPaymentURL("visa"); } }), diff --git a/lib/presentation/authentication/login.dart b/lib/presentation/authentication/login.dart index 371ad6ab..c38e9ad9 100644 --- a/lib/presentation/authentication/login.dart +++ b/lib/presentation/authentication/login.dart @@ -99,7 +99,7 @@ class LoginScreenState extends State { hintText: "xxxxxxxxx", controller: authVm.nationalIdController, focusNode: _nationalIdFocusNode, - keyboardType: TextInputType.text, + keyboardType: TextInputType.number, isEnable: true, prefix: null, autoFocus: true, diff --git a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart index dd3c5ff8..18806515 100644 --- a/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart +++ b/lib/presentation/habib_wallet/wallet_payment_confirm_page.dart @@ -2,8 +2,12 @@ import 'dart:async'; import 'dart:developer'; import 'dart:io'; +import 'package:amazon_payfort/amazon_payfort.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_amazonpaymentservices/flutter_amazonpaymentservices.dart'; +import 'package:hmg_patient_app_new/core/api_consts.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'; @@ -26,6 +30,7 @@ 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:network_info_plus/network_info_plus.dart'; import 'package:provider/provider.dart'; class WalletPaymentConfirmPage extends StatefulWidget { @@ -206,7 +211,7 @@ class _WalletPaymentConfirmPageState extends State { ), ], ).paddingSymmetrical(16.h, 16.h), - ).paddingSymmetrical(24.h, 0.h).onPress(() { + ).paddingSymmetrical(24.h, 0.h).onPress(() async { selectedPaymentMethod = "VISA"; if (appState.isPaytabsEnabled) { paytabsViewModel.setPaymentConfiguration("Advance Payment", habibWalletVM.walletRechargeAmount); @@ -267,7 +272,46 @@ class _WalletPaymentConfirmPageState extends State { ); }); } else { - openPaymentURL("visa"); + if (appState.isPayfortHostedPageEnabled) { + LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingPaymentInformation.tr(context: context)); + + transID = Utils.getAdvancePaymentTransID(habibWalletVM.selectedHospital!.iD!, int.parse(habibWalletVM.fileNumber)); + await payfortViewModel.getPayfortConfigurations( + serviceId: ServiceTypeEnum.advancePayment.getIdFromServiceEnum(), projectId: habibWalletVM.selectedHospital!.iD!, integrationId: 1); + + // await payfortViewModel.generateSdkResponseForNormalPayment( + // accessCode: payfortViewModel.payfortProjectDetailsRespModel!.accessCode, + // merchantIdentifier: payfortViewModel.payfortProjectDetailsRespModel!.merchantIdentifier, + // shaRequestPhrase: payfortViewModel.payfortProjectDetailsRespModel!.shaRequest, + // shaType: "SHA-256", + // merchantReference: transID, + // amount: habibWalletVM.walletRechargeAmount.toString()); + + // var requestParam = { + // "command": "PURCHASE", + // "merchant_reference": transID, // Completely alphanumeric testing reference + // "amount": (habibWalletVM.walletRechargeAmount * 100).toInt(), + // "currency": appState.getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED", + // "language": "en", + // "customer_email": "CustID_${habibWalletVM.fileNumber.toString()}@HMG.com", + // "sdk_token": payfortViewModel.sdkTokenResponse!.sdkToken, + // "customer_name": "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}", + // }; + + payfortViewModel.initiatePaymentWithCard( + transactionID: transID, + fileNumber: habibWalletVM.fileNumber.toString(), + amount: habibWalletVM.walletRechargeAmount.toString(), + onSucceeded: (paymentResult) { + print("Payment Success Data: ${paymentResult.toString()}"); + }, + onFailed: (err) { + print("Payment Failed Data: ${err.toString()}"); + }, + ); + } else { + openPaymentURL("visa"); + } } }), ], @@ -626,4 +670,28 @@ class _WalletPaymentConfirmPageState extends State { "", "3"); } + + Future runSafePayment(Map requestParam, {String sdkToken = ""}) async { + dynamic result; + + try { + // Force a 100ms microtask buffer to isolate the UI rendering channel + await Future.delayed(const Duration(milliseconds: 350)); + + result = await FlutterAmazonpaymentservices.normalPay(requestParam, ApiConsts.payFortEnvironmentType, isShowResponsePage: true); + + print("Payment Success Data: ${result.toString()}"); + } on PlatformException catch (e) { + // If the error is the MethodChannel duplicate reply bug, handle it safely + if (e.message != null && e.message!.contains("Reply already submitted")) { + print("Swallowed native channel race-condition crash safely."); + return; + } + + // Process real payment rejection errors here + print("Actual Payment Failure: ${e.details.toString()}"); + } catch (error) { + print("Generic Error: $error"); + } + } } diff --git a/lib/presentation/home/app_update_page.dart b/lib/presentation/home/app_update_page.dart index 8750fcb7..37dab487 100644 --- a/lib/presentation/home/app_update_page.dart +++ b/lib/presentation/home/app_update_page.dart @@ -18,7 +18,7 @@ import 'package:lottie/lottie.dart'; class AppUpdatePage extends StatelessWidget { AppUpdatePage({super.key, required this.appUpdateMessage}); - String appUpdateMessage; + final String appUpdateMessage; @override Widget build(BuildContext context) { @@ -72,21 +72,7 @@ class AppUpdatePage extends StatelessWidget { openAppUpdateLink() { if (Platform.isAndroid) { - // _launchURL("https://play.google.com/store/apps/details?id=com.ejada.hmg"); - InAppUpdate.checkForUpdate().then((info) { - print("checkForUpdate!!!"); - print(info.toString()); - if (info.immediateUpdateAllowed) { - print("Immediate Allowed!!!"); - InAppUpdate.performImmediateUpdate().then((value) {}).catchError((e) => print(e.toString())); - } - }).catchError((e) { - print(e.toString()); - Utils.openWebView( - // url: "https://play.google.com/store/apps/details?id=com.ejada.hmg", - url: "https://play.google.com/store/apps/details?id=com.cloudsolutions.HMGPatientApp", - ); - }); + _handleAndroidAppUpdate(); } if (Platform.isIOS) { Utils.openWebView( @@ -95,4 +81,43 @@ class AppUpdatePage extends StatelessWidget { ); } } + + Future _handleAndroidAppUpdate() async { + const fallbackUrl = "https://play.google.com/store/apps/details?id=com.cloudsolutions.HMGPatientApp"; + try { + final info = await InAppUpdate.checkForUpdate(); + print("InAppUpdate.checkForUpdate -> $info"); + + if (info != null) { + final immediateAllowed = info.immediateUpdateAllowed ?? false; + final flexibleAllowed = info.flexibleUpdateAllowed ?? false; + + print("immediateAllowed: $immediateAllowed, flexibleAllowed: $flexibleAllowed"); + + if (immediateAllowed) { + print("Performing immediate update..."); + await InAppUpdate.performImmediateUpdate(); + return; + } + + if (flexibleAllowed) { + print("Starting flexible update..."); + await InAppUpdate.startFlexibleUpdate(); + try { + await InAppUpdate.completeFlexibleUpdate(); + } catch (e) { + print("Error completing flexible update: $e"); + } + return; + } + } + + print("No in-app update allowed/available; opening Play Store page"); + Utils.openWebView(url: fallbackUrl); + } catch (e, st) { + print("InAppUpdate.checkForUpdate threw an exception: $e"); + print(st); + Utils.openWebView(url: fallbackUrl); + } + } } diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index 1e48083c..abc5f998 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -37,11 +37,13 @@ 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/login.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/hmg_services/services_page.dart'; +import 'package:hmg_patient_app_new/presentation/home/app_update_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/lakum_wallet_card.dart'; @@ -290,6 +292,16 @@ class _LandingPageState extends State { text: LocaleKeys.loginOrRegister.tr(context: context), onPressed: () async { await authVM.onLoginPressed(); + + // Navigator.of(context).push( + // CustomPageRoute( + // // page: NotificationsListPage(), + // page: AppUpdatePage( + // appUpdateMessage: + // "A new update for Dr.Alhabib app is now available with new features and services.\r\nFor technical support:\r\neservices.hmg@drsulaimanalhabib.com"), + // ), + // ); + // ...existing commented code... }, backgroundColor: AppColors.secondaryLightRedColor, diff --git a/pubspec.yaml b/pubspec.yaml index 4531e800..85bcb302 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.35+34 +version: 0.0.37+36 #version: 0.0.6+3 environment: @@ -106,6 +106,7 @@ dependencies: flutter_paytabs_bridge: ^2.7.13 clarity_flutter: 1.9.0 + flutter_amazonpaymentservices: ^0.0.13 dev_dependencies: flutter_test: