Ads and Appointment Module Progress

models_removal
Faiz Hashmi 1 year ago
parent b766157d7f
commit d412383aad

@ -81,8 +81,7 @@ class ApiClientImp implements ApiClient {
var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: headers0, retryTimes: retryTimes);
try {
if (!kReleaseMode) {
log("res121:${response.body}");
log("res121:${response.statusCode}");
log("statusCode:${response.statusCode}");
}
var jsonData = jsonDecode(response.body);
return factoryConstructor(jsonData);

@ -51,6 +51,7 @@ class ApiConsts {
static String BranchesAndServices = "${baseUrlServices}api/ServiceProviders/ServiceProviderDetail_Get";
static String GetAllNearBranches = "${baseUrlServices}api/ServiceProviders/ServiceProviderBranchDetail_Get";
static String GetServiceItemAppointmentScheduleSlots = "${baseUrlServices}api/ServiceProviders/ServiceItemAppointmentScheduleSlots_Get";
static String ServiceProvidersAppointmentCreate = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Create";
//Appointment APIs
static String serviceProvidersAppointmentGet = "${baseUrlServices}api/ServiceProviders/ServiceProvidersAppointment_Get";
@ -94,6 +95,9 @@ class ApiConsts {
static String vehicleAdsSingleStepCreate = "${baseUrlServices}api/Advertisement/AdsSingleStep_Create";
static String vehicleAdsGet = "${baseUrlServices}api/Advertisement/Ads_Get";
static String myAdsReserveGet = "${baseUrlServices}api/Advertisement/AdsReserve_Get";
static String reserveAdsBankDetailsGet = "${baseUrlServices}api/Advertisement/MCBankAccountAd_Get";
static String adsUpdateStatus = "${baseUrlServices}api/Advertisement/Ads_UpdateStatus";
static String deleteAd = "${baseUrlServices}api/Advertisement/Ads_Delete";
static String adsCarCheckupSPBranchScheduleSlotGet = "${baseUrlServices}api/Advertisement/AdsCarCheckupSPBranchScheduleSlot_Get";
static String adsPhotoOfficeAppointmentScheduleSlotGet = "${baseUrlServices}api/Advertisement/PhotoOfficeAppointmentScheduleSlot_Get";

@ -176,6 +176,8 @@ extension AdPostEnum on int {
return AdPostStatus.buyingService;
} else if (this == 11) {
return AdPostStatus.reserveCancel;
} else if (this == -1) {
return AdPostStatus.allAds;
} else {
return AdPostStatus.pendingForPost;
}
@ -338,17 +340,31 @@ extension DateTimeConversions on DateTime {
}
extension VehicleAdTypeEnum on int {
VehicleTypeEnum getVehicleTypeEnum() {
VehicleType toVehicleTypeEnum() {
if (this == 1) {
return VehicleTypeEnum.car;
return VehicleType.car;
} else if (this == 2) {
return VehicleTypeEnum.motorCycle;
return VehicleType.motorCycle;
} else if (this == 3) {
return VehicleTypeEnum.golfCart;
return VehicleType.golfCart;
} else if (this == 4) {
return VehicleTypeEnum.buggy;
return VehicleType.buggy;
} else {
return VehicleTypeEnum.car;
return VehicleType.car;
}
}
String toVehicleTypeString() {
if (this == 1) {
return "Car";
} else if (this == 2) {
return "Motorcycle";
} else if (this == 3) {
return "Golf Cart";
} else if (this == 4) {
return "Buggy";
} else {
return "Car";
}
}
}

@ -40,6 +40,7 @@ class AdDetailsModel {
AdPostStatus? adPostStatus;
AdReserveStatus? adReserveStatus;
bool? isMyAd;
bool? isReservedByMe;
String? phoneNo;
String? whatsAppNo;
CreatedByRoleEnum? createdByRoleEnum;
@ -78,6 +79,7 @@ class AdDetailsModel {
this.adPostStatus,
this.adReserveStatus,
this.isMyAd,
this.isReservedByMe,
this.phoneNo,
this.whatsAppNo,
this.createdByRoleEnum,
@ -127,12 +129,14 @@ class AdDetailsModel {
modifiedOn = json['modifiedOn'];
whatsAppNo = json['phoneNo'];
modifiedOn = json['whatsAppNo'];
// adPostStatus = AdPostStatus.expired;
adPostStatus = (json['statusID'] as int).toAdPostEnum();
//TODO: THIS ID SHOULD BE UPDATED!
adReserveStatus = AdReserveStatus.defaultStatus;
createdByRoleEnum = CreatedByRoleEnum.admin;
// createdByRoleEnum = (json['createdByRole'] as int).toCreatedByRoleEnum();
// createdByRoleEnum = CreatedByRoleEnum.admin;
createdByRoleEnum = (json['createdByRole'] as int).toCreatedByRoleEnum();
isMyAd = isMyAds;
isReservedByMe = false;
}
Map<String, dynamic> toJson() {

@ -59,14 +59,14 @@ class VehicleTypeModel {
String? vehicleTypeName;
String? vehicleTypeNameN;
bool? isActive;
VehicleTypeEnum? vehicleTypeEnum;
VehicleType? vehicleTypeEnum;
VehicleTypeModel({
this.id,
this.vehicleTypeName,
this.vehicleTypeNameN,
this.isActive,
this.vehicleTypeEnum = VehicleTypeEnum.car,
this.vehicleTypeEnum = VehicleType.car,
});
VehicleTypeModel.fromJson(Map<String, dynamic> json) {
@ -74,7 +74,7 @@ class VehicleTypeModel {
vehicleTypeName = json['vehicleTypeName'];
vehicleTypeNameN = json['vehicleTypeNameN'];
isActive = json['isActive'];
vehicleTypeEnum = (json['id'] as int).getVehicleTypeEnum();
vehicleTypeEnum = (json['id'] as int).toVehicleTypeEnum();
}
Map<String, dynamic> toJson() {

@ -3,22 +3,26 @@ class GenericRespModel {
this.data,
this.messageStatus,
this.totalItemsCount,
this.message,
});
dynamic data;
int? messageStatus;
int? totalItemsCount;
String? message;
factory GenericRespModel.fromJson(Map<String, dynamic> json) => GenericRespModel(
data: json["data"],
messageStatus: json["messageStatus"],
totalItemsCount: json["totalItemsCount"],
message: json["message"],
);
Map<String, dynamic> toJson() => {
"data": data,
"messageStatus": messageStatus,
"totalItemsCount": totalItemsCount,
"message": message,
};
}

@ -2,13 +2,23 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/services/item_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
class CustomTimeDateSlotModel {
TimeSlotModel? date;
List<TimeSlotModel>? availableSlots;
CustomTimeDateSlotModel({this.date, this.availableSlots});
}
class ServiceAppointmentScheduleModel {
List<ServiceSlotList>? serviceSlotList;
List<ItemData>? serviceItemList;
String? selectedDate;
String? selectedTimeSlot;
List<TimeSlotModel>? availableDates;
List<TimeSlotModel>? availableTimeSlots;
int? selectedDateIndex;
// String? selectedTimeSlot;
// List<TimeSlotModel>? availableDates;
// List<TimeSlotModel>? availableTimeSlots;
List<CustomTimeDateSlotModel>? customTimeDateSlotList;
CustomTimeDateSlotModel? selectedCustomTimeDateSlotModel;
double? amountToPay;
double? amountTotal;
double? amountRem;
@ -16,15 +26,41 @@ class ServiceAppointmentScheduleModel {
ServiceAppointmentScheduleModel({
this.serviceSlotList,
this.serviceItemList,
this.selectedDate,
this.selectedTimeSlot,
this.availableDates,
this.availableTimeSlots,
this.selectedDateIndex,
// this.selectedTimeSlot,
// this.availableDates,
// this.availableTimeSlots,
this.customTimeDateSlotList,
this.selectedCustomTimeDateSlotModel,
this.amountToPay,
this.amountTotal,
this.amountRem,
});
List<CustomTimeDateSlotModel> getFormattedDateTimeSlotPackage() {
List<CustomTimeDateSlotModel> customTimeDateSlotList = [];
for (var element in serviceSlotList!) {
if (!isAlreadyThere(element.slotDate!, customTimeDateSlotList)) {
customTimeDateSlotList.add(CustomTimeDateSlotModel(
date: TimeSlotModel(slotId: element.id!, isSelected: false, date: element.slotDate!, allowAppointment: true),
availableSlots: getAvailableSlotsByDate(element.slotDate!),
));
}
}
return customTimeDateSlotList;
}
List<TimeSlotModel>? getAvailableSlotsByDate(String date) {
List<TimeSlotModel> timeslots = [];
for (var element in serviceSlotList!) {
if (element.slotDate == date) {
timeslots.add(TimeSlotModel(slotId: element.id!, slot: element.startTime!, date: element.slotDate!, isSelected: false, allowAppointment: element.bookAppointment! < element.allowAppointment!));
}
}
return timeslots;
}
List<TimeSlotModel> getFormattedSlotTimes() {
var seenSlots = <TimeSlotModel>{};
@ -33,31 +69,30 @@ class ServiceAppointmentScheduleModel {
slot: slot.startTime!,
slotId: slot.id!,
isSelected: false,
date: slot.slotDate!.toFormattedDateWithoutTime(),
)))
.toList();
List<TimeSlotModel> slotTime = [];
for (var element in slotTimeData) {
slotTime.add(TimeSlotModel(isSelected: false, slotId: element.id!, slot: element.slotDate ?? ""));
slotTime.add(TimeSlotModel(isSelected: false, slotId: element.id!, slot: element.startTime ?? "", date: element.slotDate!.toFormattedDateWithoutTime() ?? ""));
}
return slotTime;
}
List<TimeSlotModel> getFormattedSlotDates() {
var seenDates = <TimeSlotModel>{};
var slotDatesData = serviceSlotList!
.where((slot) => seenDates.add(TimeSlotModel(
slot: slot.slotDate!,
slotId: slot.id!,
isSelected: false,
)))
.toList();
List<TimeSlotModel> slotDates = [];
for (var element in slotDatesData) {
slotDates.add(TimeSlotModel(isSelected: false, slotId: element.id!, slot: element.slotDate!.toFormattedDateWithoutTime() ?? ""));
bool isAlreadyThere(String dateToFind, List<CustomTimeDateSlotModel> slots) {
int index = slots.indexWhere((element) {
return element.date!.date == dateToFind;
});
if (index == -1) {
return false;
} else {
return true;
}
}
List<TimeSlotModel> getFormattedSlotDates() {
List<TimeSlotModel> slotDates = [];
return slotDates;
}
@ -77,12 +112,9 @@ class ServiceAppointmentScheduleModel {
serviceItemList!.add(ItemData.fromJson(v));
});
}
customTimeDateSlotList = getFormattedDateTimeSlotPackage();
amountToPay = json['amountToPay'];
selectedDate = '';
selectedTimeSlot = '';
availableDates = getFormattedSlotDates();
availableTimeSlots = getFormattedSlotTimes();
selectedDateIndex = null;
amountTotal = json['amountTotal'];
amountRem = json['amountRem'];
}
@ -143,7 +175,7 @@ class ServiceSlotList {
branchAppointmentScheduleID = json['branchAppointmentScheduleID'];
branchAppointmentSchedule = json['branchAppointmentSchedule'];
serviceProviderID = json['serviceProviderID'];
slotDate = json['slotDate'];
slotDate = (json['slotDate'] as String).toFormattedDateWithoutTime();
startTime = json['startTime'];
endTime = json['endTime'];
bookAppointment = json['bookAppointment'];
@ -177,4 +209,9 @@ class ServiceSlotList {
data['modifiedOn'] = modifiedOn;
return data;
}
@override
String toString() {
return 'ServiceSlotList{id: $id, branchAppointmentScheduleID: $branchAppointmentScheduleID, branchAppointmentSchedule: $branchAppointmentSchedule, serviceProviderID: $serviceProviderID, slotDate: $slotDate, startTime: $startTime, endTime: $endTime, bookAppointment: $bookAppointment, allowAppointment: $allowAppointment, slotDurationMinute: $slotDurationMinute, appointmentType: $appointmentType, isActive: $isActive, createdBy: $createdBy, createdOn: $createdOn, modifiedBy: $modifiedBy, modifiedOn: $modifiedOn}';
}
}

@ -45,6 +45,7 @@ class ItemData {
final dynamic pictureUrl;
final int? companyId;
final int? serviceProviderServiceId;
final String? serviceProviderServiceDescription;
final bool? isActive;
final bool? isAllowAppointment;
final bool? isAppointmentCompanyLoc;
@ -61,6 +62,7 @@ class ItemData {
this.pictureUrl,
this.companyId,
this.serviceProviderServiceId,
this.serviceProviderServiceDescription,
this.isActive,
this.isAllowAppointment,
this.isAppointmentCompanyLoc,
@ -78,6 +80,7 @@ class ItemData {
pictureUrl: json["pictureUrl"],
companyId: json["companyID"],
serviceProviderServiceId: json["serviceProviderServiceID"],
serviceProviderServiceDescription: json["serviceProviderServiceDescription"],
isActive: json["isActive"],
isAllowAppointment: json["isAllowAppointment"],
isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"],

@ -6,7 +6,6 @@ class FilterListModel {
FilterListModel({required this.id, required this.isSelected, required this.title});
}
class SelectionModel {
String selectedOption;
int selectedId;
@ -24,11 +23,20 @@ class SelectionModel {
class TimeSlotModel {
int slotId;
bool isSelected;
bool allowAppointment;
String slot;
String date;
TimeSlotModel({
this.slot = "",
this.slotId = 0,
this.date = "",
this.isSelected = false,
this.allowAppointment = false,
});
}
@override
String toString() {
return 'TimeSlotModel{slotId: $slotId, isSelected: $isSelected, slot: $slot, date: $date}';
}
}

@ -1,302 +0,0 @@
import 'package:collection/collection.dart' show IterableExtension;
import 'package:country_code_picker/country_code_picker.dart';
import 'package:flutter/material.dart';
class CustomCountryCodePicker extends StatefulWidget {
final bool isTextNeeded;
final ValueChanged<CountryCode>? onChanged;
final ValueChanged<CountryCode?>? onInit;
final String? initialSelection;
final List<String> favorite;
final TextStyle? textStyle;
final EdgeInsetsGeometry padding;
final bool showCountryOnly;
final InputDecoration searchDecoration;
final TextStyle? searchStyle;
final TextStyle? dialogTextStyle;
final WidgetBuilder? emptySearchBuilder;
final Function(CountryCode?)? builder;
final bool enabled;
final TextOverflow textOverflow;
final Icon closeIcon;
/// Barrier color of ModalBottomSheet
final Color? barrierColor;
/// Background color of ModalBottomSheet
final Color? backgroundColor;
/// BoxDecoration for dialog
final BoxDecoration? boxDecoration;
/// the size of the selection dialog
final Size? dialogSize;
/// Background color of selection dialog
final Color? dialogBackgroundColor;
/// used to customize the country list
final List<String>? countryFilter;
/// shows the name of the country instead of the dialcode
final bool showOnlyCountryWhenClosed;
/// aligns the flag and the Text left
///
/// additionally this option also fills the available space of the widget.
/// this is especially useful in combination with [showOnlyCountryWhenClosed],
/// because longer country names are displayed in one line
final bool alignLeft;
/// shows the flag
final bool showFlag;
final bool hideMainText;
final bool? showFlagMain;
final bool? showFlagDialog;
/// Width of the flag images
final double flagWidth;
/// Use this property to change the order of the options
final Comparator<CountryCode>? comparator;
/// Set to true if you want to hide the search part
final bool hideSearch;
/// Set to true if you want to show drop down button
final bool showDropDownButton;
/// [BoxDecoration] for the flag image
final Decoration? flagDecoration;
/// An optional argument for injecting a list of countries
/// with customized codes.
final List<Map<String, String>> countryList;
const CustomCountryCodePicker({
this.isTextNeeded = true,
this.onChanged,
this.onInit,
this.initialSelection,
this.favorite = const [],
this.textStyle,
this.padding = const EdgeInsets.all(8.0),
this.showCountryOnly = false,
this.searchDecoration = const InputDecoration(),
this.searchStyle,
this.dialogTextStyle,
this.emptySearchBuilder,
this.showOnlyCountryWhenClosed = false,
this.alignLeft = false,
this.showFlag = true,
this.showFlagDialog,
this.hideMainText = false,
this.showFlagMain,
this.flagDecoration,
this.builder,
this.flagWidth = 32.0,
this.enabled = true,
this.textOverflow = TextOverflow.ellipsis,
this.barrierColor,
this.backgroundColor,
this.boxDecoration,
this.comparator,
this.countryFilter,
this.hideSearch = false,
this.showDropDownButton = false,
this.dialogSize,
this.dialogBackgroundColor,
this.closeIcon = const Icon(Icons.close),
this.countryList = codes,
Key? key,
}) : super(key: key);
@override
// ignore: no_logic_in_create_state
State<StatefulWidget> createState() {
List<Map<String, String>> jsonList = countryList;
List<CountryCode> elements = jsonList.map((json) => CountryCode.fromJson(json)).toList();
if (comparator != null) {
elements.sort(comparator);
}
if (countryFilter != null && countryFilter!.isNotEmpty) {
final uppercaseCustomList = countryFilter!.map((criteria) => criteria.toUpperCase()).toList();
elements = elements.where((criteria) => uppercaseCustomList.contains(criteria.code) || uppercaseCustomList.contains(criteria.name) || uppercaseCustomList.contains(criteria.dialCode)).toList();
}
return CustomCountryCodePickerState(elements);
}
}
class CustomCountryCodePickerState extends State<CustomCountryCodePicker> {
CountryCode? selectedItem;
List<CountryCode> elements = [];
List<CountryCode> favoriteElements = [];
CustomCountryCodePickerState(this.elements);
@override
Widget build(BuildContext context) {
Widget internalWidget;
if (widget.builder != null) {
internalWidget = InkWell(
onTap: showCountryCodePickerDialog,
child: widget.builder!(selectedItem),
);
} else {
internalWidget = TextButton(
onPressed: widget.enabled ? showCountryCodePickerDialog : null,
child: Padding(
padding: widget.padding,
child: Flex(
direction: Axis.horizontal,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (widget.showFlagMain != null ? widget.showFlagMain! : widget.showFlag)
Flexible(
flex: widget.alignLeft ? 0 : 1,
fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose,
child: Container(
clipBehavior: widget.flagDecoration == null ? Clip.none : Clip.hardEdge,
decoration: widget.flagDecoration,
margin: widget.alignLeft ? const EdgeInsets.only(right: 16.0, left: 8.0) : const EdgeInsets.only(right: 16.0),
child: Image.asset(
selectedItem!.flagUri!,
package: 'country_code_picker',
width: widget.flagWidth,
),
),
),
if (!widget.hideMainText)
Flexible(
fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose,
child: Text(
widget.showOnlyCountryWhenClosed ? selectedItem!.toCountryStringOnly() : selectedItem.toString(),
style: widget.textStyle ?? Theme.of(context).textTheme.labelLarge,
overflow: widget.textOverflow,
),
),
if (widget.showDropDownButton)
Flexible(
flex: widget.alignLeft ? 0 : 1,
fit: widget.alignLeft ? FlexFit.tight : FlexFit.loose,
child: Padding(
padding: widget.alignLeft ? const EdgeInsets.only(right: 16.0, left: 8.0) : const EdgeInsets.only(right: 16.0),
child: Icon(
Icons.arrow_drop_down,
color: Colors.grey,
size: widget.flagWidth,
)),
),
],
),
),
);
}
return internalWidget;
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
elements = elements.map((element) => element.localize(context)).toList();
_onInit(selectedItem);
}
@override
void didUpdateWidget(CustomCountryCodePicker oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initialSelection != widget.initialSelection) {
if (widget.initialSelection != null) {
selectedItem = elements.firstWhere(
(criteria) =>
(criteria.code!.toUpperCase() == widget.initialSelection!.toUpperCase()) ||
(criteria.dialCode == widget.initialSelection) ||
(criteria.name!.toUpperCase() == widget.initialSelection!.toUpperCase()),
orElse: () => elements[0]);
} else {
selectedItem = elements[0];
}
_onInit(selectedItem);
}
}
@override
void initState() {
super.initState();
if (widget.initialSelection != null) {
selectedItem = elements.firstWhere(
(item) =>
(item.code!.toUpperCase() == widget.initialSelection!.toUpperCase()) ||
(item.dialCode == widget.initialSelection) ||
(item.name!.toUpperCase() == widget.initialSelection!.toUpperCase()),
orElse: () => elements[0]);
} else {
selectedItem = elements[0];
}
favoriteElements = elements
.where((item) =>
widget.favorite.firstWhereOrNull((criteria) => item.code!.toUpperCase() == criteria.toUpperCase() || item.dialCode == criteria || item.name!.toUpperCase() == criteria.toUpperCase()) !=
null)
.toList();
}
void showCountryCodePickerDialog() async {
final item = await showDialog(
barrierColor: widget.barrierColor ?? Colors.grey.withOpacity(0.5),
context: context,
builder: (context) => Center(
child: Dialog(
child: SelectionDialog(
elements,
favoriteElements,
showCountryOnly: widget.showCountryOnly,
emptySearchBuilder: widget.emptySearchBuilder,
searchDecoration: widget.searchDecoration,
searchStyle: widget.searchStyle,
textStyle: widget.dialogTextStyle,
boxDecoration: widget.boxDecoration,
showFlag: widget.showFlagDialog ?? widget.showFlag,
flagWidth: widget.flagWidth,
size: widget.dialogSize,
backgroundColor: widget.dialogBackgroundColor,
barrierColor: widget.barrierColor,
hideSearch: widget.hideSearch,
closeIcon: widget.closeIcon,
flagDecoration: widget.flagDecoration,
),
),
),
);
if (item != null) {
setState(() {
selectedItem = item;
});
_publishSelection(item);
}
}
void _publishSelection(CountryCode countryCode) {
if (widget.onChanged != null) {
widget.onChanged!(countryCode);
}
}
void _onInit(CountryCode? countryCode) {
if (widget.onInit != null) {
widget.onInit!(countryCode);
}
}
}

@ -53,6 +53,10 @@ abstract class AdsRepo {
Future<List<MyReservedAdsRespModel>> getMyReservedAds();
Future<List<AdDetailsModel>> getMyAds();
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate});
Future<GenericRespModel> deleteAd({required int adId});
}
class AdsRepoImp implements AdsRepo {
@ -374,4 +378,40 @@ class AdsRepoImp implements AdsRepo {
List<AdDetailsModel> vehicleAdsDetails = List.generate(adsGenericModel.data.length, (index) => AdDetailsModel.fromJson(adsGenericModel.data[index], true));
return vehicleAdsDetails;
}
@override
Future<GenericRespModel> updateAdStatus({required int adId, required AdPostStatus adStatusToUpdate}) async {
var postParams = {
"id": adId,
"status": adStatusToUpdate.getIdFromAdPostStatusEnum().toString(),
"comment": "",
};
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.adsUpdateStatus,
postParams,
token: token,
);
return Future.value(adsGenericModel);
}
@override
Future<GenericRespModel> deleteAd({required int adId}) async {
var postParams = {
"adID": adId,
};
String token = appState.getUser.data!.accessToken ?? "";
GenericRespModel adsGenericModel = await apiClient.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConsts.deleteAd,
postParams,
token: token,
);
return Future.value(adsGenericModel);
}
}

@ -1,7 +1,7 @@
import 'package:permission_handler/permission_handler.dart';
import 'dialogs.dart';
import 'dialogs_and_bottomsheets.dart';
enum ConfirmAction { CANCEL, ACCEPT }

@ -1,36 +0,0 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/utils/AppPermissionHandler.dart';
Future<ConfirmAction?> showConfirmDialogs(
context, msg, positiveText, negativeText) async {
return showDialog<ConfirmAction>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
backgroundColor: Colors.white,
title: Text(msg, style: TextStyle(fontSize: 16)),
actions: <Widget>[
TextButton(
child: Text(
negativeText,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
},
),
TextButton(
child: Text(
positiveText,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.ACCEPT);
},
)
],
);
},
);
}

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/utils/AppPermissionHandler.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
Future<ConfirmAction?> showConfirmDialogs(context, msg, positiveText, negativeText) async {
return showDialog<ConfirmAction>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
backgroundColor: Colors.white,
title: Text(msg, style: TextStyle(fontSize: 16)),
actions: <Widget>[
TextButton(
child: Text(
negativeText,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.CANCEL);
},
),
TextButton(
child: Text(
positiveText,
),
onPressed: () {
Navigator.of(context).pop(ConfirmAction.ACCEPT);
},
)
],
);
},
);
}
void actionConfirmationBottomSheet({required BuildContext context, required Widget title, required subtitle, required Widget actionButtonYes, required Widget actionButtonNo}) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: title,
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"$subtitle".toText(fontSize: 16),
25.height,
Row(
children: [
actionButtonYes,
20.width,
actionButtonNo,
],
),
19.height,
],
));
},
);
}

@ -5,7 +5,7 @@
// unverified,
// }
enum VehicleTypeEnum {
enum VehicleType {
car,
motorCycle,
golfCart,
@ -33,9 +33,10 @@ enum AdPostStatus {
reserved,
buyingService,
reserveCancel,
allAds,
}
enum PaymentMethodsEnum {
enum PaymentMethods {
mada,
visa,
applePay,
@ -43,15 +44,16 @@ enum PaymentMethodsEnum {
tamara,
}
enum PaymentTypesEnum {
enum PaymentTypes {
subscription,
appointment,
ads,
adReserve,
request,
extendAds,
}
enum AdCreationStepsEnum {
enum AdCreationSteps {
vehicleDetails,
damageParts,
adDuration,

@ -2,7 +2,6 @@ import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mc_common_app/utils/date_helper.dart';
import 'package:path/path.dart' as p;
@ -14,7 +13,8 @@ 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/widgets/loading_dialog.dart';
import 'package:path/path.dart' as p;
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
class Utils {
static bool _isLoadingVisible = false;
@ -26,6 +26,24 @@ class Utils {
msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 2, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
}
static Future<void> openNumberViaCaller({required String phoneNumber}) async {
Uri phoneLaunchUrl = Uri.parse('tel:$phoneNumber');
if (await canLaunchUrl(phoneLaunchUrl)) {
try {
await launchUrl(phoneLaunchUrl);
} catch (e) {
await launchUrl(phoneLaunchUrl);
}
}
}
static Future<void> openNumberViaWhatsApp({required String phoneNumber}) async {
final url = 'https://wa.me/$phoneNumber?text=';
await launchUrlString(url, mode: LaunchMode.externalApplication);
}
static Future<String> pickDateFromDatePicker(BuildContext context, {DateTime? firstDate, DateTime? lastDate}) async {
DateTime? pickedDate = await showDatePicker(
context: context,
@ -110,7 +128,7 @@ class Utils {
hexColor = hexColor.toUpperCase().replaceAll('#', '');
if (hexColor.length == 6) {
hexColor = 'FF' + hexColor;
hexColor = 'FF$hexColor';
}
return Color(int.parse(hexColor, radix: 16));
@ -200,6 +218,7 @@ class Utils {
case AdPostStatus.buyingService:
case AdPostStatus.reserveCancel:
case AdPostStatus.allAds:
return MyColors.greenColor;
}
}

@ -33,7 +33,7 @@ class AdVM extends BaseVM {
AdVM({required this.commonServices, required this.commonRepo, required this.adsRepo});
AdCreationStepsEnum currentProgressStep = AdCreationStepsEnum.vehicleDetails;
AdCreationSteps currentProgressStep = AdCreationSteps.vehicleDetails;
VehicleDetailsModel? vehicleDetails;
@ -142,7 +142,7 @@ class AdVM extends BaseVM {
isExploreAdsTapped = value;
//To show the Active Ads
applyFilterOnMyAds(index: 0, adPostStatusEnum: AdPostStatus.active);
applyFilterOnMyAds(index: 0, adPostStatusEnum: AdPostStatus.allAds);
applyFilterOnExploreAds(index: 0, createdByRoleFilter: CreatedByRoleEnum.allAds);
// if (value) {
// await getExploreAds();
@ -163,11 +163,14 @@ class AdVM extends BaseVM {
];
myAdsFilterOptions = [
// FilterListModel(title: "All Ads", isSelected: true, id: -1),
FilterListModel(title: "All Ads", isSelected: true, id: -1),
FilterListModel(title: "Active", isSelected: false, id: 6),
FilterListModel(title: "Pending For Review", isSelected: false, id: 1),
FilterListModel(title: "Pending For Payment", isSelected: false, id: 2),
FilterListModel(title: "Sold", isSelected: false, id: 8),
FilterListModel(title: "Deactivated", isSelected: false, id: 4),
FilterListModel(title: "Reserved", isSelected: false, id: 9),
FilterListModel(title: "Expired", isSelected: false, id: 7),
FilterListModel(title: "Rejected", isSelected: false, id: 3),
FilterListModel(title: "Pending For Post", isSelected: false, id: 5),
];
@ -210,6 +213,9 @@ class AdVM extends BaseVM {
if (index == 3 && adPostStatusEnum.getIdFromAdPostStatusEnum() == 9) {
selectedIds = myReservedAdsRespModel.map((component) => component.adsID).toList();
myAdsFilteredList = myAds.where((element) => selectedIds.contains(element.id)).toList();
for (var ad in myAdsFilteredList) {
ad.isReservedByMe = true;
}
notifyListeners();
return;
}
@ -259,6 +265,54 @@ class AdVM extends BaseVM {
notifyListeners();
}
Future<void> markAdAsSold(BuildContext context, {required int adId}) async {
Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.sold);
if (respModel.messageStatus != 1) {
Utils.hideLoading(context);
Utils.showToast(respModel.message ?? "Something went wrong!");
return;
}
Utils.hideLoading(context);
Utils.showToast("A has been marked as sold successfully!");
updateIsExploreAds(false);
applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.sold); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
}
Future<void> deleteMyAd(BuildContext context, {required int adId}) async {
Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.deleteAd(adId: adId);
if (respModel.messageStatus != 1) {
Utils.hideLoading(context);
Utils.showToast(respModel.message ?? "Something went wrong!");
return;
}
Utils.hideLoading(context);
Utils.showToast("A has been deleted successfully!");
updateIsExploreAds(false);
applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.active); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
}
Future<void> deactivateTheAd(BuildContext context, {required int adId}) async {
Utils.showLoading(context);
GenericRespModel respModel = await adsRepo.updateAdStatus(adId: adId, adStatusToUpdate: AdPostStatus.cancelled);
if (respModel.messageStatus != 1) {
Utils.hideLoading(context);
Utils.showToast(respModel.message ?? "Something went wrong!");
return;
}
Utils.hideLoading(context);
Utils.showToast("A has been deactivated successfully!");
updateIsExploreAds(false);
applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.cancelled); //pending for review
navigateReplaceWithName(context, AppRoutes.dashboard);
}
bool isFetchingLists = false;
bool isCountryFetching = false;
@ -281,7 +335,7 @@ class AdVM extends BaseVM {
// }
getVehicleBrandsByVehicleTypeId() async {
if (vehicleTypeId.selectedId == -1) {
if (vehicleTypeId.selectedId == -1 || vehicleBrands.isNotEmpty) {
return;
}
vehicleBrands = await adsRepo.getVehicleBrands(vehicleTypeId: vehicleTypeId.selectedId);
@ -491,6 +545,13 @@ class AdVM extends BaseVM {
notifyListeners();
}
SelectionModel vehicleExtendAdDurationId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateVehicleExtendAdDurationId(SelectionModel id) {
vehicleAdDurationId = id;
notifyListeners();
}
SelectionModel vehicleAdReservableId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
void updateVehicleAdReservableId(SelectionModel id) {
@ -812,20 +873,20 @@ class AdVM extends BaseVM {
void onBackButtonPressed(BuildContext context) {
switch (currentProgressStep) {
case AdCreationStepsEnum.vehicleDetails:
case AdCreationSteps.vehicleDetails:
resetValues();
pop(context);
break;
case AdCreationStepsEnum.damageParts:
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
case AdCreationSteps.damageParts:
currentProgressStep = AdCreationSteps.vehicleDetails;
notifyListeners();
break;
case AdCreationStepsEnum.adDuration:
currentProgressStep = AdCreationStepsEnum.damageParts;
case AdCreationSteps.adDuration:
currentProgressStep = AdCreationSteps.damageParts;
notifyListeners();
break;
case AdCreationStepsEnum.reviewAd:
currentProgressStep = AdCreationStepsEnum.adDuration;
case AdCreationSteps.reviewAd:
currentProgressStep = AdCreationSteps.adDuration;
notifyListeners();
break;
}
@ -833,28 +894,28 @@ class AdVM extends BaseVM {
void updateCurrentStep(BuildContext context) async {
switch (currentProgressStep) {
case AdCreationStepsEnum.vehicleDetails:
case AdCreationSteps.vehicleDetails:
if (isVehicleDetailsValidated()) {
currentProgressStep = AdCreationStepsEnum.damageParts;
currentProgressStep = AdCreationSteps.damageParts;
getVehicleDamagePartsList();
notifyListeners();
}
break;
case AdCreationStepsEnum.damageParts:
case AdCreationSteps.damageParts:
if (isDamagePartsValidated()) {
currentProgressStep = AdCreationStepsEnum.adDuration;
currentProgressStep = AdCreationSteps.adDuration;
getVehicleAdsDuration();
getVehicleAdsSpecialServices();
notifyListeners();
}
break;
case AdCreationStepsEnum.adDuration:
case AdCreationSteps.adDuration:
if (isAdDurationValidated()) {
currentProgressStep = AdCreationStepsEnum.reviewAd;
currentProgressStep = AdCreationSteps.reviewAd;
notifyListeners();
}
break;
case AdCreationStepsEnum.reviewAd:
case AdCreationSteps.reviewAd:
Utils.showLoading(context);
try {
int status = await createNewAd();
@ -865,7 +926,7 @@ class AdVM extends BaseVM {
}
Utils.hideLoading(context);
Utils.showToast("A new ads has been created.");
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
currentProgressStep = AdCreationSteps.vehicleDetails;
resetValues();
updateIsExploreAds(false);
applyFilterOnMyAds(index: 1, adPostStatusEnum: AdPostStatus.pendingForReview); //pending for review
@ -982,7 +1043,7 @@ class AdVM extends BaseVM {
pickedVehicleImages.clear();
vehicleDamageCards.clear();
specialServiceCards.clear();
currentProgressStep = AdCreationStepsEnum.vehicleDetails;
currentProgressStep = AdCreationSteps.vehicleDetails;
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleTypeId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
vehicleBrandId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

@ -13,8 +13,8 @@ class PaymentVM extends ChangeNotifier {
PaymentVM({required this.paymentService, required this.paymentRepo});
PaymentMethodsEnum selectedPaymentMethod = PaymentMethodsEnum.mada;
PaymentTypesEnum currentPaymentType = PaymentTypesEnum.ads;
PaymentMethods selectedPaymentMethod = PaymentMethods.mada;
PaymentTypes currentPaymentType = PaymentTypes.ads;
int currentAdId = -1;
@ -22,26 +22,26 @@ class PaymentVM extends ChangeNotifier {
currentAdId = id;
}
updateSelectedPaymentMethod(PaymentMethodsEnum selectedMethod) {
updateSelectedPaymentMethod(PaymentMethods selectedMethod) {
selectedPaymentMethod = selectedMethod;
notifyListeners();
}
Future<void> onContinuePressed(BuildContext context, {required PaymentTypesEnum paymentType}) async {
Future<void> onContinuePressed(BuildContext context, {required PaymentTypes paymentType}) async {
switch (selectedPaymentMethod) {
case PaymentMethodsEnum.mada:
case PaymentMethods.mada:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.visa:
case PaymentMethods.visa:
await onVisaCardSelected(context, paymentType);
break;
case PaymentMethodsEnum.applePay:
case PaymentMethods.applePay:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.masterCard:
case PaymentMethods.masterCard:
// TODO: Handle this case.
break;
case PaymentMethodsEnum.tamara:
case PaymentMethods.tamara:
// TODO: Handle this case.
break;
}
@ -49,74 +49,64 @@ class PaymentVM extends ChangeNotifier {
return;
}
Future<void> onVisaCardSelected(BuildContext context, PaymentTypesEnum paymentType) async {
Future<void> placeThePayment({required int adId, required int paymentTypeId, required BuildContext context}) async {
await paymentService.placeAdPayment(
id: currentAdId,
paymentType: paymentTypeId,
onFailure: () {
Utils.showToast("Payment Failed!");
},
onSuccess: () async {
Utils.showLoading(context);
PayOrderDetailRespModel payOrderDetailRespModel = await paymentRepo.getPayOrderDetails(paymentId: paymentTypeId, adId: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
if (payOrderDetailRespModel.isPaid == null || !payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Failed!");
return;
}
if (payOrderDetailRespModel.isPaid != null && payOrderDetailRespModel.isPaid!) {
Utils.showToast("Payment Successful");
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
}
},
);
}
Future<void> onVisaCardSelected(BuildContext context, PaymentTypes paymentType) async {
currentPaymentType = paymentType;
switch (currentPaymentType) {
case PaymentTypesEnum.subscription:
// TODO: Handle this case.
break;
case PaymentTypesEnum.appointment:
// TODO: Handle this case.
break;
case PaymentTypesEnum.ads:
case PaymentTypes.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: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
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);
}
},
);
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
break;
case PaymentTypesEnum.adReserve:
case PaymentTypes.adReserve:
if (currentAdId == -1) return;
int paymentType = 4;
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: currentAdId);
await Future.delayed(const Duration(seconds: 2));
Utils.hideLoading(context);
print("payOrderDetailRespModel: ${payOrderDetailRespModel.toString()}");
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);
}
},
);
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
break;
case PaymentTypes.extendAds:
if (currentAdId == -1) return;
int paymentType = 6;
await placeThePayment(adId: currentAdId, context: context, paymentTypeId: paymentType);
break;
case PaymentTypes.request:
// TODO: Handle this case.
break;
case PaymentTypes.subscription:
// TODO: Handle this case.
break;
case PaymentTypesEnum.request:
case PaymentTypes.appointment:
// TODO: Handle this case.
break;
}

@ -36,7 +36,7 @@ class AdDuration extends StatelessWidget {
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: "Reserve Ad Price Info",
title: "Reserve Ad Price Info".toText(fontSize: 24, isBold: true),
description: Flexible(
child: GlobalConsts.reserveAdPriceInfo.toText(
textAlign: TextAlign.justify,

@ -5,6 +5,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/ads_duration_model.dart';
import 'package:mc_common_app/models/widgets_models.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/ad_view_model.dart';
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
@ -12,13 +13,14 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
class AdDurationSelectionSheetContent extends StatelessWidget {
const AdDurationSelectionSheetContent({super.key});
final bool isFromExtendAd;
final bool isUpdateAdSelected;
const AdDurationSelectionSheetContent({super.key, required this.isFromExtendAd, required this.isUpdateAdSelected});
@override
Widget build(BuildContext context) {
AdVM adVM = context.watch<AdVM>();
print("hello : ${adVM.vehicleAdDurationId.selectedId}");
return SizedBox(
height: MediaQuery.of(context).size.height / 1.2,
child: Column(
@ -70,6 +72,16 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
],
).toWhiteContainer(width: double.infinity, allPading: 12, isBorderRequired: adDuration.id == adVM.vehicleAdDurationId.selectedId ? true : false),
).onPress(() {
if (isFromExtendAd) {
adVM.updateVehicleExtendAdDurationId(
SelectionModel(
selectedId: adDuration.id ?? 0,
selectedOption: "${adDuration.days} Days",
itemPrice: adDuration.price!.toInt().toString(),
),
);
return;
}
adVM.updateVehicleAdDurationId(
SelectionModel(
selectedId: adDuration.id ?? 0,
@ -90,7 +102,10 @@ class AdDurationSelectionSheetContent extends StatelessWidget {
maxWidth: double.infinity,
margin: const EdgeInsets.all(21),
onPressed: () {
if (isFromExtendAd && !isUpdateAdSelected) {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.extendAds);
return;
}
navigateReplaceWithName(context, AppRoutes.createAdView);
},
).toContainer(paddingAll: 0, backgroundColor: Colors.white),

@ -1,14 +1,22 @@
import 'package:flutter/material.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/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/advertisment_models/ad_details_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.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';
import 'package:mc_common_app/view_models/ad_view_model.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/advertisement/ad_duration_selection_sheet_content.dart';
import 'package:mc_common_app/views/advertisement/ads_images_slider.dart';
import 'package:mc_common_app/widgets/bottom_sheet.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/common_widgets/info_bottom_sheet.dart';
@ -20,17 +28,72 @@ class AdsDetailView extends StatelessWidget {
const AdsDetailView({Key? key, required this.adDetails}) : super(key: key);
void deleteAdBottomSheet(BuildContext context) {
AdVM adVM = context.read<AdVM>();
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to delete the ad?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "Your ad will be permanently deleted and you cannot undo this action.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Yes",
fontSize: 15,
onPressed: () {
Navigator.pop(context);
adVM.deleteMyAd(context, adId: adDetails.id!);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: "No",
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
@override
Widget build(BuildContext context) {
print("adId: ${adDetails.id}");
print("statusID: ${adDetails.adPostStatus}");
print("statusID: ${adDetails.statusID}");
return Scaffold(
appBar: CustomAppBar(
title: "Ads",
profileImageUrl: MyAssets.bnCar,
isRemoveBackButton: false,
isDrawerEnabled: false,
actions: [const Icon(Icons.chat_outlined).paddingOnly(right: 21)],
actions: [
(adDetails.isMyAd ?? false
? IconButton(
icon: const Icon(Icons.delete_outline, color: MyColors.redColor),
onPressed: () {
return deleteAdBottomSheet(context);
},
)
: IconButton(
icon: const Icon(Icons.chat_outlined, color: Colors.black),
onPressed: () {},
))
.toContainer(
margin: const EdgeInsets.fromLTRB(0, 8, 21, 8),
paddingAll: 0,
padding: const EdgeInsets.only(right: 21),
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 42,
)
],
onTap: () {},
),
body: Container(
@ -97,6 +160,27 @@ class AdsDetailView extends StatelessWidget {
fontSize: 14,
isBold: true,
),
if (adDetails.isMyAd ?? false) ...[
8.height,
"Demand: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
adDetails.vehicle!.demandAmount!.toInt().toString().toText(fontSize: 30, height: 1.2, isBold: true),
" SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
],
),
if (adDetails.adPostStatus == AdPostStatus.expired) ...[
8.height,
const Divider(thickness: 1, height: 1),
8.height,
"Your Ad Duration time is over.".toText(
color: MyColors.redColor,
fontSize: 12,
isItalic: true,
),
],
]
],
).toWhiteContainer(width: double.infinity, allPading: 12),
],
@ -105,16 +189,18 @@ class AdsDetailView extends StatelessWidget {
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).paddingOnly(bottom: 5),
],
),
14.height,
if (!(adDetails.isMyAd ?? false)) ...[
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).paddingOnly(bottom: 5),
],
),
14.height,
],
adDetails.isMyAd ?? false ? BuildAdDetailsActionButtonForMyAds(adDetailsModel: adDetails) : BuildAdDetailsActionButtonForExploreAds(adDetailsModel: adDetails),
],
),
@ -138,7 +224,7 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: "Reserve Ad",
title: "Reserve Ad".toText(fontSize: 24, isBold: true),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -270,7 +356,7 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
title: "Complete Reservation",
onPressed: () {
Navigator.pop(context);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypesEnum.adReserve);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.adReserve);
},
),
),
@ -322,7 +408,9 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
//TODO: It Will be replaced by a WhatsApp Icon
child: const Icon(Icons.message, color: MyColors.black),
).onPress(() {}),
).onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),
],
if (adDetailsModel.phoneNo != null) ...[
8.width,
@ -332,14 +420,16 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
child: const Icon(Icons.phone, color: MyColors.black),
).onPress(() {}),
).onPress(() {
Utils.openNumberViaCaller(phoneNumber: adDetailsModel.phoneNo ?? "");
}),
]
],
);
}
Widget defaultActionForProviderAndCustomer(BuildContext context, AdDetailsModel adDetailsModel) {
return (adDetailsModel.phoneNo != null)
return (adDetailsModel.phoneNo == null)
? Row(
children: [
Expanded(
@ -352,10 +442,12 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
padding: EdgeInsets.only(right: 10),
child: Icon(Icons.phone, color: MyColors.white, size: 24),
),
onPressed: () {},
onPressed: () {
Utils.openNumberViaCaller(phoneNumber: adDetailsModel.phoneNo ?? "");
},
),
),
if (adDetailsModel.whatsAppNo != null) ...[
if (adDetailsModel.whatsAppNo == null) ...[
8.width,
Container(
height: 55,
@ -364,7 +456,9 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 2)),
//TODO: It Will be replaced by a WhatsApp Icon
child: const Icon(Icons.message, color: MyColors.black),
).onPress(() {}),
).onPress(() {
Utils.openNumberViaWhatsApp(phoneNumber: adDetailsModel.whatsAppNo ?? "");
}),
],
],
)
@ -401,7 +495,7 @@ class BuildAdDetailsActionButtonForExploreAds extends StatelessWidget {
case CreatedByRoleEnum.admin:
return reserveAdAction(context, adDetailsModel);
case CreatedByRoleEnum.allAds:
return SizedBox.shrink();
return const SizedBox.shrink();
}
}
}
@ -418,7 +512,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
enableDrag: true,
builder: (BuildContext context) {
return InfoBottomSheet(
title: "Reserve Ad",
title: "Reserve Ad".toText(fontSize: 24, isBold: true),
description: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -555,7 +649,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
});
}
Widget pendingForReviewAction(BuildContext context, {required int adID}) {
Widget pendingForReviewAction(BuildContext context, {required bool isPendingPost}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -566,7 +660,7 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
backgroundColor: MyColors.grey98Color.withOpacity(0.3),
txtColor: MyColors.lightTextColor,
maxHeight: 55,
title: "Waiting for Admins Approval",
title: isPendingPost ? "Waiting for admin to post" : "Waiting for Admins Approval",
isBold: false,
onPressed: () {},
),
@ -588,29 +682,18 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
maxHeight: 55,
title: "Pay Now",
onPressed: () {
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypesEnum.ads);
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.ads);
},
),
),
],
),
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),
),
),
],
)
],
);
}
Widget markAsSoldAction(BuildContext context) {
AdVM adVM = context.read<AdVM>();
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -620,20 +703,55 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
child: ShowFillButton(
maxHeight: 55,
title: "Mark As Sold",
onPressed: () {},
isBold: false,
onPressed: () {
adVM.markAdAsSold(context, adId: adDetailsModel.id!);
},
),
),
],
),
8.height,
Row(
children: [
Expanded(
child: ShowFillButton(
isFilled: true,
borderColor: MyColors.darkPrimaryColor,
isFilled: false,
borderColor: MyColors.redColor,
maxHeight: 55,
title: "Deactivate Ad",
onPressed: () {},
txtColor: MyColors.redColor,
onPressed: () {
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to the Deactivate this Ad?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "We will stop showing this ad to the buyers.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Yes",
fontSize: 15,
onPressed: () {
Navigator.pop(context);
adVM.deactivateTheAd(context, adId: adDetailsModel.id!);
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: "No",
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
Navigator.pop(context);
},
),
),
);
},
),
),
],
@ -660,6 +778,60 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
);
}
Widget expiredAdAction(BuildContext context) {
return Row(
children: [
Expanded(
child: ShowFillButton(
fontSize: 16,
maxHeight: 55,
title: "Extend Ad",
onPressed: () {
final AdVM adVM = context.read<AdVM>();
return actionConfirmationBottomSheet(
context: context,
title: "Do you want to update the Ad Details?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
subtitle: "You can change the ad duration and details before extending the ad.",
actionButtonYes: Expanded(
child: ShowFillButton(
maxHeight: 55,
title: "Yes",
fontSize: 15,
onPressed: () {
Navigator.pop(context);
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: adDetailsModel.vehicle!.vehicleType!, selectedOption: (adDetailsModel.vehicle!.vehicleType!).toVehicleTypeString(), errorValue: ""),
);
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isFromExtendAd: true, isUpdateAdSelected: true));
},
),
),
actionButtonNo: Expanded(
child: ShowFillButton(
maxHeight: 55,
isFilled: false,
borderColor: MyColors.darkPrimaryColor,
title: "No",
txtColor: MyColors.darkPrimaryColor,
fontSize: 15,
onPressed: () {
adVM.updateSelectionVehicleTypeId(
SelectionModel(selectedId: adDetailsModel.vehicle!.vehicleType!, selectedOption: (adDetailsModel.vehicle!.vehicleType!).toVehicleTypeString(), errorValue: ""),
);
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isFromExtendAd: true, isUpdateAdSelected: false));
},
),
),
);
},
),
),
],
);
}
Widget defaultAction(BuildContext context) {
return Row(
children: [
@ -709,12 +881,15 @@ class BuildAdDetailsActionButtonForMyAds extends StatelessWidget {
case AdPostStatus.rejected:
case AdPostStatus.cancelled:
case AdPostStatus.pendingForPost:
return pendingForReviewAction(context, isPendingPost: true);
case AdPostStatus.pendingForReview:
return pendingForReviewAction(context, adID: adDetailsModel.id!);
return pendingForReviewAction(context, isPendingPost: false);
// return pendingForPaymentAction(context, adID: adId);
case AdPostStatus.sold:
case AdPostStatus.expired:
return expiredAdAction(context);
case AdPostStatus.allAds:
break;
}
return const SizedBox.shrink();

@ -39,19 +39,19 @@ class CreateAdProgressSteps extends StatelessWidget {
);
}
bool isStepCompleted({required AdCreationStepsEnum currentStep}) {
bool isStepCompleted({required AdCreationSteps currentStep}) {
return true;
}
int getProgressStepNumber({required AdCreationStepsEnum currentStep}) {
int getProgressStepNumber({required AdCreationSteps currentStep}) {
switch (currentStep) {
case AdCreationStepsEnum.vehicleDetails:
case AdCreationSteps.vehicleDetails:
return 1;
case AdCreationStepsEnum.damageParts:
case AdCreationSteps.damageParts:
return 2;
case AdCreationStepsEnum.adDuration:
case AdCreationSteps.adDuration:
return 3;
case AdCreationStepsEnum.reviewAd:
case AdCreationSteps.reviewAd:
return 4;
}
}

@ -73,7 +73,7 @@ class BuildFooterButton extends StatelessWidget {
return Consumer(
builder: (BuildContext context, AdVM adVm, Widget? child) {
switch (adVm.currentProgressStep) {
case AdCreationStepsEnum.vehicleDetails:
case AdCreationSteps.vehicleDetails:
return SizedBox(
width: double.infinity,
child: ShowFillButton(
@ -83,7 +83,7 @@ class BuildFooterButton extends StatelessWidget {
},
),
);
case AdCreationStepsEnum.damageParts:
case AdCreationSteps.damageParts:
return Row(
children: [
Expanded(
@ -111,7 +111,7 @@ class BuildFooterButton extends StatelessWidget {
),
],
);
case AdCreationStepsEnum.adDuration:
case AdCreationSteps.adDuration:
return Row(
children: [
Expanded(
@ -139,7 +139,7 @@ class BuildFooterButton extends StatelessWidget {
),
],
);
case AdCreationStepsEnum.reviewAd:
case AdCreationSteps.reviewAd:
return Row(
children: [
Expanded(
@ -182,7 +182,7 @@ class BuildAdStepContainer extends StatelessWidget {
final WidgetBuilder onDamageParts;
final WidgetBuilder onAdDuration;
final WidgetBuilder onReviewAd;
final AdCreationStepsEnum adCreationStepsEnum;
final AdCreationSteps adCreationStepsEnum;
const BuildAdStepContainer({
Key? key,
@ -196,16 +196,16 @@ class BuildAdStepContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
switch (adCreationStepsEnum) {
case AdCreationStepsEnum.vehicleDetails:
case AdCreationSteps.vehicleDetails:
return onVehicleDetails(context);
case AdCreationStepsEnum.damageParts:
case AdCreationSteps.damageParts:
return onDamageParts(context);
case AdCreationStepsEnum.adDuration:
case AdCreationSteps.adDuration:
return onAdDuration(context);
case AdCreationStepsEnum.reviewAd:
case AdCreationSteps.reviewAd:
return onReviewAd(context);
}
}

@ -22,18 +22,18 @@ class SelectAdTypeView extends StatelessWidget {
this.isProvider = true,
}) : super(key: key);
Widget getVehicleAdTypeIcon(VehicleTypeEnum vehicleTypeEnum) {
Widget getVehicleAdTypeIcon(VehicleType vehicleTypeEnum) {
switch (vehicleTypeEnum) {
case VehicleTypeEnum.car:
case VehicleType.car:
return MyAssets.vehicleTypeCar.buildSvg(height: 22);
case VehicleTypeEnum.motorCycle:
case VehicleType.motorCycle:
return MyAssets.vehicleTypeMotorcycle.buildSvg(height: 26);
case VehicleTypeEnum.golfCart:
case VehicleType.golfCart:
return MyAssets.vehicleTypeGolfCart.buildSvg(height: 26);
case VehicleTypeEnum.buggy:
case VehicleType.buggy:
return MyAssets.vehicleTypeBuggy.buildSvg(height: 26);
}
}
@ -61,7 +61,7 @@ class SelectAdTypeView extends StatelessWidget {
SelectionModel(selectedId: vehicleTypeModel.id!, selectedOption: vehicleTypeModel.vehicleTypeName ?? "", errorValue: ""),
);
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent());
showMyBottomSheet(context, child: const AdDurationSelectionSheetContent(isUpdateAdSelected: false, isFromExtendAd: false));
},
child: SizedBox(
width: double.infinity,

@ -11,7 +11,7 @@ import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
import 'package:provider/provider.dart';
class PaymentMethodsView extends StatelessWidget {
final PaymentTypesEnum paymentType;
final PaymentTypes paymentType;
const PaymentMethodsView({Key? key, required this.paymentType}) : super(key: key);
@ -40,24 +40,24 @@ class PaymentMethodsView extends StatelessWidget {
shrinkWrap: true,
children: [
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.mada,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.mada),
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.mada,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.mada),
cardAsset: MyAssets.madaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.visa,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.visa),
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.visa,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.visa),
cardAsset: MyAssets.visaPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.applePay,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.applePay),
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.applePay,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.applePay),
cardAsset: MyAssets.applePayPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.masterCard,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.masterCard),
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.masterCard,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.masterCard),
cardAsset: MyAssets.mastercardPng),
PaymentMethodContainer(
isSelected: paymentVm.selectedPaymentMethod == PaymentMethodsEnum.tamara,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethodsEnum.tamara),
isSelected: paymentVm.selectedPaymentMethod == PaymentMethods.tamara,
onTap: () => paymentVm.updateSelectedPaymentMethod(PaymentMethods.tamara),
cardAsset: MyAssets.tamaraEngPng),
],
),

@ -29,7 +29,7 @@ class _LoginWithPasswordState extends State<LoginWithPassword> {
ClassType type = ClassType.EMAIL;
//TODO: ONLY FOR DEVELOPMENT PURPOSE
String phoneNum = "966504278213", password = "Fa@1234";
String phoneNum = "966504278212", password = "Fa@123";
String email = "";
String countryCode = "";
Country? _country;

@ -29,7 +29,7 @@ class ShowFillButton extends StatelessWidget {
this.fontSize = 16,
this.horizontalPadding = 16,
this.isFlatButton = false,
this.isBold = true,
this.isBold = false,
this.horizontalMargin = 0,
this.verticalMargin = 0,
this.margin,

@ -104,45 +104,45 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
centerTitle: isTitleCenter ?? true,
leading: isDrawerEnabled
? InkWell(
onTap: onTap,
child: Row(
children: [
Image.asset(
profileImageUrl,
width: 34,
height: 34,
fit: BoxFit.fill,
).toCircle(borderRadius: 100),
10.width,
SvgPicture.asset(MyAssets.dashboardDrawerIcon),
],
).paddingOnly(left: 21),
)
onTap: onTap,
child: Row(
children: [
Image.asset(
profileImageUrl,
width: 34,
height: 34,
fit: BoxFit.fill,
).toCircle(borderRadius: 100),
10.width,
SvgPicture.asset(MyAssets.dashboardDrawerIcon),
],
).paddingOnly(left: 21),
)
: isRemoveBackButton
? null
: Row(
children: [
21.width,
IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 16,
),
onPressed: onBackButtonTapped ?? () {
Navigator.pop(context);
},
).toContainer(
paddingAll: 0,
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 40,
),
],
),
? null
: Row(
children: [
21.width,
IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 16,
),
onPressed: onBackButtonTapped ??
() {
Navigator.pop(context);
},
).toContainer(
paddingAll: 0,
borderRadius: 100,
borderColor: MyColors.lightGreyEFColor,
isEnabledBorder: true,
height: 40,
width: 40,
),
],
),
iconTheme: IconThemeData(
color: backIconColor ?? Colors.black, //change your color here
),

@ -5,7 +5,7 @@ import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
class InfoBottomSheet extends StatelessWidget {
final String title;
final Widget title;
final Widget description;
const InfoBottomSheet({Key? key, required this.title, required this.description}) : super(key: key);
@ -13,8 +13,11 @@ class InfoBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
// height: MediaQuery.of(context).size.height * 0.35,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.all(8),
@ -22,16 +25,13 @@ class InfoBottomSheet extends StatelessWidget {
width: 60,
decoration: const BoxDecoration(color: MyColors.lightTextColor, borderRadius: BorderRadius.all(Radius.circular(20))),
),
12.height,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
title.toText(fontSize: 24, isBold: true),
],
),
8.height,
description,
],
).horPaddingMain());
),
12.height,
title,
8.height,
description,
],
).horPaddingMain());
}
}

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/models/service_schedule_model.dart';
import 'package:mc_common_app/models/widgets_models.dart';
import 'package:mc_common_app/theme/colors.dart';
@ -45,3 +46,46 @@ class BuildTimeSlots extends StatelessWidget {
);
}
}
class BuildDateSlotsForAppointment extends StatelessWidget {
final List<CustomTimeDateSlotModel> customDateSlots;
final Function(int) onPressed;
const BuildDateSlotsForAppointment({Key? key, required this.customDateSlots, required this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 37,
width: double.infinity,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: customDateSlots.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
onPressed(index);
},
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.only(right: 8),
// width: 50,
padding: const EdgeInsets.symmetric(horizontal: 9),
decoration: BoxDecoration(
color: customDateSlots[index].date!.isSelected ? MyColors.darkIconColor : null,
border: Border.all(
color: customDateSlots[index].date!.isSelected ? MyColors.darkIconColor : MyColors.primaryColor,
),
),
child: customDateSlots[index].date!.date.toText(
fontSize: 12,
color: customDateSlots[index].date!.isSelected ? MyColors.white : null,
),
),
);
}),
);
}
}

@ -31,7 +31,7 @@ dependencies:
local_auth: any
hexcolor: ^3.0.1
cached_network_image: any
url_launcher: ^6.1.7
url_launcher: ^6.1.14
badges: ^3.0.2
carousel_slider: ^4.2.1
dropdown_button2: ^2.0.0

Loading…
Cancel
Save