diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 9381824..5cb1115 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -784,5 +784,7 @@ "enterCustomerName": "أدخل اسم العميل", "tapToView": "انقر لعرض", "noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.", - "copySelectedItems": "نسخ العناصر المحددة" + "copySelectedItems": "نسخ العناصر المحددة", + "companyNameMandatory": "اسم الشركة إلزامي" + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 84263e4..865ef94 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -782,5 +782,6 @@ "enterCustomerName": "Enter Customer Name", "tapToView": "Tap to view", "noServicesAvailableToCopy": "There are no services available in this branch to copy.", - "copySelectedItems": "Copy Selected Items" + "copySelectedItems": "Copy Selected Items", + "companyNameMandatory": "Company Name is mandatory" } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 736aabb..7f9ee48 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -261,6 +261,8 @@ class GlobalConsts { static int maxFileCount = 7; static int maxFileSizeInBytes = 2 * 1024 * 1024; + static String allowedFileExtensions = "jpg,png - 2MB"; + static String allowedFileExtensionsPDF = "PDF 2MB"; static int providerDealerRoleTypeId = 6; static int providerIndividualRoleTypeId = 5; diff --git a/lib/generated/codegen_loader.g.dart b/lib/generated/codegen_loader.g.dart index f79e313..18d8869 100644 --- a/lib/generated/codegen_loader.g.dart +++ b/lib/generated/codegen_loader.g.dart @@ -736,7 +736,7 @@ class CodegenLoader extends AssetLoader{ "ownerInformation": "معلومات المالك", "acceptedRequests": "الطلبات المقبولة", "specialRequestChat": "دردشة الطلب الخاص", - "companyName": "اسم الشركة", + "companyName": "اسم الشركة *", "noAvailableItems": "لا توجد عناصر متاحة.", "serviceDeliveryType": "نوع تقديم الخدمة", "noImagesToShow": "لا توجد صور للعرض", @@ -800,7 +800,8 @@ class CodegenLoader extends AssetLoader{ "enterCustomerName": "أدخل اسم العميل", "tapToView": "انقر لعرض", "noServicesAvailableToCopy": "لا توجد خدمات متاحة في هذا الفرع لنسخها.", - "copySelectedItems": "نسخ العناصر المحددة" + "copySelectedItems": "نسخ العناصر المحددة", + "companyNameMandatory": "اسم الشركة إلزامي" }; static const Map en_US = { "firstTimeLogIn": "First Time Log In", @@ -1518,7 +1519,7 @@ static const Map en_US = { "noItemsToShow": "There are no Items no show.", "acceptedRequests": "Accepted Requests", "specialRequestChat": "Special Request Chat", - "companyName": "Company Name", + "companyName": "Company Name *", "noAvailableItems": "There are no available items.", "serviceDeliveryType": "Service Delivery Type", "noImagesToShow": "No Images to Show", @@ -1586,7 +1587,8 @@ static const Map en_US = { "enterCustomerName": "Enter Customer Name", "tapToView": "Tap to view", "noServicesAvailableToCopy": "There are no services available in this branch to copy.", - "copySelectedItems": "Copy Selected Items" + "copySelectedItems": "Copy Selected Items", + "companyNameMandatory": "Company Name is mandatory" }; static const Map> mapLocales = {"ar_SA": ar_SA, "en_US": en_US}; } diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index 23be5e5..16d573f 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -764,5 +764,6 @@ abstract class LocaleKeys { static const tapToView = 'tapToView'; static const noServicesAvailableToCopy = 'noServicesAvailableToCopy'; static const copySelectedItems = 'copySelectedItems'; + static const companyNameMandatory = 'companyNameMandatory'; } diff --git a/lib/models/chat_models/chat_message_model.dart b/lib/models/chat_models/chat_message_model.dart index b8137b9..63ce43a 100644 --- a/lib/models/chat_models/chat_message_model.dart +++ b/lib/models/chat_models/chat_message_model.dart @@ -113,8 +113,8 @@ class ReqOffer { offerStatusText = json['offerStatusText']; comment = json['comment']; serviceItemName = json['serviceItem']; - manufacturedByName = json['offeredItemCreatedBy'].toString(); - manufacturedOn = json['offeredItemCreatedOn']; + manufacturedByName = json['offeredItemCreatedByName'].toString(); + manufacturedOn = json['offeredItemCreatedOn'] ?? json["createdOn"]; price = json['price']; isDeliveryAvailable = json['isDeliveryAvailable']; requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum(); diff --git a/lib/repositories/request_repo.dart b/lib/repositories/request_repo.dart index 16c121b..2293cc9 100644 --- a/lib/repositories/request_repo.dart +++ b/lib/repositories/request_repo.dart @@ -369,7 +369,7 @@ class RequestRepoImp implements RequestRepo { "serviceItem": serviceItemName, "comment": message, "price": offerPrice, - "offeredItemCreatedBy": manufacturedByName.toString(), + "offeredItemCreatedByName": manufacturedByName.toString(), "offeredItemCreatedOn": manufacturedOn.toString(), "reqOfferImages": requestImages, "isDeliveryAvailable": isDeliveryAvailable diff --git a/lib/repositories/user_repo.dart b/lib/repositories/user_repo.dart index 589681e..19feaea 100644 --- a/lib/repositories/user_repo.dart +++ b/lib/repositories/user_repo.dart @@ -31,7 +31,7 @@ abstract class UserRepo { Future basicVerify(String phoneNo, String otp, String userToken, {bool isNeedToPassToken = false}); - Future basicComplete(String userId, String firstName, String lastName, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false}); + Future basicComplete(String userId, String firstName, String lastName, String compannyNname, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false}); Future loginV1(String phoneNo, String password); @@ -106,12 +106,12 @@ class UserRepoImp implements UserRepo { } @override - Future basicComplete(String userId, String firstName, String lastName, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false}) async { + Future basicComplete(String userId, String firstName, String lastName, String companyName, String email, String password, String cityID, String genderID, {bool isNeedToPassToken = false}) async { Map postParams; if (email.isEmpty) { - postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "companyName": "string", "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID}; + postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "companyName": companyName, "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID}; } else { - postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "email": email, "companyName": "string", "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID}; + postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "email": email, "companyName": companyName, "isEmailVerified": true, "password": password, "cityID": cityID, "genderID": genderID}; } String? t; if (isNeedToPassToken) { diff --git a/lib/view_models/chat_view_model.dart b/lib/view_models/chat_view_model.dart index 20bbc7e..9f7ea92 100644 --- a/lib/view_models/chat_view_model.dart +++ b/lib/view_models/chat_view_model.dart @@ -387,8 +387,8 @@ class ChatVM extends BaseVM { "IsDeliveryAvailable": isDeliveryAvailable, "ServiceItem": serviceItemName, "ReqOfferImages": offerImages, - "OfferedItemCreatedBy": manufacturedByName, - // "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime + "OfferedItemCreatedByName": manufacturedByName, + "OfferedItemCreatedOn": manufacturedOn, // TODO: This should be in String on Server, Right now it is in DateTime "ServiceProviderID": providerId, "OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(), "Comment": message, @@ -610,7 +610,7 @@ class ChatVM extends BaseVM { int providerId = AppState().getUser.data!.userInfo!.providerId!; Utils.showLoading(context); List chatMessages = await chatRepo.getUsersChatMessagesForRequests(providerId: providerId, customerId: customerId, requestOfferId: requestOfferId, requestId: requestId); - context.read().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context); + await context.read().overwriteChatMessagesInRequestsModel(messages: chatMessages, index: customerRequestIndex, context: context); List unreadMessageIds = []; for (var msg in chatMessages) { if (!msg.isRead! && !msg.isMyMessage!) { @@ -674,7 +674,7 @@ class ChatVM extends BaseVM { "RequestID": requestId, "Price": double.parse(offerPrice), "ServiceItem": serviceItemName, - "OfferedItemCreatedBy": manufacturedByName, + "OfferedItemCreatedByName": manufacturedByName, // "OfferedItemCreatedOn": manufacturedOn, "ServiceProviderID": serviceProviderID, "OfferStatus": requestOfferStatusEnum.getIdFromRequestOfferStatusEnum(), diff --git a/lib/view_models/dashboard_view_model_provider.dart b/lib/view_models/dashboard_view_model_provider.dart index b43e2d5..f0433c6 100644 --- a/lib/view_models/dashboard_view_model_provider.dart +++ b/lib/view_models/dashboard_view_model_provider.dart @@ -81,18 +81,20 @@ class DashboardVMProvider extends BaseVM { requestsVM.populateDataForRequestsFilter(); appointmentVM.populateAppointmentsFilterList(); shippingManagementVM.populateShippingRequestFilterList(); - await serviceVM.getBranchAndServices(); await serviceVM.populateBranchServiceFilters(); - await appointmentVM.getMyAppointmentsForProvider(branchID: appointmentVM.selectedBranchIdForAppointments); - adVM.populateAdsFilterList(); - await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); + + await serviceVM.getBranchAndServices(); + if (dashboardRouteEnum != DashboardRouteEnum.fromAdsPayment && dashboardRouteEnum != DashboardRouteEnum.fromAdsSubmit) { await adVM.getMyAds(); await adVM.getExploreAds(); } + await appointmentVM.getMyAppointmentsForProvider(branchID: appointmentVM.selectedBranchIdForAppointments); + adVM.populateAdsFilterList(); + await requestsVM.getRequests(); + await subscriptionsVM.getSubscriptionBySP(AppState().getUser.data?.userInfo?.providerId.toString() ?? "", true); await adVM.getVehicleTypes(); await adVM.getVehicleAdsDuration(); - await requestsVM.getRequests(); await chatVM.buildHubConnection(context); } @@ -128,7 +130,7 @@ class DashboardVMProvider extends BaseVM { void performCheckOnUsers(BuildContext context, Function() callBack) async { if (AppState().getproviderSubscription.isNotEmpty && AppState().getproviderSubscription.first.subUsersRemaining! > 0) { - showMyBottomSheet(context, isDismissible: false, child: const AddPhoneNumWidget(), callBackFunc: callBack); + showMyBottomSheet(context, isDismissible: false, isScrollControlled: true, child: AddPhoneNumWidget(), callBackFunc: callBack); } else { Utils.showToast(LocaleKeys.upgradeSubUsers.tr()); } diff --git a/lib/view_models/requests_view_model.dart b/lib/view_models/requests_view_model.dart index 41ef7be..f8f9833 100644 --- a/lib/view_models/requests_view_model.dart +++ b/lib/view_models/requests_view_model.dart @@ -215,13 +215,13 @@ class RequestsVM extends BaseVM { notifyListeners(); } - overwriteChatMessagesInRequestsModel({required List messages, required int index, required BuildContext context}) { + overwriteChatMessagesInRequestsModel({required List messages, required int index, required BuildContext context}) async { if (myFilteredRequests.isEmpty) return; myFilteredRequests[index].chatMessages = messages; if (myFilteredRequests[index].chatMessages.isNotEmpty) { for (var message in myFilteredRequests[index].chatMessages) { if (message.chatMessageTypeEnum == ChatMessageTypeEnum.offer) { - context.read().updateLatestOfferId(message.reqOfferID ?? 0); + await context.read().updateLatestOfferId(message.reqOfferID ?? 0); if (message.reqOffer!.requestOfferStatusEnum == RequestOfferStatusEnum.accepted) { updateAcceptedReqOffer(message.reqOffer!); updateAcceptedRequestOfferProviderName(message.senderName ?? ""); diff --git a/lib/view_models/user_view_model.dart b/lib/view_models/user_view_model.dart index 6a2bd38..24a983e 100644 --- a/lib/view_models/user_view_model.dart +++ b/lib/view_models/user_view_model.dart @@ -65,6 +65,15 @@ class UserVM extends BaseVM { _loginOtherAccount = value; } + bool isImagepUploading = false; + + bool get getIsImagepUploading => isImagepUploading; + + set setIsImagepUploading(bool value) { + isImagepUploading = value; + notifyListeners(); + } + Country? userCountries; Cities? userCities; @@ -198,11 +207,13 @@ class UserVM extends BaseVM { notifyListeners(); } - Future performCompleteProfile(BuildContext context, { + Future performCompleteProfile( + BuildContext context, { required String password, required String confirmPassword, required String firstName, required String lastName, + required String companyName, required String email, required String? userId, bool isNeedToPassToken = false, @@ -212,15 +223,7 @@ class UserVM extends BaseVM { if (Utils.passwordValidateStructure(password)) { if (password == confirmPassword) { Utils.showLoading(context); - RegisterUserRespModel user = await userRepo.basicComplete( - userId ?? "", - firstName, - lastName, - email, - password, - cityID, - genderID, - isNeedToPassToken: isNeedToPassToken); + RegisterUserRespModel user = await userRepo.basicComplete(userId ?? "", firstName, lastName, companyName, email, password, cityID, genderID, isNeedToPassToken: isNeedToPassToken); Utils.hideLoading(context); if (user.messageStatus == 1) { Utils.showToast(LocaleKeys.successfullyRegistered.tr()); @@ -242,6 +245,7 @@ class UserVM extends BaseVM { required String password, required String? firstName, required String? lastName, + required String? companyName, required String? email, required DropValue? city, required DropValue? gender, @@ -255,6 +259,11 @@ class UserVM extends BaseVM { Utils.showToast(LocaleKeys.surnameNameMandatory.tr()); //("Surname is mandatory"); isValid = false; + } else if (companyName!.isEmpty) { + if (AppState().currentAppType == AppType.provider) { + Utils.showToast(LocaleKeys.companyNameMandatory.tr()); + isValid = false; + } } else if (email!.isNotEmpty) { if (!Utils.isEmailValid(email)) { Utils.showToast(LocaleKeys.enterValidEmail.tr()); @@ -582,17 +591,18 @@ class UserVM extends BaseVM { type == ClassType.NUMBER && countryCode != null ? countryCode + phoneNum : type == ClassType.NUMBER && countryCode == null - ? phoneNum - : phoneNum, + ? phoneNum + : phoneNum, password); + Utils.hideLoading(context); LoginPasswordRespModel user = LoginPasswordRespModel.fromJson(jsonDecode(response.body)); if (user.messageStatus == 1) { SharedPrefManager.setPhoneOrEmail(type == ClassType.NUMBER && countryCode != null ? countryCode + phoneNum : type == ClassType.NUMBER && countryCode == null - ? phoneNum - : phoneNum); + ? phoneNum + : phoneNum); SharedPrefManager.setUserPassword(password); navigateReplaceWithName(context, AppRoutes.loginMethodSelection, arguments: user.data!.userToken); } else { @@ -683,9 +693,22 @@ class UserVM extends BaseVM { Future updateUserImage(BuildContext context) async { File? myPick = await commanServices.pickFile(context, fileType: FileType.image); if (myPick != null) { - await userRepo.updateUserImage(encodeBase64Image(myPick)); - AppState().getUser.data!.userInfo!.userLocalImage = myPick; - notifyListeners(); + setIsImagepUploading = true; + ImageResponse image = await userRepo.updateUserImage(encodeBase64Image(myPick)); + print(image.message); + print(image.messageStatus); + + if (image.messageStatus == 1) { + UserInfo user = AppState().getUser.data!.userInfo!; + user.userLocalImage = myPick; + AppState().setUser = User(data: UserData(userInfo: user)); + setIsImagepUploading = false; + notifyListeners(); + } else { + Utils.showToast(image.message!); + setIsImagepUploading = false; + notifyListeners(); + } } notifyListeners(); } @@ -718,13 +741,8 @@ class UserVM extends BaseVM { } void changeLanguage(BuildContext context) { - print("${EasyLocalization - .of(context) - ?.currentLocale}"); - if (EasyLocalization - .of(context) - ?.currentLocale - ?.countryCode == "SA") { + print("${EasyLocalization.of(context)?.currentLocale}"); + if (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA") { context.setLocale(const Locale("en", "US")); } else { context.setLocale(const Locale('ar', 'SA')); @@ -749,13 +767,8 @@ class UserVM extends BaseVM { AppState().setUser = null; if (AppState().currentAppType == AppType.provider) { AppState().setproviderSubscription = null; - context - .read() - .mySubscriptionsBySp - .clear(); - context - .read() - .allSubscriptions = SubscriptionModel(); + context.read().mySubscriptionsBySp.clear(); + context.read().allSubscriptions = SubscriptionModel(); } navigateReplaceWithNameUntilRoute(context, AppRoutes.registerSelection); diff --git a/lib/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart b/lib/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart index f0a5a6c..93e66ec 100644 --- a/lib/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart +++ b/lib/views/advertisement/ad_creation_steps/ad_creation_steps_containers.dart @@ -1,7 +1,9 @@ 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/theme/colors.dart'; import 'package:mc_common_app/widgets/common_widgets/dotted_rect.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class DottedRoundedCard extends StatelessWidget { final Function() onTap; @@ -26,7 +28,7 @@ class DottedRoundedCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ icon, - SizedBox(width: 8), + const SizedBox(width: 8), text.toText( fontSize: 15, isBold: true, @@ -44,34 +46,46 @@ class DottedRectContainer extends StatelessWidget { final Function() onTap; final String text; final Widget icon; + final String extensions; - const DottedRectContainer({Key? key, required this.onTap, required this.text, required this.icon}) : super(key: key); + const DottedRectContainer({Key? key, required this.onTap, required this.text, required this.icon, required this.extensions}) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: onTap, - child: Container( - height: 46, - width: double.infinity, - color: MyColors.white, - child: DashedRect( - color: MyColors.lightIconColor, - strokeWidth: 2.0, - gap: 4.0, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Column( + children: [ + DashedRect( + color: MyColors.lightIconColor, + strokeWidth: 2.0, + gap: 4.0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + icon, + const SizedBox(width: 8), + text + .toText( + fontSize: 15, + isBold: true, + color: MyColors.darkPrimaryColor, + ) + .paddingAll(6), + ], + ), + ), + 8.height, + Row( + mainAxisAlignment: MainAxisAlignment.end, children: [ - icon, - SizedBox(width: 8), - text.toText( - fontSize: 15, - isBold: true, - color: MyColors.darkPrimaryColor, + "( $extensions )".toText( + fontSize: 8, + color: MyColors.lightTextColor, ), ], - ), - ), + ) + ], ), ); } diff --git a/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart b/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart index a1501c5..ac6ea39 100644 --- a/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart +++ b/lib/views/advertisement/ad_creation_steps/vehicle_details_container.dart @@ -300,6 +300,7 @@ class VehicleDetails extends StatelessWidget { onTap: () => context.read().pickMultipleImages(), text: LocaleKeys.attachImage.tr(), icon: MyAssets.attachmentIcon.buildSvg(), + extensions: GlobalConsts.allowedFileExtensions, ), ], if (adVM.vehicleImageError != "") ...[ diff --git a/lib/views/chat/widgets/chat_message_widget.dart b/lib/views/chat/widgets/chat_message_widget.dart index 1b0fe88..98be862 100644 --- a/lib/views/chat/widgets/chat_message_widget.dart +++ b/lib/views/chat/widgets/chat_message_widget.dart @@ -12,6 +12,7 @@ import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/models/requests_models/request_model.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/date_helper.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'; @@ -739,7 +740,8 @@ class _ChatMessageCustomWidgetState extends State { requestVM.updateOfferPrice((offer.price ?? "").toString()); requestVM.updateServiceItem((offer.serviceItemName ?? "").toString()); requestVM.updateItemManufacturer((offer.manufacturedByName ?? "").toString()); - requestVM.updateServiceItemCreatedOn((offer.manufacturedOn ?? "").toString()); + requestVM.updateServiceItemCreatedOn(DateHelper.formatAsDayMonthYear(DateHelper.parseStringToDate(DateHelper.formatDateT(offer.manufacturedOn.toString() ?? "")))); + requestVM.updateOfferDescription((widget.chatMessageModel.chatText ?? "").toString()); requestVM.updateIsDeliveryAvailableStatus((offer.isDeliveryAvailable ?? false)); if (offer.reqOfferImages != null && offer.reqOfferImages!.isNotEmpty) { diff --git a/lib/views/profile/profile_view.dart b/lib/views/profile/profile_view.dart index d555ad5..8fbbc7d 100644 --- a/lib/views/profile/profile_view.dart +++ b/lib/views/profile/profile_view.dart @@ -48,9 +48,6 @@ class _ProfileScreenState extends State { String freeTrialName = ""; if (AppState().currentAppType == AppType.provider && AppState().getproviderSubscription.isNotEmpty) { mySubscription = AppState().getproviderSubscription.first; - log("mySubscription!.dateStart.toString(): ${mySubscription!.dateStart}"); - log("mySubscription!.dateEnd.toString(): ${mySubscription!.dateEnd}"); - if (mySubscription!.id == 1) { freeTrialName = mySubscription!.name ?? ""; } else { @@ -176,32 +173,40 @@ class _ProfileScreenState extends State { height: 100, alignment: Alignment.centerLeft, child: ClipOval( - child: AppState().getUser.data!.userInfo!.userLocalImage != null - ? Image.file( - AppState().getUser.data!.userInfo!.userLocalImage!, + child: model.isImagepUploading + ? SizedBox( width: 100, height: 100, - fit: BoxFit.fill, + child: Center( + child: CircularProgressIndicator(), + ).toCircle(borderRadius: 100), ) - : CachedNetworkImage( - imageUrl: "${AppState().getUser.data!.userInfo!.userImageUrl}", - imageBuilder: (context, imageProvider) => Container( - decoration: BoxDecoration( - image: DecorationImage( - image: imageProvider, - fit: BoxFit.cover, + : AppState().getUser.data!.userInfo!.userLocalImage != null + ? Image.file( + AppState().getUser.data!.userInfo!.userLocalImage!, + width: 100, + height: 100, + fit: BoxFit.fill, + ) + : CachedNetworkImage( + imageUrl: "${AppState().getUser.data!.userInfo!.userImageUrl}", + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), ), + placeholder: (context, url) => const Center(child: CircularProgressIndicator()), + errorWidget: (context, url, error) => const Icon(Icons.error), + width: 100, + height: 100, + fit: BoxFit.fill, + fadeInCurve: Curves.easeIn, + fadeInDuration: const Duration(milliseconds: 1000), + useOldImageOnUrlChange: false, ), - ), - placeholder: (context, url) => const Center(child: CircularProgressIndicator()), - errorWidget: (context, url, error) => const Icon(Icons.error), - width: 100, - height: 100, - fit: BoxFit.fill, - fadeInCurve: Curves.easeIn, - fadeInDuration: const Duration(milliseconds: 1000), - useOldImageOnUrlChange: false, - ), ), ).horPaddingMain(), ), diff --git a/lib/views/requests/create_request_page.dart b/lib/views/requests/create_request_page.dart index 555defb..773232b 100644 --- a/lib/views/requests/create_request_page.dart +++ b/lib/views/requests/create_request_page.dart @@ -239,6 +239,7 @@ class CreateRequestPage extends StatelessWidget { onTap: () => context.read().pickMultipleImages(), text: LocaleKeys.attachImage.tr(), icon: MyAssets.attachmentIcon.buildSvg(), + extensions: GlobalConsts.allowedFileExtensions, ), ], if (requestsVM.vehicleImageError != "") ...[ diff --git a/lib/views/requests/request_bottomsheets.dart b/lib/views/requests/request_bottomsheets.dart index 0a358d3..ab737c6 100644 --- a/lib/views/requests/request_bottomsheets.dart +++ b/lib/views/requests/request_bottomsheets.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'package:flutter/cupertino.dart'; 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/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; @@ -9,6 +10,7 @@ import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/chat_models/chat_message_model.dart'; import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/date_helper.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'; @@ -66,20 +68,27 @@ Future buildSendOfferBottomSheet({ if (requestDetail.requestType == RequestsTypeEnum.serviceRequest.getIdFromRequestTypeEnum()) ...[ 12.height, TxtField( - value: requestsVM.itemManufacturer, + onTap: () {}, + isNeedClickAll: true, + isButtonEnable: false, + isBackgroundEnabled: true, + value: "${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName}", errorValue: requestsVM.offerPriceError, hint: LocaleKeys.createdBy.tr(), onChanged: (v) => requestsVM.updateItemManufacturer(v), ), 12.height, TxtField( + isButtonEnable: false, + isBackgroundEnabled: true, errorValue: "", hint: LocaleKeys.createdOn.tr(), - value: requestsVM.serviceItemCreatedOn, + value: DateHelper.formatAsYearMonthDay(DateTime.now()), isNeedClickAll: true, postfixData: Icons.calendar_month_rounded, postFixDataColor: MyColors.darkTextColor, onTap: () async { + return; final formattedDate = await Utils.pickDateFromDatePicker(context, firstDate: DateTime(2020), lastDate: DateTime.now()); requestsVM.updateServiceItemCreatedOn(formattedDate); }, @@ -126,6 +135,7 @@ Future buildSendOfferBottomSheet({ onTap: () => context.read().pickMultipleImages(), text: LocaleKeys.attachImage.tr(), icon: MyAssets.attachmentIcon.buildSvg(), + extensions: GlobalConsts.allowedFileExtensions, ), ], if (requestsVM.pickedVehicleImages.isNotEmpty) ...[ @@ -145,6 +155,10 @@ Future buildSendOfferBottomSheet({ title: offerId == null ? LocaleKeys.submit.tr() : LocaleKeys.update.tr(), maxHeight: 55, onPressed: () { + requestsVM.updateItemManufacturer( + "${AppState().getUser.data!.userInfo!.firstName} ${AppState().getUser.data!.userInfo!.lastName}", + ); + requestsVM.updateServiceItemCreatedOn(DateHelper.formatAsYearMonthDay(DateTime.now())); if (offerId == null) { requestsVM.onSendOfferPressed( context: context, diff --git a/lib/views/setting_options/provider_license_page.dart b/lib/views/setting_options/provider_license_page.dart index d4501fc..e100e8d 100644 --- a/lib/views/setting_options/provider_license_page.dart +++ b/lib/views/setting_options/provider_license_page.dart @@ -235,6 +235,7 @@ class _ProviderLicensePageState extends State { onTap: () => serviceVM.pickPdfReceiptFile(context, document.documentId!, index) ?? "", text: LocaleKeys.attachPDF.tr(), icon: MyAssets.attachmentIcon.buildSvg(), + extensions: GlobalConsts.allowedFileExtensionsPDF, ), ] ], diff --git a/lib/views/user/complete_profile_page.dart b/lib/views/user/complete_profile_page.dart index 0ce12a0..7b013b5 100644 --- a/lib/views/user/complete_profile_page.dart +++ b/lib/views/user/complete_profile_page.dart @@ -6,6 +6,7 @@ import 'package:mc_common_app/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; import 'package:mc_common_app/models/user_models/register_user.dart'; +import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/view_models/user_view_model.dart'; import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; @@ -27,10 +28,7 @@ class CompleteProfilePage extends StatefulWidget { } class _CompleteProfilePageState extends State { - String? firstName = "", - lastName = "", - email = "", - confirmPassword = ""; + String? firstName = "", lastName = "", email = "", confirmPassword = "", companyName = ""; late String password = ""; bool isChecked = false; DropValue? city; @@ -41,231 +39,234 @@ class _CompleteProfilePageState extends State { super.initState(); } - - @override Widget build(BuildContext context) { + context.read().getAllCitiesForUser(AppState().getUserRegisterCountrySelection.id); return Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { - userVM.getAllCitiesForUser(AppState().getUserRegisterCountrySelection.id); return Scaffold( - appBar: CustomAppBar( - isRemoveBackButton: widget.user.data!.roleId == 7 ? false : true, - title: widget.user.data!.roleId == 7 ? "" : LocaleKeys.signUp.tr(), - ), - body: SizedBox( - width: double.infinity, - height: double.infinity, - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - 6.height, - LocaleKeys.completeProfile.tr().toText( - height: 23 / 24, - fontSize: 24, - letterSpacing: -1.44, - ), - 12.height, - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: LocaleKeys.profileMsg.tr().toText( - color: MyColors.lightTextColor, - textAlign: TextAlign.center, - fontSize: 14, + appBar: CustomAppBar( + isRemoveBackButton: widget.user.data!.roleId == 7 ? false : true, + title: widget.user.data!.roleId == 7 ? "" : LocaleKeys.signUp.tr(), + ), + body: SizedBox( + width: double.infinity, + height: double.infinity, + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + 6.height, + LocaleKeys.completeProfile.tr().toText( height: 23 / 24, - letterSpacing: -0.48, + fontSize: 24, + letterSpacing: -1.44, ), - ), - 12.height, - TxtField( - hint: LocaleKeys.firstName.tr(), - value: firstName, - onChanged: (v) { - firstName = v; - }, - ), + 12.height, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: LocaleKeys.profileMsg.tr().toText( + color: MyColors.lightTextColor, + textAlign: TextAlign.center, + fontSize: 14, + height: 23 / 24, + letterSpacing: -0.48, + ), + ), + 12.height, + TxtField( + hint: LocaleKeys.firstName.tr(), + value: firstName, + onChanged: (v) { + firstName = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.surname.tr(), + value: lastName, + onChanged: (v) { + lastName = v; + }, + ), + if (AppState().currentAppType == AppType.provider) ...[ 12.height, TxtField( - hint: LocaleKeys.surname.tr(), - value: lastName, + hint: LocaleKeys.companyName.tr(), + value: companyName, onChanged: (v) { - lastName = v; + companyName = v; }, ), - 12.height, - Container( - padding: const EdgeInsets.only(right: 0, left: 0, top: 0, bottom: 0), - child: Builder(builder: (context) { - List userGender = []; - userGender.add(DropValue(1.toInt(), "${LocaleKeys.userMale.tr()}", "", isEnabled: true)); - userGender.add(DropValue(2.toInt(), "${LocaleKeys.userFemale.tr()}", "", isEnabled: true)); - // for (var element in userVM.userCities!.data!) { - // if (AppState().getUser.data != null) { - // if (AppState().getUser.data!.userInfo!.cityId == element.id) { - // city = DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""); - // } - // } - // - // } - return DropdownField( - (DropValue value) { - gender = value; - setState(() {}); - }, - list: userGender, - dropdownValue: gender != null && gender != -1 ? DropValue(gender!.id, gender!.value, "") : null, - hint: gender != null && gender != -1 ? gender!.value : "${LocaleKeys.userGender.tr()} *", - // errorValue: adVM.vehicleCountryId.errorValue, - ); - })), - 12.height, - TxtField( - hint: LocaleKeys.email.tr(), - value: email, - // isButtonEnable: email!.length > 0 ? true : false, - buttonTitle: LocaleKeys.verify.tr(), - onChanged: (v) { - email = v; - }, - ), - 12.height, - userVM.userCities != null - ? Container( - padding: const EdgeInsets.only(right: 0, left: 0, top: 0, bottom: 0), - child: Builder(builder: (context) { - List userCityDrop = []; - for (var element in userVM.userCities!.data!) { - if (AppState().getUser.data != null) { - if (AppState().getUser.data!.userInfo!.cityId == element.id) { - city = DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""); + ], + 12.height, + Container( + padding: const EdgeInsets.only(right: 0, left: 0, top: 0, bottom: 0), + child: Builder(builder: (context) { + List userGender = []; + userGender.add(DropValue(1.toInt(), "${LocaleKeys.userMale.tr()}", "", isEnabled: true)); + userGender.add(DropValue(2.toInt(), "${LocaleKeys.userFemale.tr()}", "", isEnabled: true)); + // for (var element in userVM.userCities!.data!) { + // if (AppState().getUser.data != null) { + // if (AppState().getUser.data!.userInfo!.cityId == element.id) { + // city = DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""); + // } + // } + // + // } + return DropdownField( + (DropValue value) { + gender = value; + setState(() {}); + }, + list: userGender, + dropdownValue: gender != null && gender != -1 ? DropValue(gender!.id, gender!.value, "") : null, + hint: gender != null && gender != -1 ? gender!.value : "${LocaleKeys.userGender.tr()} *", + // errorValue: adVM.vehicleCountryId.errorValue, + ); + })), + 12.height, + TxtField( + hint: LocaleKeys.email.tr(), + value: email, + // isButtonEnable: email!.length > 0 ? true : false, + buttonTitle: LocaleKeys.verify.tr(), + onChanged: (v) { + email = v; + }, + ), + 12.height, + userVM.userCities != null + ? Container( + padding: const EdgeInsets.only(right: 0, left: 0, top: 0, bottom: 0), + child: Builder(builder: (context) { + List userCityDrop = []; + for (var element in userVM.userCities!.data!) { + if (AppState().getUser.data != null) { + if (AppState().getUser.data!.userInfo!.cityId == element.id) { + city = DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""); + } } + userCityDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", "")); } - userCityDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", "")); - } - return DropdownField( - (DropValue value) { - city = value; - setState(() {}); - }, - list: userCityDrop, - dropdownValue: city != null && city != -1 ? DropValue(city!.id, city!.value, "") : null, - hint: city != null && city != -1 ? city!.value : "${LocaleKeys.city.tr()} *", - // errorValue: adVM.vehicleCountryId.errorValue, - ); - })) - : SizedBox(), - 12.height, - TxtField( - hint: LocaleKeys.createPass.tr(), - isPasswordEnabled: true, - maxLines: 1, - value: password, - onChanged: (v) { - password = v; - }, - ), - 12.height, - TxtField( - hint: LocaleKeys.confirmPass.tr(), - isPasswordEnabled: true, - maxLines: 1, - value: confirmPassword, - onChanged: (v) { - confirmPassword = v; - }, - ), - 50.height, - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { - return Checkbox( - value: userVM.completeProfilePageCheckbox, - activeColor: MyColors.darkPrimaryColor, - onChanged: (value) { - userVM.updateCompleteProfilePageCheckbox(value!); - }, - ); + return DropdownField( + (DropValue value) { + city = value; + setState(() {}); + }, + list: userCityDrop, + dropdownValue: city != null && city != -1 ? DropValue(city!.id, city!.value, "") : null, + hint: city != null && city != -1 ? city!.value : "${LocaleKeys.city.tr()} *", + // errorValue: adVM.vehicleCountryId.errorValue, + ); + })) + : SizedBox(), + 12.height, + TxtField( + hint: LocaleKeys.createPass.tr(), + isPasswordEnabled: true, + maxLines: 1, + value: password, + onChanged: (v) { + password = v; + }, + ), + 12.height, + TxtField( + hint: LocaleKeys.confirmPass.tr(), + isPasswordEnabled: true, + maxLines: 1, + value: confirmPassword, + onChanged: (v) { + confirmPassword = v; + }, + ), + 50.height, + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { + return Checkbox( + value: userVM.completeProfilePageCheckbox, + activeColor: MyColors.darkPrimaryColor, + onChanged: (value) { + userVM.updateCompleteProfilePageCheckbox(value!); + }, + ); + }), + Expanded( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: LocaleKeys.termsOfService.tr(), + style: const TextStyle(fontSize: 12, fontWeight: MyFonts.Medium), + ), + TextSpan( + text: " ${LocaleKeys.terms.tr()}", + style: const TextStyle( + decoration: TextDecoration.underline, + fontSize: 12, + color: MyColors.darkPrimaryColor, + fontWeight: MyFonts.Bold, + )) + ], + ), + ).onPress(() { + navigateWithName(context, AppRoutes.settingOptionsTermsAndConditions); }), - Expanded( - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: LocaleKeys.termsOfService.tr(), - style: const TextStyle(fontSize: 12, fontWeight: MyFonts.Medium), - ), - TextSpan( - text: " ${LocaleKeys.terms.tr()}", - style: const TextStyle( - decoration: TextDecoration.underline, - fontSize: 12, - color: MyColors.darkPrimaryColor, - fontWeight: MyFonts.Bold, - )) - ], - ), - ).onPress(() { - navigateWithName(context, AppRoutes.settingOptionsTermsAndConditions); - }), - ) - // Column( - // children: [ - // LocaleKeys.termsOfService.tr().toText(fontSize: 12), - // LocaleKeys.terms.tr().toText(fontSize: 12, color: MyColors.darkPrimaryColor), - // ], - // ), - // Theme( - // data: ThemeData(unselectedWidgetColor: Colors.transparent), - // child: Checkbox( - // value: false, - // onChanged: (_) {}, - // ), - // ) - ], - ), - 16.height, - Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { - return ShowFillButton( - title: LocaleKeys.save.tr(), - maxWidth: double.infinity, - isDisabled: !userVM.completeProfilePageCheckbox, - onPressed: () { - if (!userVM.completeProfilePageCheckbox) { - return; - } - bool validateStatus = userVM.dataValidation(password: password, - firstName: firstName, - lastName: lastName, - email: email, - city: city, - gender: gender); - if (validateStatus) { - userVM.performCompleteProfile( - context, - password: password, - confirmPassword: confirmPassword!, - firstName: firstName!, - lastName: lastName!, - email: email!, - userId: widget.user.data!.userId ?? "", - isNeedToPassToken: widget.user.data!.isNeedToPassToken, - cityID: city!.id.toString(), - genderID: gender!.id.toString(), - ); - } - }); - }), - 16.height, - ], - ), + ) + // Column( + // children: [ + // LocaleKeys.termsOfService.tr().toText(fontSize: 12), + // LocaleKeys.terms.tr().toText(fontSize: 12, color: MyColors.darkPrimaryColor), + // ], + // ), + // Theme( + // data: ThemeData(unselectedWidgetColor: Colors.transparent), + // child: Checkbox( + // value: false, + // onChanged: (_) {}, + // ), + // ) + ], + ), + 16.height, + Consumer(builder: (BuildContext context, UserVM userVM, Widget? child) { + return ShowFillButton( + title: LocaleKeys.save.tr(), + maxWidth: double.infinity, + isDisabled: !userVM.completeProfilePageCheckbox, + onPressed: () { + if (!userVM.completeProfilePageCheckbox) { + return; + } + bool validateStatus = userVM.dataValidation(password: password, firstName: firstName, lastName: lastName, companyName: companyName, email: email, city: city, gender: gender); + if (validateStatus) { + userVM.performCompleteProfile( + context, + password: password, + confirmPassword: confirmPassword!, + firstName: firstName!, + lastName: lastName!, + companyName: companyName!, + email: email!, + userId: widget.user.data!.userId ?? "", + isNeedToPassToken: widget.user.data!.isNeedToPassToken, + cityID: city!.id.toString(), + genderID: gender!.id.toString(), + ); + } + }); + }), + 16.height, + ], ), ), ), - ); - } - ); + ), + ); + }); } } diff --git a/lib/widgets/bottom_sheet.dart b/lib/widgets/bottom_sheet.dart index 9580d58..88b5c52 100644 --- a/lib/widgets/bottom_sheet.dart +++ b/lib/widgets/bottom_sheet.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; -void showMyBottomSheet(BuildContext context, {bool isDismissible = true,bool isScrollControlled = true, required Widget child, VoidCallback? callBackFunc}) { +void showMyBottomSheet(BuildContext context, {bool isDismissible = true, bool isScrollControlled = true, required Widget child, VoidCallback? callBackFunc}) { showModalBottomSheet( context: context, isScrollControlled: true, diff --git a/lib/widgets/common_widgets/add_phone_num_wiget.dart b/lib/widgets/common_widgets/add_phone_num_wiget.dart index 3b5b7a3..ca9e0f3 100644 --- a/lib/widgets/common_widgets/add_phone_num_wiget.dart +++ b/lib/widgets/common_widgets/add_phone_num_wiget.dart @@ -1,7 +1,10 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/gestures.dart'; 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/extensions/int_extensions.dart'; import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/generated/locale_keys.g.dart'; @@ -12,6 +15,7 @@ import 'package:mc_common_app/utils/utils.dart'; import 'package:mc_common_app/view_models/user_view_model.dart'; import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:mc_common_app/widgets/txt_field.dart'; import 'package:provider/provider.dart'; @@ -24,13 +28,13 @@ class AddPhoneNumWidget extends StatefulWidget { class _AddPhoneNumWidgetState extends State { String phoneNum = "", countryCode = ""; + DropValue? countryCodeVal; late UserVM userVM; Country? _country; @override void initState() { super.initState(); - scheduleMicrotask(() { userVM = Provider.of(context, listen: false); getCountryList(); @@ -56,7 +60,25 @@ class _AddPhoneNumWidgetState extends State { children: [ "Enter Phone Number".toText(fontSize: 16, isBold: true), 8.height, - getCountry(context), + Container( + decoration: Utils.containerColorRadiusBorderWidth(MyColors.white, 0, MyColors.darkPrimaryColor, 2), + margin: const EdgeInsets.all(0), + padding: const EdgeInsets.only(left: 8, right: 8), + width: null, + child: Row( + children: [ + if (countryCode.isEmpty) ...[ + LocaleKeys.selectCountryCode.tr().toText(color: borderColor, fontSize: 15, fontWeight: MyFonts.Medium).paddingOnly(top: 12, bottom: 12), + ] else ...[ + countryCode.toText(fontSize: 15, fontWeight: MyFonts.Medium).paddingOnly(top: 12, bottom: 12), + ] + ], + ), + ).onPress(() { + if (_country != null) { + getCountry(context); + } + }), 8.height, TxtField( keyboardType: TextInputType.phone, @@ -103,24 +125,20 @@ class _AddPhoneNumWidgetState extends State { ); } - Widget getCountry(BuildContext context) { - if (_country != null) { - List dropList = []; - _country!.data?.forEach((element) { - dropList.add(DropValue(element.id ?? 0, "${element.countryName ?? ""} ${element.countryCode ?? ""}", element.countryCode ?? "")); - }); - return DropdownField( - (DropValue value) { + void getCountry(BuildContext context) { + List dropList = []; + _country!.data?.forEach((element) { + dropList.add(DropValue(element.id ?? 0, "${element.countryName ?? ""} ${element.countryCode ?? ""}", element.countryCode ?? "")); + }); + return showCustomBottomPicker( + items: dropList, + onItemSelected: (value) { + AppState().setUserRegisterCountrySelection = value; countryCode = value.subValue; + countryCodeVal = value; + setState(() {}); }, - list: dropList, - hint: countryCode.isNotEmpty ? countryCode.toString() : LocaleKeys.selectCountryCode.tr(), - ); - } else { - return const Center( - child: CircularProgressIndicator(), - ); - } + context: context); } bool validation() { @@ -137,3 +155,73 @@ class _AddPhoneNumWidgetState extends State { return isValid; } } + +class CustomBottomPicker extends StatelessWidget { + final List items; + final void Function(DropValue selectedItem) onItemSelected; + + const CustomBottomPicker({ + Key? key, + required this.items, + required this.onItemSelected, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + color: Colors.black.withOpacity(0.4), + child: DraggableScrollableSheet( + initialChildSize: 0.2, + maxChildSize: 0.4, + minChildSize: 0.2, + expand: true, + builder: (context, scrollController) { + return Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + child: ListView.builder( + controller: scrollController, + itemCount: items.length, + shrinkWrap: true, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + return ListTile( + title: Text(items[index].value), + onTap: () { + onItemSelected(items[index]); + Navigator.of(context).pop(); + }, + ); + }, + ), + ); + }, + ), + ), + ); + } +} + +// Function to show the bottom picker +void showCustomBottomPicker({ + required BuildContext context, + required List items, + required void Function(DropValue selectedItem) onItemSelected, +}) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, + backgroundColor: Colors.transparent, + builder: (context) { + return CustomBottomPicker( + items: items, + onItemSelected: onItemSelected, + ); + }, + ); +} diff --git a/lib/widgets/common_widgets/app_bar.dart b/lib/widgets/common_widgets/app_bar.dart index da6c90f..aa9314f 100644 --- a/lib/widgets/common_widgets/app_bar.dart +++ b/lib/widgets/common_widgets/app_bar.dart @@ -8,7 +8,9 @@ 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/view_models/user_view_model.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { final Color? backgroundColor; @@ -58,81 +60,79 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { toolbarHeight: toolbarHeight, leading: isDrawerEnabled ? InkWell( - onTap: onTap, - child: Row( - children: [ - profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userLocalImage != null - ? Image.file( - AppState().getUser.data!.userInfo!.userLocalImage!, - width: 34, - height: 34, - fit: BoxFit.fill, - ).toCircle(borderRadius: 100) - : profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userImageUrl != null - ? CachedNetworkImage( - imageUrl: AppState().getUser.data!.userInfo!.userImageUrl, - imageBuilder: (context, imageProvider) => - Container( - decoration: BoxDecoration( - image: DecorationImage( - image: imageProvider, - fit: BoxFit.cover, - ), - ), - ), - placeholder: (context, url) => const Center(child: CircularProgressIndicator()), - errorWidget: (context, url, error) => const Icon(Icons.supervised_user_circle_outlined), - fadeInCurve: Curves.easeIn, - width: 34, - height: 34, - fit: BoxFit.fill, - fadeInDuration: const Duration(milliseconds: 1000), - useOldImageOnUrlChange: false) - .toCircle(borderRadius: 100) - : Image.asset( - MyAssets.carBanner, - width: 34, - height: 34, - fit: BoxFit.fill, - ).toCircle(borderRadius: 100), - 10.width, - SvgPicture.asset(MyAssets.dashboardDrawerIcon), - ], - ).paddingOnly(left: 21), - ) + onTap: onTap, + child: Row( + children: [ + Consumer(builder: (BuildContext context, UserVM uvm, Widget? child) { + return profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userLocalImage != null + ? Image.file( + AppState().getUser.data!.userInfo!.userLocalImage!, + width: 34, + height: 34, + fit: BoxFit.fill, + ).toCircle(borderRadius: 100) + : profileImageUrl.isEmpty && AppState().getUser.data!.userInfo!.userImageUrl != null + ? CachedNetworkImage( + imageUrl: AppState().getUser.data!.userInfo!.userImageUrl, + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + image: DecorationImage( + image: imageProvider, + fit: BoxFit.cover, + ), + ), + ), + placeholder: (context, url) => const Center(child: CircularProgressIndicator()), + errorWidget: (context, url, error) => const Icon(Icons.supervised_user_circle_outlined), + fadeInCurve: Curves.easeIn, + width: 34, + height: 34, + fit: BoxFit.fill, + fadeInDuration: const Duration(milliseconds: 1000), + useOldImageOnUrlChange: false) + .toCircle(borderRadius: 100) + : Image.asset( + MyAssets.carBanner, + 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, - const Icon(Icons.arrow_back_ios, color: Colors.black, size: 16) - .toContainer( - padding: const EdgeInsets.only(left: 5), - borderRadius: 100, - borderColor: MyColors.lightGreyEFColor, - isEnabledBorder: true, - height: 40, - width: 40, - ) - .onPress(() { - if (onBackButtonTapped != null) { - onBackButtonTapped!(); - } else { - Navigator.pop(context); - } - }), - ], - ), + ? null + : Row( + children: [ + 21.width, + const Icon(Icons.arrow_back_ios, color: Colors.black, size: 16) + .toContainer( + padding: const EdgeInsets.only(left: 5), + borderRadius: 100, + borderColor: MyColors.lightGreyEFColor, + isEnabledBorder: true, + height: 40, + width: 40, + ) + .onPress(() { + if (onBackButtonTapped != null) { + onBackButtonTapped!(); + } else { + Navigator.pop(context); + } + }), + ], + ), iconTheme: IconThemeData( color: backIconColor ?? Colors.black, //change your color here ), actions: actions, title: (title ?? "").toText(fontSize: 20), ), - if (backgroundColor == null) - const Divider( - thickness: 1, - height: 1) + if (backgroundColor == null) const Divider(thickness: 1, height: 1) ], ); } diff --git a/lib/widgets/common_widgets/branch_details_card.dart b/lib/widgets/common_widgets/branch_details_card.dart index d1f0359..87013e0 100644 --- a/lib/widgets/common_widgets/branch_details_card.dart +++ b/lib/widgets/common_widgets/branch_details_card.dart @@ -68,10 +68,11 @@ class BranchDetailCard extends StatelessWidget { ], if (providerName != null) Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ ("${LocaleKeys.provider.tr()}:").toText(color: MyColors.lightTextColor, fontSize: 12), 4.width, - providerName!.toText(fontSize: 12, isBold: true), + Flexible(child: providerName!.toText(fontSize: 12, isBold: true),) ], ), ], diff --git a/lib/widgets/dropdown/dropdow_field.dart b/lib/widgets/dropdown/dropdow_field.dart index f3d4b95..c8c75ce 100644 --- a/lib/widgets/dropdown/dropdow_field.dart +++ b/lib/widgets/dropdown/dropdow_field.dart @@ -28,6 +28,7 @@ class DropdownField extends StatefulWidget { final List? list; final DropValue? dropdownValue; final Function(DropValue) onSelect; + final Function()? onTap; final bool showAppointmentPickerVariant; final TextStyle? textStyle; final bool isSelectAble; @@ -50,6 +51,7 @@ class _DropdownFieldState extends State { super.initState(); } + @override Widget build(BuildContext context) { dropdownValue = widget.dropdownValue; @@ -58,13 +60,19 @@ class _DropdownFieldState extends State { IgnorePointer( ignoring: !widget.isSelectAble, child: Container( - decoration: widget.showAppointmentPickerVariant ? null : Utils.containerColorRadiusBorderWidth(MyColors.white, 0, widget.isSelectAble ? MyColors.darkPrimaryColor : MyColors.greyACColor, 2), + decoration: + widget.showAppointmentPickerVariant ? null : Utils.containerColorRadiusBorderWidth(MyColors.white, 0, widget.isSelectAble ? MyColors.darkPrimaryColor : MyColors.greyACColor, 2), margin: const EdgeInsets.all(0), padding: const EdgeInsets.only(left: 8, right: 8), width: widget.showAppointmentPickerVariant ? 170 : null, child: DropdownButton( value: dropdownValue, - icon: Icon(Icons.keyboard_arrow_down_sharp, color: !widget.isSelectAble ? Colors.transparent : null, size: 21,), + icon: Icon( + Icons.keyboard_arrow_down_sharp, + color: !widget.isSelectAble ? Colors.transparent : null, + size: 21, + ), + elevation: 16, iconSize: widget.showAppointmentPickerVariant ? 26 : 16, iconEnabledColor: borderColor, @@ -82,6 +90,8 @@ class _DropdownFieldState extends State { widget.onSelect(newValue); }); }, + onTap: widget.onTap, + items: (widget.list ?? defaultV).map>( (DropValue value) { return DropdownMenuItem(