This commit is contained in:
Hamza-Ayed
2023-08-21 00:07:08 +03:00
parent 6a3865a3d1
commit b340316e11
13 changed files with 515 additions and 82 deletions

Binary file not shown.

View File

@@ -10,4 +10,8 @@ class BoxName {
static const String email = "email";
static const String tokens = "tokens";
static const String tokenFCM = "tokenFCM";
static const String cardNumber = "cardNumber";
static const String cardHolderName = "cardHolderName";
static const String expiryDate = "expiryDate";
static const String cvvCode = "cvvCode";
}

View File

@@ -7,6 +7,7 @@ import 'package:get/get.dart';
import 'package:ride/constant/box_name.dart';
import 'package:ride/constant/links.dart';
import 'package:ride/controller/functions/crud.dart';
import 'package:ride/controller/functions/secure_storage.dart';
import 'package:ride/main.dart';
import 'package:ride/views/auth/verify_email_page.dart';
import 'package:ride/views/home/map_page.dart';
@@ -20,7 +21,7 @@ class LoginController extends GetxController {
TextEditingController passwordController = TextEditingController();
bool isAgreeTerms = false;
bool isloading = false;
final FlutterSecureStorage _storage = FlutterSecureStorage();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
void changeAgreeTerm() {
isAgreeTerms = !isAgreeTerms;
@@ -33,15 +34,6 @@ class LoginController extends GetxController {
update();
}
void saveData(String key, value) async {
await _storage.write(key: key, value: value);
}
Future<String?> 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();

View File

@@ -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);
}
}

View File

@@ -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<void> scanCard() async {
final CardDetails? cardDetails =
await CardScanner.scanCard(scanOptions: scanOptions);
if (cardDetails == null) {
return;
}
_cardDetails = cardDetails;
update();
}
}

View File

@@ -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<String?> readData(String boxName) async {
final String? value = await _storage.read(key: boxName);
return value;
}
}

View File

@@ -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<CarLocationModel> carLocations = <CarLocationModel>[];
// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
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();
}
}
}

View File

@@ -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<FormState> formKey = GlobalKey<FormState>();
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,
});
}

View File

@@ -24,7 +24,7 @@ Future<void> backgroundMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('===========back===${message.notification?.title}');
if (message.notification!.title == 'reef') {
if (message.notification!.title == 'ride') {
// SendGpsNow().getSiteNotification();
}
}

View File

@@ -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();
})
],
),
),

View File

@@ -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<CreditCardController>(
// 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<CreditCardController>(
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<CreditCardController>(
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';
}
}
}

View File

@@ -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:

View File

@@ -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: