8-20/1
This commit is contained in:
BIN
assets/fonts/digital-counter-7.regular.ttf
Normal file
BIN
assets/fonts/digital-counter-7.regular.ttf
Normal file
Binary file not shown.
@@ -10,4 +10,8 @@ class BoxName {
|
|||||||
static const String email = "email";
|
static const String email = "email";
|
||||||
static const String tokens = "tokens";
|
static const String tokens = "tokens";
|
||||||
static const String tokenFCM = "tokenFCM";
|
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";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:ride/constant/box_name.dart';
|
import 'package:ride/constant/box_name.dart';
|
||||||
import 'package:ride/constant/links.dart';
|
import 'package:ride/constant/links.dart';
|
||||||
import 'package:ride/controller/functions/crud.dart';
|
import 'package:ride/controller/functions/crud.dart';
|
||||||
|
import 'package:ride/controller/functions/secure_storage.dart';
|
||||||
import 'package:ride/main.dart';
|
import 'package:ride/main.dart';
|
||||||
import 'package:ride/views/auth/verify_email_page.dart';
|
import 'package:ride/views/auth/verify_email_page.dart';
|
||||||
import 'package:ride/views/home/map_page.dart';
|
import 'package:ride/views/home/map_page.dart';
|
||||||
@@ -20,7 +21,7 @@ class LoginController extends GetxController {
|
|||||||
TextEditingController passwordController = TextEditingController();
|
TextEditingController passwordController = TextEditingController();
|
||||||
bool isAgreeTerms = false;
|
bool isAgreeTerms = false;
|
||||||
bool isloading = false;
|
bool isloading = false;
|
||||||
final FlutterSecureStorage _storage = FlutterSecureStorage();
|
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
void changeAgreeTerm() {
|
void changeAgreeTerm() {
|
||||||
isAgreeTerms = !isAgreeTerms;
|
isAgreeTerms = !isAgreeTerms;
|
||||||
@@ -33,15 +34,6 @@ class LoginController extends GetxController {
|
|||||||
update();
|
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 {
|
void login() async {
|
||||||
isloading = true;
|
isloading = true;
|
||||||
update();
|
update();
|
||||||
@@ -65,7 +57,8 @@ class LoginController extends GetxController {
|
|||||||
box.write(BoxName.email, jsonDecoeded['data'][0]['email']);
|
box.write(BoxName.email, jsonDecoeded['data'][0]['email']);
|
||||||
box.write(BoxName.name, jsonDecoeded['data'][0]['first_name']);
|
box.write(BoxName.name, jsonDecoeded['data'][0]['first_name']);
|
||||||
box.write(BoxName.phone, jsonDecoeded['data'][0]['phone']);
|
box.write(BoxName.phone, jsonDecoeded['data'][0]['phone']);
|
||||||
saveData(BoxName.passwoerd, passwordController.text);
|
SecureStorage()
|
||||||
|
.saveData(BoxName.passwoerd, passwordController.text);
|
||||||
Get.offAll(() => MapPage());
|
Get.offAll(() => MapPage());
|
||||||
isloading = false;
|
isloading = false;
|
||||||
update();
|
update();
|
||||||
|
|||||||
42
lib/controller/functions/digit_obsecur_formate.dart
Normal file
42
lib/controller/functions/digit_obsecur_formate.dart
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
lib/controller/functions/scan_id_card.dart
Normal file
25
lib/controller/functions/scan_id_card.dart
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
lib/controller/functions/secure_storage.dart
Normal file
14
lib/controller/functions/secure_storage.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,10 +48,11 @@ class MapController extends GetxController {
|
|||||||
bool isMainBottomMenuMap = true;
|
bool isMainBottomMenuMap = true;
|
||||||
double heightButtomSheetShown = 300;
|
double heightButtomSheetShown = 300;
|
||||||
double cashConfirmPageShown = 250;
|
double cashConfirmPageShown = 250;
|
||||||
double paymentPageShown = 380;
|
double paymentPageShown = Get.height * .6;
|
||||||
late final LatLng southwest;
|
late final LatLng southwest;
|
||||||
late final LatLng northeast;
|
late final LatLng northeast;
|
||||||
List<CarLocationModel> carLocations = <CarLocationModel>[];
|
List<CarLocationModel> carLocations = <CarLocationModel>[];
|
||||||
|
|
||||||
// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
|
// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
|
||||||
void changeButtomSheetShown() {
|
void changeButtomSheetShown() {
|
||||||
isButtomSheetShown = !isButtomSheetShown;
|
isButtomSheetShown = !isButtomSheetShown;
|
||||||
@@ -341,9 +342,9 @@ class MapController extends GetxController {
|
|||||||
|
|
||||||
// Animate the camera to the adjusted bounds
|
// Animate the camera to the adjusted bounds
|
||||||
if (distanceOfDestnation <= 10) {
|
if (distanceOfDestnation <= 10) {
|
||||||
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 14));
|
|
||||||
} else if (distanceOfDestnation > 10 && distanceOfDestnation < 16) {
|
|
||||||
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 12));
|
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 12));
|
||||||
|
} else if (distanceOfDestnation > 10 && distanceOfDestnation < 16) {
|
||||||
|
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 11));
|
||||||
} else if (distanceOfDestnation > 16 && distanceOfDestnation < 30) {
|
} else if (distanceOfDestnation > 16 && distanceOfDestnation < 30) {
|
||||||
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 10));
|
mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 10));
|
||||||
} else if (distanceOfDestnation > 30 && distanceOfDestnation < 100) {
|
} else if (distanceOfDestnation > 30 && distanceOfDestnation < 100) {
|
||||||
@@ -376,18 +377,18 @@ class MapController extends GetxController {
|
|||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
late double totaME;
|
late double totaME = 0;
|
||||||
late double tax;
|
late double tax = 0;
|
||||||
late double totalPassenger;
|
late double totalPassenger = 0;
|
||||||
late double totalDriver;
|
late double totalDriver = 0;
|
||||||
late double averageDuration;
|
late double averageDuration = 0;
|
||||||
late double costDuration;
|
late double costDuration = 0;
|
||||||
late double cost;
|
late double cost = 0;
|
||||||
late double distance;
|
late double distance = 0;
|
||||||
late double duration;
|
late double duration = 2;
|
||||||
DateTime currentTime = DateTime.now();
|
DateTime currentTime = DateTime.now();
|
||||||
late Duration durationToAdd;
|
late Duration durationToAdd;
|
||||||
late DateTime newTime;
|
late DateTime newTime = DateTime.now();
|
||||||
void bottomSheet() {
|
void bottomSheet() {
|
||||||
if (data.isNotEmpty) {
|
if (data.isNotEmpty) {
|
||||||
String distanceText = data[0]['distance']['text'];
|
String distanceText = data[0]['distance']['text'];
|
||||||
@@ -395,12 +396,25 @@ class MapController extends GetxController {
|
|||||||
distance = getDistanceFromText(distanceText);
|
distance = getDistanceFromText(distanceText);
|
||||||
duration = getDistanceFromText(durationText);
|
duration = getDistanceFromText(durationText);
|
||||||
durationToAdd = Duration(minutes: duration.toInt());
|
durationToAdd = Duration(minutes: duration.toInt());
|
||||||
|
DateTime currentTime = DateTime.now();
|
||||||
newTime = currentTime.add(durationToAdd);
|
newTime = currentTime.add(durationToAdd);
|
||||||
|
update();
|
||||||
if (distanceText.contains('km')) {
|
if (currentTime.hour >= 21) {
|
||||||
cost = distance * 0.21;
|
if (distanceText.contains('km')) {
|
||||||
|
cost = distance * 0.23;
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
cost = distance * 0.23 / 1000;
|
||||||
|
update();
|
||||||
|
}
|
||||||
} else {
|
} 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;
|
averageDuration = duration / distance;
|
||||||
costDuration = duration * averageDuration * 0.016;
|
costDuration = duration * averageDuration * 0.016;
|
||||||
@@ -410,12 +424,15 @@ class MapController extends GetxController {
|
|||||||
totaME = totalPassenger - totalDriver - tax;
|
totaME = totalPassenger - totalDriver - tax;
|
||||||
if (totalPassenger < 1) {
|
if (totalPassenger < 1) {
|
||||||
totalPassenger = 1;
|
totalPassenger = 1;
|
||||||
|
update();
|
||||||
if (totalDriver < .5) {
|
if (totalDriver < .5) {
|
||||||
totalDriver = .85;
|
totalDriver = .85;
|
||||||
totaME = .11;
|
totaME = .11;
|
||||||
|
update();
|
||||||
} else {
|
} else {
|
||||||
totalDriver = .95;
|
totalDriver = .95;
|
||||||
totaME = .05;
|
totaME = .05;
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
lib/controller/home/payment/payment_controller.dart
Normal file
88
lib/controller/home/payment/payment_controller.dart
Normal 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,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ Future<void> backgroundMessageHandler(RemoteMessage message) async {
|
|||||||
await Firebase.initializeApp();
|
await Firebase.initializeApp();
|
||||||
print('===========back===${message.notification?.title}');
|
print('===========back===${message.notification?.title}');
|
||||||
|
|
||||||
if (message.notification!.title == 'reef') {
|
if (message.notification!.title == 'ride') {
|
||||||
// SendGpsNow().getSiteNotification();
|
// SendGpsNow().getSiteNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:ride/constant/style.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 'package:ride/views/widgets/elevated_btn.dart';
|
||||||
|
|
||||||
import '../../../constant/colors.dart';
|
import '../../../constant/colors.dart';
|
||||||
@@ -20,7 +21,9 @@ class CashConfirmPageShown extends StatelessWidget {
|
|||||||
left: 5,
|
left: 5,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 400),
|
||||||
height: controller.cashConfirmPageShown,
|
height: controller.isCashConfirmPageShown
|
||||||
|
? controller.cashConfirmPageShown
|
||||||
|
: 0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColor.secondaryColor,
|
color: AppColor.secondaryColor,
|
||||||
borderRadius: BorderRadius.circular(15)),
|
borderRadius: BorderRadius.circular(15)),
|
||||||
@@ -110,10 +113,11 @@ class CashConfirmPageShown extends StatelessWidget {
|
|||||||
indent: 1,
|
indent: 1,
|
||||||
),
|
),
|
||||||
MyElevatedButton(
|
MyElevatedButton(
|
||||||
title: 'Add Payment Method',
|
title: 'Add Payment Method',
|
||||||
onPressed: () =>
|
onPressed: () {
|
||||||
controller.changePaymentMethodPageShown(),
|
controller.changePaymentMethodPageShown();
|
||||||
)
|
CreditCardController().openPayment();
|
||||||
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:get/get.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 'package:ride/views/widgets/elevated_btn.dart';
|
||||||
|
|
||||||
import '../../../constant/colors.dart';
|
import '../../../constant/colors.dart';
|
||||||
import '../../../constant/style.dart';
|
import '../../../constant/style.dart';
|
||||||
|
import '../../../controller/functions/digit_obsecur_formate.dart';
|
||||||
import '../../../controller/home/map_page_controller.dart';
|
import '../../../controller/home/map_page_controller.dart';
|
||||||
|
|
||||||
class PaymentMethodPage extends StatelessWidget {
|
class PaymentMethodPage extends StatelessWidget {
|
||||||
@@ -20,7 +25,9 @@ class PaymentMethodPage extends StatelessWidget {
|
|||||||
left: 5,
|
left: 5,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 400),
|
||||||
height: controller.paymentPageShown,
|
height: controller.isPaymentMethodPageShown
|
||||||
|
? controller.paymentPageShown
|
||||||
|
: 0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColor.secondaryColor,
|
color: AppColor.secondaryColor,
|
||||||
borderRadius: BorderRadius.circular(15)),
|
borderRadius: BorderRadius.circular(15)),
|
||||||
@@ -43,41 +50,57 @@ class PaymentMethodPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(
|
Row(
|
||||||
'Add Card'.tr,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
style: AppStyle.title,
|
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(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
Container(
|
const CreditCardWidget(),
|
||||||
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 Spacer(),
|
const Spacer(),
|
||||||
Row(
|
GetBuilder<CreditCardController>(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
builder: (controller) => Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
MyElevatedButton(
|
children: [
|
||||||
title: 'Add Credit Card',
|
MyElevatedButton(
|
||||||
onPressed: () {},
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
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:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
24
pubspec.yaml
24
pubspec.yaml
@@ -54,6 +54,7 @@ dependencies:
|
|||||||
custom_searchable_dropdown: ^2.1.1
|
custom_searchable_dropdown: ^2.1.1
|
||||||
animated_text_kit: ^4.2.2
|
animated_text_kit: ^4.2.2
|
||||||
flutter_secure_storage: ^8.0.0
|
flutter_secure_storage: ^8.0.0
|
||||||
|
credit_card_scanner: ^1.0.5
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -81,24 +82,13 @@ flutter:
|
|||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/lottie/
|
- assets/lottie/
|
||||||
# - images/a_dot_ham.jpeg
|
- assets/fonts/
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
fonts:
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
- family: digital-counter-7
|
||||||
|
fonts:
|
||||||
# For details regarding adding assets from package dependencies, see
|
- asset: assets/fonts/digital-counter-7.regular.ttf
|
||||||
# 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
|
|
||||||
# style: italic
|
# style: italic
|
||||||
# - family: Trajan Pro
|
# - family: Trajan Pro
|
||||||
# fonts:
|
# fonts:
|
||||||
|
|||||||
Reference in New Issue
Block a user