diff --git a/assets/icons/search_icon.svg b/assets/icons/search_icon.svg new file mode 100644 index 0000000..f490a60 --- /dev/null +++ b/assets/icons/search_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index c4861e1..1b6217e 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -169,5 +169,7 @@ "accessories_modifications": "الملحقات والتعديلات", "my_recent_providers": "مزودي الخدمة الجدد", "my_active_ads": "إعلاناتي النشطة", - "recommended_Ads": "الإعلانات الموصى بها" + "recommended_Ads": "الإعلانات الموصى بها", + "location": "موقع" + } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 575756a..a499d5b 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -169,5 +169,8 @@ "accessories_modifications": "Accessories and Modifications", "my_recent_providers": "My Recent Service Providers", "my_active_ads": "My Active Ads", - "recommended_Ads": "Recommended Ads" + "recommended_Ads": "Recommended Ads", + "select_services": "Select services you want", + "location": "Location" + } \ No newline at end of file diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 972c57c..52b2a01 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -109,6 +109,8 @@ class MyAssets { static String icNotification = "${assetPath}images/ic_notification.svg"; static String logo = "${assetPath}images/logo.svg"; static String splashLogo = "${assetPath}images/splash_logo.svg"; + static String searchIcon = "${assetPath}icons/search_icon.svg"; + //PNG static String icWorldPng = "${assetPath}images/ic_world.png"; diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 6e1d741..6ccf08d 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -51,6 +51,8 @@ class AppRoutes { static const String editAccountPage = "/editAccoundPage"; static const String dashboard = "/dashboard"; + static const String bookProviderAppView = "/bookProviderAppView"; + static const String appointmentDetailView = "/appointmentDetailView"; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index ac17df6..ce15754 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -1,10 +1,19 @@ - import 'package:flutter/cupertino.dart'; import 'package:intl/intl.dart'; import 'package:mc_common_app/theme/colors.dart'; extension EmailValidator on String { - Widget toText({Color? color, bool isBold = false, double? fontSize, bool isUnderLine = false, TextDecoration? textDecoration, double letterSpacing = -0.4, TextAlign? textAlign, double? height}) => + Widget toText({ + Color? color, + bool isSemiBold = false, + bool isBold = false, + double? fontSize, + bool isUnderLine = false, + TextDecoration? textDecoration, + double letterSpacing = -0.4, + TextAlign? textAlign, + double? height, + }) => Text( this, textAlign: textAlign, @@ -18,7 +27,6 @@ extension EmailValidator on String { ), ); - bool isValidEmail() { return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this); } diff --git a/lib/views/user/forget_password_page.dart b/lib/views/user/forget_password_page.dart index fedc92d..761dd5c 100644 --- a/lib/views/user/forget_password_page.dart +++ b/lib/views/user/forget_password_page.dart @@ -50,7 +50,7 @@ class _ForgetPasswordPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: CustomAppBar( isRemoveBackButton: true, title: LocaleKeys.changePassword.tr()), + appBar: CustomAppBar(isRemoveBackButton: true, title: LocaleKeys.changePassword.tr()), body: Container( width: double.infinity, height: double.infinity, @@ -135,9 +135,11 @@ class _ForgetPasswordPageState extends State { Widget getCountry() { if (_country != null) { List dropList = []; - _country!.data?.forEach((element) { - dropList.add(DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); - }); + _country!.data?.forEach( + (element) { + dropList.add(DropValue(element.id ?? 0, "${element.countryName ?? ""} ${element.countryCode ?? ""}", element.countryCode ?? "")); + }, + ); return Padding( padding: const EdgeInsets.all(2.0), child: DropdownField((DropValue value) { diff --git a/lib/widgets/common_widgets/app_bar.dart b/lib/widgets/common_widgets/app_bar.dart index bb41f49..31f8fb3 100644 --- a/lib/widgets/common_widgets/app_bar.dart +++ b/lib/widgets/common_widgets/app_bar.dart @@ -91,6 +91,7 @@ class CustomAppBar extends StatelessWidget with PreferredSizeWidget { @override Widget build(BuildContext context) { return AppBar( + automaticallyImplyLeading: false, leadingWidth: 100, backgroundColor: backgroundColor ?? appBackgroundColor, elevation: elevation ?? 0, diff --git a/lib/widgets/common_widgets/categories_list.dart b/lib/widgets/common_widgets/categories_list.dart new file mode 100644 index 0000000..5ddbc0a --- /dev/null +++ b/lib/widgets/common_widgets/categories_list.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; + + +class CategoriesList extends StatelessWidget { + // We will pass a list here! + final String name; + final Function() onTapped; + const CategoriesList({Key? key, required this.name, required this.onTapped}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 37, + width: double.infinity, + child: ListView.builder( + padding: const EdgeInsets.only(left: 12), + itemCount: 20, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + return InkWell( + onTap: onTapped, + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 8), + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: index < 1 ? MyColors.darkIconColor : null, + border: Border.all( + color: index < 1 ? MyColors.darkIconColor : MyColors.primaryColor, + width: 2, + ), + ), + child: name.toText( + fontSize: 12, + color: index < 1 ? MyColors.white : null, + ), + ), + ); + }), + ); + } +} diff --git a/lib/widgets/common_widgets/custom_button.dart b/lib/widgets/common_widgets/custom_button.dart new file mode 100644 index 0000000..469dfc0 --- /dev/null +++ b/lib/widgets/common_widgets/custom_button.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +class CustomButton extends StatelessWidget { + final Function() onTapped; + final Color? backgroundColor; + final String buttonText; + final double? textFontSize; + + final Color textColor; + final bool? isIcon; + final double? buttonHeight; + + const CustomButton({ + Key? key, + required this.onTapped, + required this.buttonText, + this.isIcon = false, + this.backgroundColor = MyColors.primaryColor, + this.textColor = MyColors.white, + this.buttonHeight = 55, + this.textFontSize = 15, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: buttonHeight, + color: backgroundColor, + alignment: Alignment.center, + child: InkWell( + onTap: onTapped, + child: buttonText.toText(fontSize: textFontSize, color: textColor), + ), + ); + } +} diff --git a/lib/widgets/common_widgets/customer_appointment_slider_widget.dart b/lib/widgets/common_widgets/customer_appointment_slider_widget.dart index 16a100f..0c9f995 100644 --- a/lib/widgets/common_widgets/customer_appointment_slider_widget.dart +++ b/lib/widgets/common_widgets/customer_appointment_slider_widget.dart @@ -1,5 +1,6 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.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'; @@ -9,61 +10,6 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class CustomerAppointmentSliderWidget extends StatelessWidget { const CustomerAppointmentSliderWidget({Key? key}) : super(key: key); - Widget buildAppointmentContainerForCustomer() { - return Container( - margin: const EdgeInsets.only(bottom: 21, left: 21, right: 21, top: 7), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset( - MyAssets.bnCar, - width: 56, - height: 56, - fit: BoxFit.fill, - ).toCircle(borderRadius: 100), - 8.width, - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "Al Aziz Service Station".toText(color: MyColors.black, isBold: true, fontSize: 16), - Row( - children: [ - MyAssets.miniClock.buildSvg(height: 12), - 2.width, - "08:00 to 08:30 25 July, 2023".toText( - color: MyColors.lightTextColor, - fontSize: 12, - ), - ], - ), - 9.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - "Appointment Details".toText( - color: MyColors.primaryColor, - isUnderLine: true, - isBold: true, - fontSize: 14, - ), - const Icon(Icons.arrow_forward), - ], - ), - ], - ), - ), - ], - ), - ], - ).toWhiteContainer(width: double.infinity, allPading: 12), - ); - } - @override Widget build(BuildContext context) { return CarouselSlider.builder( @@ -80,7 +26,7 @@ class CustomerAppointmentSliderWidget extends StatelessWidget { // }, ), itemCount: 10, - itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => buildAppointmentContainerForCustomer(), + itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => const BuildAppointmentContainerForCustomer(isForHome: true), ); } @@ -101,3 +47,106 @@ class CustomerAppointmentSliderWidget extends StatelessWidget { ); } } + +class BuildAppointmentContainerForCustomer extends StatelessWidget { + final bool? isForHome; + + const BuildAppointmentContainerForCustomer({Key? key, this.isForHome = false}) : super(key: key); + + Widget showServices(String title, String icon) { + return Row( + children: [ + SvgPicture.asset(icon), + 8.width, + title.toText( + fontSize: 14, + isBold: true, + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.only(bottom: 21, left: 21, right: 21, top: 7), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + isForHome != null && isForHome! + ? Image.asset( + MyAssets.bnCar, + width: 56, + height: 56, + fit: BoxFit.fill, + ).toCircle(borderRadius: 100) + : Image.asset( + MyAssets.bnCar, + width: 80, + height: 85, + fit: BoxFit.cover, + ), + 8.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + "Al Aziz Service Station".toText(color: MyColors.black, isBold: true, fontSize: 16), + Row( + children: [ + MyAssets.miniClock.buildSvg(height: 12), + 2.width, + "08:00 to 08:30 25 July, 2023".toText( + color: MyColors.lightTextColor, + fontSize: 12, + ), + ], + ), + 9.height, + isForHome != null && isForHome! + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "Appointment Details".toText( + color: MyColors.primaryColor, + isUnderLine: true, + isBold: true, + fontSize: 14, + ), + const Icon(Icons.arrow_forward), + ], + ) + : Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Column( + children: [ + showServices("Maintenance", MyAssets.maintenanceIcon), + 2.height, + showServices( + "Accessories and Modification", + MyAssets.modificationsIcon, + ), + ], + ), + ), + const Icon( + Icons.arrow_forward, + ), + ], + ), + ], + ), + ), + ], + ), + ], + ).toWhiteContainer(width: double.infinity, allPading: 12), + ); + } +} diff --git a/lib/widgets/common_widgets/provider_appointment_slider_widget.dart b/lib/widgets/common_widgets/provider_appointment_slider_widget.dart index da4da92..98b93e1 100644 --- a/lib/widgets/common_widgets/provider_appointment_slider_widget.dart +++ b/lib/widgets/common_widgets/provider_appointment_slider_widget.dart @@ -10,7 +10,48 @@ import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; class ProviderAppointmentSliderWidget extends StatelessWidget { const ProviderAppointmentSliderWidget({Key? key}) : super(key: key); - Widget buildAppointmentContainerForProvider() { + + @override + Widget build(BuildContext context) { + return CarouselSlider.builder( + options: CarouselOptions( + height: 160, + viewportFraction: 1.0, + enlargeCenterPage: false, + enableInfiniteScroll: false, + // + // onPageChanged: (index) { + // setState(() { + // _current = index; + // }); + // }, + ), + itemCount: 10, + itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => const BuildAppointmentContainerForProvider(), + ); + } + + +} + +class BuildAppointmentContainerForProvider extends StatelessWidget { + const BuildAppointmentContainerForProvider({Key? key}) : super(key: key); + + Widget showServices(String title, String icon) { + return Row( + children: [ + SvgPicture.asset(icon), + 8.width, + title.toText( + fontSize: 14, + isBold: true, + ), + ], + ); + } + + @override + Widget build(BuildContext context) { return Container( margin: const EdgeInsets.only(bottom: 21, left: 21, right: 21, top: 7), child: Column( @@ -43,13 +84,13 @@ class ProviderAppointmentSliderWidget extends StatelessWidget { ), ), "1+ Requests".toText(fontSize: 10).toContainer( - borderRadius: 15, - backgroundColor: MyColors.lightGreyEAColor, - padding: const EdgeInsets.symmetric( - vertical: 6, - horizontal: 12, - ), - ), + borderRadius: 15, + backgroundColor: MyColors.lightGreyEAColor, + padding: const EdgeInsets.symmetric( + vertical: 6, + horizontal: 12, + ), + ), ], ), 8.height, @@ -74,37 +115,5 @@ class ProviderAppointmentSliderWidget extends StatelessWidget { ).toWhiteContainer(width: double.infinity, allPading: 12), ); } - - @override - Widget build(BuildContext context) { - return CarouselSlider.builder( - options: CarouselOptions( - height: 160, - viewportFraction: 1.0, - enlargeCenterPage: false, - enableInfiniteScroll: false, - // - // onPageChanged: (index) { - // setState(() { - // _current = index; - // }); - // }, - ), - itemCount: 10, - itemBuilder: (BuildContext context, int itemIndex, int pageViewIndex) => buildAppointmentContainerForProvider(), - ); - } - - Widget showServices(String title, String icon) { - return Row( - children: [ - SvgPicture.asset(icon), - 8.width, - title.toText( - fontSize: 14, - isBold: true, - ), - ], - ); - } } + diff --git a/lib/widgets/common_widgets/provider_details_card.dart b/lib/widgets/common_widgets/provider_details_card.dart new file mode 100644 index 0000000..159ea99 --- /dev/null +++ b/lib/widgets/common_widgets/provider_details_card.dart @@ -0,0 +1,118 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/generated/locale_keys.g.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; + +class ProviderDetailsCard extends StatelessWidget { + final String providerImageUrl; + final String providerName; + final String providerLocation; + final String providerRatings; + final Function() onCardTapped; + + const ProviderDetailsCard({ + Key? key, + required this.providerImageUrl, + required this.providerName, + required this.providerRatings, + required this.providerLocation, + required this.onCardTapped, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only( + bottom: 10, + left: 21, + right: 21, + ), + child: Row( + children: [ + Image.asset( + providerImageUrl, + width: 80, + height: 85, + fit: BoxFit.cover, + ), + 12.width, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + providerName.toText(fontSize: 16, isBold: true), + Row( + children: [ + LocaleKeys.location.tr().toText(color: MyColors.lightTextColor, fontSize: 12), + 2.width, + ":$providerLocation".toText(fontSize: 12), + ], + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + providerRatings.toText( + isUnderLine: true, + isBold: true, + fontSize: 12, + ), + 2.width, + MyAssets.starIcon.buildSvg(width: 12), + ], + ), + ], + ), + 8.height, + Row( + children: [ + Expanded( + child: Column( + children: [ + Row( + children: [ + MyAssets.maintenanceIcon.buildSvg(), + 8.width, + LocaleKeys.maintenance.tr().toText( + fontSize: 14, + isBold: true, + ), + ], + ), + Row( + children: [ + MyAssets.modificationsIcon.buildSvg(), + 8.width, + LocaleKeys.accessories_modifications.tr().toText( + fontSize: 14, + isBold: true, + ), + ], + ) + ], + ), + ), + ], + ), + ], + ), + ), + ], + ).onPress(onCardTapped).toWhiteContainer(width: double.infinity, allPading: 12)); + } +} diff --git a/lib/widgets/extensions/extensions_widget.dart b/lib/widgets/extensions/extensions_widget.dart index 4cfcd1b..0ca7bfb 100644 --- a/lib/widgets/extensions/extensions_widget.dart +++ b/lib/widgets/extensions/extensions_widget.dart @@ -89,6 +89,20 @@ extension ImageExt on Image { } } +extension ActionIcon on Widget { + Widget toCircleContainer() { + return Container( + height: 44, + width: 44, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: MyColors.lightTextColor), + ), + child: this, + ); + } +} + extension WidgetExt on Widget { Widget toWidget() { return this; diff --git a/pubspec.yaml b/pubspec.yaml index b426b6e..1f4ccf5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: url_launcher: ^6.1.7 badges: ^3.0.2 carousel_slider: ^4.2.1 + dropdown_button2: ^2.0.0 # google