Merge branch 'faiz_development_common' into 'master'

Added Payment Module

See merge request mirza.shafique/car_common_app!14
pull/1/head
Mirza Shafique 2 years ago
commit 8fcf125c0c

@ -53,7 +53,9 @@ class ApiConsts {
//Appointment APIs
static String serviceProvidersAppointmentGet = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Get";
static String serviceCategoryGet = "${baseUrlServices}api/Master/ServiceCategory_Get";
static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get";
static String serviceItemsGet = "${baseUrlServices}api/ServiceProviders/ServiceItem_Get";
//ServiceProvidersServiceID as params
// static String servicesGet = "${baseUrlServices}api/ServiceProviders/Services_Get";
//Services & items
static String createService = "${baseUrlServices}api/ServiceProviders/Service_Create";
@ -92,6 +94,12 @@ class ApiConsts {
//Subscription
static String getAllSubscriptions = "${baseUrlServices}api/Common/Subscription_Get";
// Payment
static String paymentWebViewUrl = "https://ms.hmg.com/pay/PaymentHome";
static String payForOrderDetailGet = "${baseUrlServices}api/Payment/PayFortOrderDetail_Get";
static List<String> closingUrls = ["PayFortResponse"];
}
class GlobalConsts {

@ -6,8 +6,10 @@ import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/repositories/ads_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/repositories/user_repo.dart';
import 'package:mc_common_app/services/services.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/services/payments_service.dart';
Injector injector = Injector.appInstance;
@ -16,11 +18,13 @@ class AppDependencies {
//services
injector.registerSingleton<AppState>(() => AppState());
injector.registerSingleton<ApiClient>(() => ApiClientImp());
injector.registerSingleton<CommonServices>(() => CommonServicesImp());
injector.registerSingleton<CommonAppServices>(() => CommonServicesImp());
injector.registerSingleton<PaymentService>(() => PaymentServiceImp());
//repos
injector.registerSingleton<UserRepo>(() => UserRepoImp());
injector.registerSingleton<CommonRepo>(() => CommonRepoImp());
injector.registerSingleton<AdsRepo>(() => AdsRepoImp());
injector.registerSingleton<PaymentsRepo>(() => PaymentsRepoImp());
}
}

@ -5,22 +5,23 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
extension EmailValidator on String {
Widget toText(
{Color? color,
bool isBold = false,
double? fontSize,
bool isUnderLine = false,
TextDecoration? textDecoration,
double letterSpacing = -0.4,
TextAlign? textAlign,
double? height,
int? maxLines}) =>
Widget toText({Color? color,
bool isBold = false,
double? fontSize,
bool isUnderLine = false,
bool isItalic = false,
TextDecoration? textDecoration,
double letterSpacing = -0.4,
TextAlign? textAlign,
double? height,
int? maxLines}) =>
AutoSizeText(
this,
textAlign: textAlign,
maxLines: maxLines,
style: TextStyle(
fontStyle: isItalic ? FontStyle.italic : null,
height: height,
decoration: isUnderLine ? TextDecoration.underline : textDecoration ?? TextDecoration.none,
fontSize: fontSize ?? 10,

@ -0,0 +1,68 @@
class PayOrderDetailRespModel {
int? id;
String? userFullName;
String? userMobile;
String? userEmail;
String? userID;
double? amount;
String? currency;
int? payFortProjectID;
int? payFortServiceID;
String? description;
bool? isPaid;
String? language;
int? serviceAppointmentID;
int? providerSubscriptionID;
PayOrderDetailRespModel(
{this.id,
this.userFullName,
this.userMobile,
this.userEmail,
this.userID,
this.amount,
this.currency,
this.payFortProjectID,
this.payFortServiceID,
this.description,
this.isPaid,
this.language,
this.serviceAppointmentID,
this.providerSubscriptionID});
PayOrderDetailRespModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
userFullName = json['userFullName'];
userMobile = json['userMobile'];
userEmail = json['userEmail'];
userID = json['userID'];
amount = json['amount'];
currency = json['currency'];
payFortProjectID = json['payFort_ProjectID'];
payFortServiceID = json['payFort_ServiceID'];
description = json['description'];
isPaid = json['isPaid'];
language = json['language'];
serviceAppointmentID = json['serviceAppointmentID'];
providerSubscriptionID = json['providerSubscriptionID'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['userFullName'] = userFullName;
data['userMobile'] = userMobile;
data['userEmail'] = userEmail;
data['userID'] = userID;
data['amount'] = amount;
data['currency'] = currency;
data['payFort_ProjectID'] = payFortProjectID;
data['payFort_ServiceID'] = payFortServiceID;
data['description'] = description;
data['isPaid'] = isPaid;
data['language'] = language;
data['serviceAppointmentID'] = serviceAppointmentID;
data['providerSubscriptionID'] = providerSubscriptionID;
return data;
}
}

@ -0,0 +1,22 @@
import 'package:mc_common_app/api/api_client.dart';
import 'package:mc_common_app/classes/app_state.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/dependencies.dart';
import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
abstract class PaymentsRepo {
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentId, required int adId});
}
class PaymentsRepoImp implements PaymentsRepo {
ApiClient apiClient = injector.get<ApiClient>();
AppState appState = injector.get<AppState>();
@override
Future<PayOrderDetailRespModel> getPayOrderDetails({required int paymentId, required int adId}) async {
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(token: appState.getUser.data!.accessToken, (json) => GenericRespModel.fromJson(json), ApiConsts.payForOrderDetailGet);
PayOrderDetailRespModel payOrderDetailRespModel = PayOrderDetailRespModel.fromJson(adsGenericModel.data);
return payOrderDetailRespModel;
}
}

@ -4,7 +4,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class CommonServices {
abstract class CommonAppServices {
Future<List<File>> pickMultipleImages();
Future<File?> pickImageFromPhone(int sourceFlag);
@ -12,7 +12,7 @@ abstract class CommonServices {
Future<File?> pickFile({FileType fileType = FileType.custom, List<String?>? allowedExtensions});
}
class CommonServicesImp implements CommonServices {
class CommonServicesImp implements CommonAppServices {
@override
Future<File?> pickImageFromPhone(int sourceFlag) async {
final picker = ImagePicker();

@ -0,0 +1,33 @@
import 'dart:developer';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class MyInAppBrowser extends InAppBrowser {
final Function onExitCallback;
final Function(String) onLoadStartCallback;
MyInAppBrowser({
required this.onExitCallback,
required this.onLoadStartCallback,
});
@override
Future onBrowserCreated() async {
log("\n\nBrowser Created!\n\n");
}
@override
Future onLoadStart(Uri? url) async {
onLoadStartCallback(url.toString());
}
@override
Future onLoadStop(Uri? url) async {
log("\n\nStopped $url\n\n");
}
@override
void onLoadError(Uri? url, int code, String message) {
log("Can't load $url.. Error: $message");
}
}

@ -0,0 +1,80 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/services/my_in_app_browser.dart';
import 'package:mc_common_app/utils/utils.dart';
abstract class PaymentService {
Future<void> placeAdPayment({
required int id,
required int paymentType,
required Function() onSuccess,
required Function() onFailure,
});
Future<void> onBrowserLoadStart({
required String url,
required Function() onSuccess,
required Function() onFailure,
});
}
class PaymentServiceImp implements PaymentService {
MyInAppBrowser? myInAppBrowser;
var inAppBrowserOptions = InAppBrowserClassOptions(
inAppWebViewGroupOptions:
InAppWebViewGroupOptions(crossPlatform: InAppWebViewOptions(useShouldOverrideUrlLoading: true, transparentBackground: false), ios: IOSInAppWebViewOptions(applePayAPIEnabled: true)),
crossPlatform: InAppBrowserOptions(hideUrlBar: true, toolbarTopBackgroundColor: Colors.black),
android: AndroidInAppBrowserOptions(),
ios:
IOSInAppBrowserOptions(hideToolbarBottom: true, toolbarBottomBackgroundColor: Colors.white, closeButtonColor: Colors.white, presentationStyle: IOSUIModalPresentationStyle.OVER_FULL_SCREEN));
String generateBrowserUrl(int id) {
String form = Utils.getAdsPaymentBrowserForm(paymentId: 3, adId: id);
// form.replaceFirst("SERVICE_URL_VALUE", ApiConsts.paymentWebViewUrl);
// form.replaceFirst("PaymentType_Value", 4.toString());
// form.replaceFirst("AdID_Value", id.toString());
var bytes = utf8.encode(form);
var base64Str = base64.encode(bytes);
return 'data:text/html;base64,$base64Str';
}
@override
Future<void> placeAdPayment({
required int id,
required int paymentType,
required Function() onSuccess,
required Function() onFailure,
}) async {
myInAppBrowser = MyInAppBrowser(onExitCallback: () {
log("Browser Exited");
}, onLoadStartCallback: (String url) {
log("Browser LoadStart");
onBrowserLoadStart(onFailure: onFailure, onSuccess: onSuccess, url: url);
});
await myInAppBrowser!.openUrlRequest(
urlRequest: URLRequest(url: Uri.parse("${ApiConsts.paymentWebViewUrl}?PaymentType=$paymentType&AdsID=$id")),
options: inAppBrowserOptions,
);
}
@override
Future<void> onBrowserLoadStart({
required String url,
required Function() onSuccess,
required Function() onFailure,
}) async {
for (var element in ApiConsts.closingUrls) {
if (url.contains(element)) {
if (myInAppBrowser!.isOpened()) myInAppBrowser!.close();
onSuccess();
return;
}
// onFailure();
}
}
}

@ -4,15 +4,18 @@ navigateWithName(BuildContext context, String routeName, {Object? arguments}) {
Navigator.pushNamed(context, routeName, arguments: arguments);
}
navigateReplaceWithName(BuildContext context, String routeName, {Object? arguments}) {
Navigator.pushReplacementNamed(context, routeName, arguments: arguments);
}
navigateReplaceWithNameUntilRoute(BuildContext context, String routeName, {Object? arguments}) {
Navigator.pushNamedAndRemoveUntil(context, routeName, (route) => false);
}
pop(BuildContext context) {
Navigator.of(context).pop();
}
navigateTo(context, page) {
Navigator.push(context, MaterialPageRoute(builder: (context) => page));
}
}

@ -8,6 +8,7 @@ import 'package:mc_common_app/utils/date_helper.dart';
import 'package:path/path.dart' as p;
import 'package:fluttertoast/fluttertoast.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/exceptions/api_exception.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -395,4 +396,17 @@ class Utils {
RegExp regExp = RegExp(p);
return regExp.hasMatch(email);
}
static String getAdsPaymentBrowserForm({required int paymentId, required int adId}) {
return '<html> ' +
'<head></head>' +
'<body>' +
'<form id="paymentForm" action="${ApiConsts.paymentWebViewUrl}" method="post">' +
'<input type="hidden" name="PaymentType" value="$paymentId">' +
'<input type="hidden" name="AdsID" value="$adId">' +
'</form>' +
'<script type="text/javascript"> document.getElementById("paymentForm").submit(); </script>' +
'</body>' +
'</html>';
}
}

@ -17,7 +17,7 @@ import 'package:mc_common_app/models/generic_resp_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/repositories/ads_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/services.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
@ -28,7 +28,7 @@ class AdVM extends BaseVM {
final CommonRepo commonRepo;
final AdsRepo adsRepo;
final CommonServices commonServices;
final CommonAppServices commonServices;
AdVM({required this.commonServices, required this.commonRepo, required this.adsRepo});

@ -0,0 +1,95 @@
import 'package:flutter/cupertino.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/models/payment_models/pay_order_detail_resp_model.dart';
import 'package:mc_common_app/repositories/payments_repo.dart';
import 'package:mc_common_app/services/payments_service.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
class PaymentVM extends ChangeNotifier {
final PaymentService paymentService;
final PaymentsRepo paymentRepo;
PaymentVM({required this.paymentService, required this.paymentRepo});
PaymentMethodsEnum selectedPaymentMethod = PaymentMethodsEnum.mada;
PaymentTypesEnum currentPaymentType = PaymentTypesEnum.ads;
int currentAdId = -1;
void updateCurrentAdId({required int id}) {
currentAdId = id;
}
updateSelectedPaymentMethod(PaymentMethodsEnum selectedMethod) {
selectedPaymentMethod = selectedMethod;
notifyListeners();
}
Future<void> onContinuePressed(BuildContext context) async {
switch (selectedPaymentMethod) {
case PaymentMethodsEnum.mada:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.visa:
await onVisaCardSelected(context);
break;
case PaymentMethodsEnum.applePay:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.masterCard:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.tamara:
// TODO: Handle this case.
break;
}
return;
}
Future<void> onVisaCardSelected(BuildContext context) async {
switch (currentPaymentType) {
case PaymentTypesEnum.subscription:
// TODO: Handle this case.
break;
case PaymentTypesEnum.appointment:
// TODO: Handle this case.
break;
case PaymentTypesEnum.ads:
if (currentAdId == -1) return;
int paymentType = 3;
await paymentService.placeAdPayment(
id: currentAdId,
paymentType: paymentType,
onFailure: () {
Utils.showToast("Payment Failed!");
},
onSuccess: () async {
Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentType, adId: 3);
await Future.delayed(Duration(seconds: 2));
Utils.hideLoading(context);
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Failed!");
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Successfully Completed!");
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
},
);
break;
case PaymentTypesEnum.adReserve:
// TODO: Handle this case.
break;
case PaymentTypesEnum.request:
// TODO: Handle this case.
break;
}
}
}

@ -7,10 +7,12 @@ import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/advertisement/ads_images_slider.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AdsDetailView extends StatelessWidget {
final AdDetailsModel adDetails;
@ -28,87 +30,90 @@ class AdsDetailView extends StatelessWidget {
),
body: Container(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: Stack(
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CarouselWithIndicatorDemo(vehicleImages: adDetails.vehicle!.image!),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${adDetails.vehicle!.vehicleTitle} | ${adDetails.vehicle!.color!.label}".toText(fontSize: 18, isBold: true),
(adDetails.vehicle!.cityName ?? "").toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
"Model: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.modelyear!.label}".toText(
fontSize: 14,
isBold: true,
),
],
),
"${adDetails.vehicle!.countryID}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
"Mileage: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.mileage!.mileageEnd}Km".toText(
fontSize: 14,
isBold: true,
),
],
),
adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) : SizedBox(),
],
),
Row(
children: [
"Transmission: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.transmission!.label}".toText(
fontSize: 14,
isBold: true,
),
],
),
8.height,
"Description: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.vehicleDescription}".toText(
fontSize: 14,
isBold: true,
),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
height: 150,
child: Column(
Expanded(
child: ListView(
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(thickness: 1, height: 1),
18.height,
CarouselWithIndicatorDemo(vehicleImages: adDetails.vehicle!.image!),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"${adDetails.vehicle!.vehicleTitle} | ${adDetails.vehicle!.color!.label}".toText(fontSize: 18, isBold: true),
(adDetails.vehicle!.cityName ?? "").toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
"Model: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.modelyear!.label}".toText(
fontSize: 14,
isBold: true,
),
],
),
"${adDetails.vehicle!.countryID}".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, isBold: true),
"SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
Row(
children: [
"Mileage: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.mileage!.mileageEnd}Km".toText(
fontSize: 14,
isBold: true,
),
],
),
adDetails.createdOn != null ? DateTime.parse(adDetails.createdOn!).getTimeAgo().toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor) : const SizedBox(),
],
),
14.height,
BuildAdDetailsActionButton(adPostStatus: adDetails.adPostStatus!),
Row(
children: [
"Transmission: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.transmission!.label}".toText(
fontSize: 14,
isBold: true,
),
],
),
8.height,
"Description: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
"${adDetails.vehicle!.vehicleDescription}".toText(
fontSize: 14,
isBold: true,
),
],
).toWhiteContainer(width: double.infinity, allPading: 12),
],
),
),
SizedBox(
child: Column(
children: [
const Divider(thickness: 1, height: 1),
18.height,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, isBold: true),
"SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
],
),
)),
14.height,
BuildAdDetailsActionButton(adPostStatus: adDetails.adPostStatus!, adId: adDetails.id!),
],
),
)
],
),
),
@ -118,18 +123,20 @@ class AdsDetailView extends StatelessWidget {
class BuildAdDetailsActionButton extends StatelessWidget {
final AdPostStatus adPostStatus;
final int adId;
const BuildAdDetailsActionButton({Key? key, required this.adPostStatus}) : super(key: key);
const BuildAdDetailsActionButton({Key? key, required this.adPostStatus, required this.adId}) : super(key: key);
Widget pendingForPaymentAction(BuildContext context) {
Widget pendingForPaymentAction(BuildContext context, {required int adID}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Reserve Ad",
title: "Pay Now",
onPressed: () {
navigateWithName(context, AppRoutes.paymentMethodsView);
},
@ -138,14 +145,13 @@ class BuildAdDetailsActionButton extends StatelessWidget {
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Reserve Ad",
onPressed: () {
navigateWithName(context, AppRoutes.paymentMethodsView);
},
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: "Delete Ad".toText(fontSize: 15, isBold: true, color: MyColors.redColor),
),
),
],
@ -155,15 +161,32 @@ class BuildAdDetailsActionButton extends StatelessWidget {
}
Widget markAsSoldAction(BuildContext context) {
return Row(
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Mark As Sold",
onPressed: () {},
),
Row(
children: [
Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Mark As Sold",
onPressed: () {},
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: "Delete Ad".toText(fontSize: 15, isBold: true, color: MyColors.redColor),
),
),
],
)
],
);
}
@ -173,6 +196,10 @@ class BuildAdDetailsActionButton extends StatelessWidget {
children: [
Expanded(
child: ShowFillButton(
borderColor: MyColors.redColor,
txtColor: MyColors.redColor,
isFilled: false,
fontSize: 16,
maxHeight: 55,
title: "Cancel Reservation",
onPressed: () {},
@ -208,9 +235,10 @@ class BuildAdDetailsActionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
context.read<PaymentVM>().updateCurrentAdId(id: adId);
switch (adPostStatus) {
case AdPostStatus.pendingForPayment:
return pendingForPaymentAction(context);
return pendingForPaymentAction(context, adID: adId);
case AdPostStatus.active:
return markAsSoldAction(context);
case AdPostStatus.reserved:
@ -222,6 +250,7 @@ class BuildAdDetailsActionButton extends StatelessWidget {
case AdPostStatus.cancelled:
case AdPostStatus.pendingForPost:
case AdPostStatus.pendingForReview:
return pendingForPaymentAction(context, adID: adId);
case AdPostStatus.sold:
case AdPostStatus.expired:
break;

@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:provider/provider.dart';
class PaymentMethodsView extends StatelessWidget {
const PaymentMethodsView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Payment Method",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
),
body: Container(
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
20.height,
"Select Payment Method".toText(fontSize: 18, isBold: true),
15.height,
Consumer(
builder: (BuildContext context, PaymentVM paymentVm, Widget? child) {
return Expanded(
child: ListView(
shrinkWrap: true,
children: [
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.mada,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.mada),
cardAsset: MyAssets.madaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.visa,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.visa),
cardAsset: MyAssets.visaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.applePay,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.applePay),
cardAsset: MyAssets.applePayPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.masterCard,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.masterCard),
cardAsset: MyAssets.mastercardPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.tamara,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.tamara),
cardAsset: MyAssets.tamaraEngPng),
],
),
);
},
),
SizedBox(
width: double.infinity,
child: ShowFillButton(
maxHeight: 55,
title: "Continue",
onPressed: () {
context.read<PaymentVM>().onContinuePressed(context);
},
backgroundColor: MyColors.darkPrimaryColor,
),
),
],
),
),
);
}
}
class PaymentMethodContainer extends StatelessWidget {
final bool isSelected;
final String cardAsset;
final Function() onTap;
const PaymentMethodContainer({Key? key, required this.isSelected, required this.cardAsset, required this.onTap}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: double.infinity,
height: 80,
decoration: BoxDecoration(
color: MyColors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isSelected ? Colors.green : Colors.transparent, width: isSelected ? 2.0 : 0.0),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
Container(
width: 24,
height: 24,
decoration: Utils.containerColorRadiusBorderWidth(isSelected ? MyColors.primaryColor : Colors.transparent, 100, Colors.grey, 0.5),
),
12.width,
Container(
height: 80.0,
width: 80.0,
padding: EdgeInsets.all(7.0),
child: Image.asset(cardAsset),
),
Utils.mFlex(1),
isSelected ? Utils.statusContainerChip(text: "Selected", padding: EdgeInsets.symmetric(vertical: 6, horizontal: 10)) : SizedBox(),
],
),
),
),
);
}
}

@ -11,6 +11,7 @@ class ShowFillButton extends StatelessWidget {
bool isFlatButton, isBold;
EdgeInsets? margin;
bool isFilled;
Color borderColor;
ShowFillButton({
super.key,
@ -30,6 +31,7 @@ class ShowFillButton extends StatelessWidget {
this.horizontalMargin = 0,
this.verticalMargin = 0,
this.margin,
this.borderColor = MyColors.primaryColor,
});
@override
@ -67,7 +69,7 @@ class ShowFillButton extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(radius),
side: isFilled ? BorderSide.none: const BorderSide(width: 3, color: MyColors.darkPrimaryColor),
side: isFilled ? BorderSide.none: BorderSide(width: 2, color: borderColor),
),
child: title.toText(
fontSize: fontSize,

Loading…
Cancel
Save