From b340316e11625b2405c7e0d59fcc0404c929bfe8 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Mon, 21 Aug 2023 00:07:08 +0300 Subject: [PATCH] 8-20/1 --- assets/fonts/digital-counter-7.regular.ttf | Bin 0 -> 29836 bytes lib/constant/box_name.dart | 4 + lib/controller/auth/login_controller.dart | 15 +- .../functions/digit_obsecur_formate.dart | 42 +++ lib/controller/functions/scan_id_card.dart | 25 ++ lib/controller/functions/secure_storage.dart | 14 + lib/controller/home/map_page_controller.dart | 51 ++- .../home/payment/payment_controller.dart | 88 +++++ lib/main.dart | 2 +- .../cash_confirm_bottom_page.dart | 14 +- .../map_widget.dart/payment_method.page.dart | 310 ++++++++++++++++-- pubspec.lock | 8 + pubspec.yaml | 24 +- 13 files changed, 515 insertions(+), 82 deletions(-) create mode 100644 assets/fonts/digital-counter-7.regular.ttf create mode 100644 lib/controller/functions/digit_obsecur_formate.dart create mode 100644 lib/controller/functions/scan_id_card.dart create mode 100644 lib/controller/functions/secure_storage.dart create mode 100644 lib/controller/home/payment/payment_controller.dart diff --git a/assets/fonts/digital-counter-7.regular.ttf b/assets/fonts/digital-counter-7.regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..81775ee5b43d0ba3f97f1dd950c01bf4dd17aff7 GIT binary patch literal 29836 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 readData(String boxName) async { - final String? value = await _storage.read(key: boxName); - return value; - } - void login() async { isloading = true; update(); @@ -65,7 +57,8 @@ class LoginController extends GetxController { box.write(BoxName.email, jsonDecoeded['data'][0]['email']); box.write(BoxName.name, jsonDecoeded['data'][0]['first_name']); box.write(BoxName.phone, jsonDecoeded['data'][0]['phone']); - saveData(BoxName.passwoerd, passwordController.text); + SecureStorage() + .saveData(BoxName.passwoerd, passwordController.text); Get.offAll(() => MapPage()); isloading = false; update(); diff --git a/lib/controller/functions/digit_obsecur_formate.dart b/lib/controller/functions/digit_obsecur_formate.dart new file mode 100644 index 0000000..b5972e4 --- /dev/null +++ b/lib/controller/functions/digit_obsecur_formate.dart @@ -0,0 +1,42 @@ +import 'package:flutter/services.dart'; + +class DigitObscuringFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + final maskedText = maskDigits(newValue.text); + return newValue.copyWith( + text: maskedText, + selection: updateCursorPosition(maskedText, newValue.selection)); + } + + String maskDigits(String text) { + final totalDigits = text.length; + final visibleDigits = 4; + final hiddenDigits = totalDigits - visibleDigits * 2; + + final firstVisibleDigits = text.substring(0, visibleDigits); + final lastVisibleDigits = text.substring(totalDigits - visibleDigits); + + final maskedDigits = List.filled(hiddenDigits, '*').join(); + + return '$firstVisibleDigits$maskedDigits$lastVisibleDigits'; + } + + TextSelection updateCursorPosition( + String maskedText, TextSelection currentSelection) { + final cursorPosition = currentSelection.baseOffset; + final cursorOffset = + currentSelection.extentOffset - currentSelection.baseOffset; + final totalDigits = maskedText.length; + const visibleDigits = 4; + final hiddenDigits = totalDigits - visibleDigits * 2; + + final updatedPosition = cursorPosition <= visibleDigits + ? cursorPosition + : hiddenDigits + visibleDigits + (cursorPosition - visibleDigits); + + return TextSelection.collapsed( + offset: updatedPosition, affinity: currentSelection.affinity); + } +} diff --git a/lib/controller/functions/scan_id_card.dart b/lib/controller/functions/scan_id_card.dart new file mode 100644 index 0000000..3c7cb96 --- /dev/null +++ b/lib/controller/functions/scan_id_card.dart @@ -0,0 +1,25 @@ +import 'package:credit_card_scanner/credit_card_scanner.dart'; +import 'package:get/get.dart'; + +class ScanIdCard extends GetxController { + CardDetails? _cardDetails; + CardScanOptions scanOptions = const CardScanOptions( + scanCardHolderName: true, +// enableDebugLogs: true, + validCardsToScanBeforeFinishingScan: 5, + possibleCardHolderNamePositions: [ + CardHolderNameScanPosition.aboveCardNumber, + ], + ); + + Future scanCard() async { + final CardDetails? cardDetails = + await CardScanner.scanCard(scanOptions: scanOptions); + if (cardDetails == null) { + return; + } + + _cardDetails = cardDetails; + update(); + } +} diff --git a/lib/controller/functions/secure_storage.dart b/lib/controller/functions/secure_storage.dart new file mode 100644 index 0000000..364dced --- /dev/null +++ b/lib/controller/functions/secure_storage.dart @@ -0,0 +1,14 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SecureStorage { + final FlutterSecureStorage _storage = const FlutterSecureStorage(); + + void saveData(String key, value) async { + await _storage.write(key: key, value: value); + } + + Future readData(String boxName) async { + final String? value = await _storage.read(key: boxName); + return value; + } +} diff --git a/lib/controller/home/map_page_controller.dart b/lib/controller/home/map_page_controller.dart index 8cbb9c4..4a63a97 100644 --- a/lib/controller/home/map_page_controller.dart +++ b/lib/controller/home/map_page_controller.dart @@ -48,10 +48,11 @@ class MapController extends GetxController { bool isMainBottomMenuMap = true; double heightButtomSheetShown = 300; double cashConfirmPageShown = 250; - double paymentPageShown = 380; + double paymentPageShown = Get.height * .6; late final LatLng southwest; late final LatLng northeast; List carLocations = []; + // final mainBottomMenuMap = GlobalKey(); void changeButtomSheetShown() { isButtomSheetShown = !isButtomSheetShown; @@ -341,9 +342,9 @@ class MapController extends GetxController { // Animate the camera to the adjusted bounds if (distanceOfDestnation <= 10) { - mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 14)); - } else if (distanceOfDestnation > 10 && distanceOfDestnation < 16) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 12)); + } else if (distanceOfDestnation > 10 && distanceOfDestnation < 16) { + mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 11)); } else if (distanceOfDestnation > 16 && distanceOfDestnation < 30) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 10)); } else if (distanceOfDestnation > 30 && distanceOfDestnation < 100) { @@ -376,18 +377,18 @@ class MapController extends GetxController { return distance; } - late double totaME; - late double tax; - late double totalPassenger; - late double totalDriver; - late double averageDuration; - late double costDuration; - late double cost; - late double distance; - late double duration; + late double totaME = 0; + late double tax = 0; + late double totalPassenger = 0; + late double totalDriver = 0; + late double averageDuration = 0; + late double costDuration = 0; + late double cost = 0; + late double distance = 0; + late double duration = 2; DateTime currentTime = DateTime.now(); late Duration durationToAdd; - late DateTime newTime; + late DateTime newTime = DateTime.now(); void bottomSheet() { if (data.isNotEmpty) { String distanceText = data[0]['distance']['text']; @@ -395,12 +396,25 @@ class MapController extends GetxController { distance = getDistanceFromText(distanceText); duration = getDistanceFromText(durationText); durationToAdd = Duration(minutes: duration.toInt()); + DateTime currentTime = DateTime.now(); newTime = currentTime.add(durationToAdd); - - if (distanceText.contains('km')) { - cost = distance * 0.21; + update(); + if (currentTime.hour >= 21) { + if (distanceText.contains('km')) { + cost = distance * 0.23; + update(); + } else { + cost = distance * 0.23 / 1000; + update(); + } } else { - cost = distance * 0.21 / 1000; + if (distanceText.contains('km')) { + cost = distance * 0.21; + update(); + } else { + cost = distance * 0.21 / 1000; + update(); + } } averageDuration = duration / distance; costDuration = duration * averageDuration * 0.016; @@ -410,12 +424,15 @@ class MapController extends GetxController { totaME = totalPassenger - totalDriver - tax; if (totalPassenger < 1) { totalPassenger = 1; + update(); if (totalDriver < .5) { totalDriver = .85; totaME = .11; + update(); } else { totalDriver = .95; totaME = .05; + update(); } } } diff --git a/lib/controller/home/payment/payment_controller.dart b/lib/controller/home/payment/payment_controller.dart new file mode 100644 index 0000000..a340bb6 --- /dev/null +++ b/lib/controller/home/payment/payment_controller.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../../constant/box_name.dart'; +import '../../functions/digit_obsecur_formate.dart'; +import '../../functions/secure_storage.dart'; + +class CreditCardController extends GetxController { + final GlobalKey formKey = GlobalKey(); + final TextEditingController cardNumberController = TextEditingController(); + final TextEditingController cardHolderNameController = + TextEditingController(); + final TextEditingController expiryDateController = TextEditingController(); + final TextEditingController cvvCodeController = TextEditingController(); + openPayment() async { + String? cardNumber = await SecureStorage().readData(BoxName.cardNumber); + String? cardHolderName = + await SecureStorage().readData(BoxName.cardHolderName); + String? expiryDate = await SecureStorage().readData(BoxName.expiryDate); + String? cvvCode = await SecureStorage().readData(BoxName.cvvCode); + + print('cardNumber: $cardNumber'); + print('cardHolderName: $cardHolderName'); + print('expiryDate: $expiryDate'); + print('cvvCode: $cvvCode'); + + if (cvvCode != null && cvvCode.isNotEmpty) { + final maskedCardNumber = DigitObscuringFormatter() + .formatEditUpdate( + TextEditingValue.empty, + TextEditingValue(text: cardNumber ?? ''), + ) + .text; + + print('maskedCardNumber: $maskedCardNumber'); + + cardNumberController.text = maskedCardNumber; + cardHolderNameController.text = cardHolderName ?? ''; + expiryDateController.text = expiryDate ?? ''; + cvvCodeController.text = cvvCode; + } + } + + @override + void onInit() async { + super.onInit(); + String? cardNumber = await SecureStorage().readData(BoxName.cardNumber); + String? cardHolderName = + await SecureStorage().readData(BoxName.cardHolderName); + String? expiryDate = await SecureStorage().readData(BoxName.expiryDate); + String? cvvCode = await SecureStorage().readData(BoxName.cvvCode); + + print('cardNumber: $cardNumber'); + print('cardHolderName: $cardHolderName'); + print('expiryDate: $expiryDate'); + print('cvvCode: $cvvCode'); + + if (cvvCode != null && cvvCode.isNotEmpty) { + final maskedCardNumber = DigitObscuringFormatter() + .formatEditUpdate( + TextEditingValue.empty, + TextEditingValue(text: cardNumber ?? ''), + ) + .text; + + print('maskedCardNumber: $maskedCardNumber'); + + cardNumberController.text = maskedCardNumber; + cardHolderNameController.text = cardHolderName ?? ''; + expiryDateController.text = expiryDate ?? ''; + cvvCodeController.text = cvvCode; + } + } +} + +class CreditCardModel { + String cardNumber; + String cardHolderName; + String expiryDate; + String cvvCode; + + CreditCardModel({ + required this.cardNumber, + required this.cardHolderName, + required this.expiryDate, + required this.cvvCode, + }); +} diff --git a/lib/main.dart b/lib/main.dart index e42aa52..0823ce9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,7 +24,7 @@ Future backgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(); print('===========back===${message.notification?.title}'); - if (message.notification!.title == 'reef') { + if (message.notification!.title == 'ride') { // SendGpsNow().getSiteNotification(); } } diff --git a/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart b/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart index 489ad70..72837b7 100644 --- a/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart +++ b/lib/views/home/map_widget.dart/cash_confirm_bottom_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ride/constant/style.dart'; +import 'package:ride/controller/home/payment/payment_controller.dart'; import 'package:ride/views/widgets/elevated_btn.dart'; import '../../../constant/colors.dart'; @@ -20,7 +21,9 @@ class CashConfirmPageShown extends StatelessWidget { left: 5, child: AnimatedContainer( duration: const Duration(milliseconds: 400), - height: controller.cashConfirmPageShown, + height: controller.isCashConfirmPageShown + ? controller.cashConfirmPageShown + : 0, decoration: BoxDecoration( color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(15)), @@ -110,10 +113,11 @@ class CashConfirmPageShown extends StatelessWidget { indent: 1, ), MyElevatedButton( - title: 'Add Payment Method', - onPressed: () => - controller.changePaymentMethodPageShown(), - ) + title: 'Add Payment Method', + onPressed: () { + controller.changePaymentMethodPageShown(); + CreditCardController().openPayment(); + }) ], ), ), diff --git a/lib/views/home/map_widget.dart/payment_method.page.dart b/lib/views/home/map_widget.dart/payment_method.page.dart index 490d2a0..039bd74 100644 --- a/lib/views/home/map_widget.dart/payment_method.page.dart +++ b/lib/views/home/map_widget.dart/payment_method.page.dart @@ -1,9 +1,14 @@ import 'package:flutter/material.dart'; + import 'package:get/get.dart'; +import 'package:ride/constant/box_name.dart'; +import 'package:ride/controller/functions/secure_storage.dart'; +import 'package:ride/controller/home/payment/payment_controller.dart'; import 'package:ride/views/widgets/elevated_btn.dart'; import '../../../constant/colors.dart'; import '../../../constant/style.dart'; +import '../../../controller/functions/digit_obsecur_formate.dart'; import '../../../controller/home/map_page_controller.dart'; class PaymentMethodPage extends StatelessWidget { @@ -20,7 +25,9 @@ class PaymentMethodPage extends StatelessWidget { left: 5, child: AnimatedContainer( duration: const Duration(milliseconds: 400), - height: controller.paymentPageShown, + height: controller.isPaymentMethodPageShown + ? controller.paymentPageShown + : 0, decoration: BoxDecoration( color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(15)), @@ -43,41 +50,57 @@ class PaymentMethodPage extends StatelessWidget { ), ], ), - Text( - 'Add Card'.tr, - style: AppStyle.title, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Add Card'.tr, + style: AppStyle.title, + ), + // GetBuilder( + // builder: (controller) => IconButton( + // onPressed: () { + // // controller.scanCard(); + // // Get.defaultDialog(content: OptionConfigureWidget( + // // initialOptions: scanOptions, + // // onScanOptionChanged: (newOptions) => + // // scanOptions = newOptions, + // // ), + // // ); + // }, + // icon: const Icon(Icons.contact_emergency_sharp), + // ), + // ) + ], ), const SizedBox( height: 10, ), - Container( - height: Get.height * .3, - decoration: const BoxDecoration( - color: AppColor.secondaryColor, - borderRadius: BorderRadius.all(Radius.circular(15)), - boxShadow: [ - BoxShadow( - spreadRadius: 3, - offset: Offset(3, 3), - blurRadius: 3, - color: AppColor.redColor), - BoxShadow( - offset: Offset(-3, -3), - blurRadius: 3, - spreadRadius: 3, - color: AppColor.redColor) - ]), - ), + const CreditCardWidget(), const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - MyElevatedButton( - title: 'Add Credit Card', - onPressed: () {}, - ), - ], - ) + GetBuilder( + builder: (controller) => Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MyElevatedButton( + title: 'Add Credit Card', + onPressed: () async { + SecureStorage().saveData( + BoxName.cardNumber, + controller.cardNumberController.text); + SecureStorage().saveData( + BoxName.cardHolderName, + controller + .cardHolderNameController.text); + SecureStorage().saveData(BoxName.cvvCode, + controller.cvvCodeController.text); + SecureStorage().saveData( + BoxName.expiryDate, + controller.expiryDateController.text); + }, + ), + ], + )) ], ), ), @@ -85,3 +108,228 @@ class PaymentMethodPage extends StatelessWidget { )); } } + +class CreditCardWidget extends StatelessWidget { + const CreditCardWidget({ + super.key, + }); + + @override + Widget build(BuildContext context) { + Get.put(CreditCardController()); + return GetBuilder( + builder: (controller) => Container( + height: Get.height * .3, + decoration: const BoxDecoration( + color: AppColor.secondaryColor, + borderRadius: BorderRadius.all(Radius.circular(15)), + boxShadow: [ + BoxShadow( + spreadRadius: 3, + offset: Offset(3, 3), + blurRadius: 3, + color: AppColor.redColor), + BoxShadow( + offset: Offset(-3, -3), + blurRadius: 3, + spreadRadius: 3, + color: AppColor.redColor), + ], + ), + child: Form( + key: controller.formKey, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + SizedBox( + child: Row( + children: [ + getCardIcon(controller.cardNumberController + .text), // Dynamic credit card icon + SizedBox( + width: Get.width * .1, + ), + SizedBox( + width: Get.width * .6, + height: 70, + child: TextFormField( + maxLength: 16, + keyboardType: TextInputType.number, + controller: controller.cardNumberController, + style: const TextStyle( + fontFamily: 'digital-counter-7', + fontWeight: FontWeight.bold), + decoration: const InputDecoration( + helperStyle: TextStyle( + fontFamily: 'digital-counter-7'), + labelText: 'Card Number', + ), + inputFormatters: [DigitObscuringFormatter()], + validator: (value) { + if (value!.isEmpty || value.length != 16) { + return 'Please enter a valid 16-digit card number'; + } + return null; + }, + ), + ), + ], + ), + ), + Row( + children: [ + const Icon(Icons.person), + SizedBox( + width: Get.width * .1, + ), + SizedBox( + width: Get.width * .6, + child: SizedBox( + height: 50, + child: TextFormField( + style: AppStyle.title, + keyboardType: TextInputType.text, + // maxLength: 16, + controller: controller.cardHolderNameController, + decoration: const InputDecoration( + labelText: 'Cardholder Name'), + validator: (value) { + if (value!.isEmpty) { + return 'Please enter the cardholder name'; + } + return null; + }, + ), + ), + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: Get.width * .4, + child: Row( + children: [ + const Icon(Icons.date_range_outlined), + SizedBox( + width: Get.width * .1, + ), + SizedBox( + width: Get.width * .2, + child: SizedBox( + height: 60, + child: TextFormField( + keyboardType: TextInputType.datetime, + controller: + controller.expiryDateController, + decoration: const InputDecoration( + labelText: 'Expiry Date'), + validator: (value) { + if (value!.isEmpty) { + return 'Please enter the expiry date'; + } + return null; + }, + ), + ), + ) + ], + ), + ), + SizedBox( + width: Get.width * .4, + child: Row( + children: [ + const Icon(Icons.security), + SizedBox( + width: Get.width * .021, + ), + SizedBox( + width: Get.width * .2, + child: SizedBox( + height: 60, + child: TextFormField( + obscureText: true, + keyboardType: TextInputType.number, + style: const TextStyle( + fontFamily: 'digital-counter-7'), + maxLength: 3, + controller: controller.cvvCodeController, + decoration: const InputDecoration( + labelText: 'CVV Code'), + validator: (value) { + if (value!.isEmpty && + value.length != 3) { + return 'Please enter the CVV code'; + } + return null; + }, + ), + ), + ) + ], + ), + ), + ], + ), + // MyElevatedButton( + // title: 'Save'.tr, + // onPressed: () { + // if (controller.formKey.currentState!.validate()) { + // final creditCard = CreditCardModel( + // cardNumber: controller.cardNumberController.text, + // cardHolderName: + // controller.cardHolderNameController.text, + // expiryDate: controller.expiryDateController.text, + // cvvCode: controller.cvvCodeController.text, + // ); + // // Process the credit card details + // // You can use GetX to handle the logic here + // } + // }, + // ), + ], + ), + )))); + } + + Widget getCardIcon(String cardNumber) { + String cardType = detectCardType( + cardNumber); // Function to detect card type based on the first digit + + IconData iconData; + Color iconColor; + + switch (cardType) { + case 'Visa': + iconData = Icons.credit_card_rounded; + iconColor = Colors.blue; // Change color for Visa cards + break; + case 'Mastercard': + iconData = Icons.credit_card_rounded; + iconColor = Colors.red; // Change color for Mastercard cards + break; + default: + iconData = Icons.credit_card_rounded; + iconColor = Colors.black; // Default color for other card types + break; + } + + return Icon( + iconData, + color: iconColor, + ); + } + + String detectCardType(String cardNumber) { + if (cardNumber.startsWith('4')) { + return 'Visa'; + } else if (cardNumber.startsWith('5')) { + return 'Mastercard'; + } else { + return 'Other'; + } + } +} diff --git a/pubspec.lock b/pubspec.lock index ff53945..f212ac9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + credit_card_scanner: + dependency: "direct main" + description: + name: credit_card_scanner + sha256: "9bbfcac698f01bb32cbb2abfc6a9efa7fdea006e5a982cb4b8dc69fa0e8c1d19" + url: "https://pub.dev" + source: hosted + version: "1.0.5" crypto: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d07b1de..01b65fa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,7 @@ dependencies: custom_searchable_dropdown: ^2.1.1 animated_text_kit: ^4.2.2 flutter_secure_storage: ^8.0.0 + credit_card_scanner: ^1.0.5 dev_dependencies: flutter_test: @@ -81,24 +82,13 @@ flutter: assets: - assets/images/ - assets/lottie/ - # - images/a_dot_ham.jpeg + - assets/fonts/ - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf + fonts: + - family: digital-counter-7 + fonts: + - asset: assets/fonts/digital-counter-7.regular.ttf + # style: italic # - family: Trajan Pro # fonts: