From 68fdbbd86b3abff93d3b052033a685900ef6a4af Mon Sep 17 00:00:00 2001 From: FaizHashmiCS22 Date: Thu, 30 Mar 2023 11:04:51 +0300 Subject: [PATCH] Ad Creation View --- lib/config/customer_routes.dart | 6 + lib/main.dart | 6 +- lib/view_models/ad_view_model.dart | 43 ++++ lib/views/advertisement/ads_detail_view.dart | 130 +++++++++++ .../advertisement/ads_images_slider.dart | 64 +++++ .../create_ad_progress_steps.dart | 60 +++++ lib/views/advertisement/create_ad_view.dart | 218 ++++++++++++++++++ lib/views/appointment_detail_view.dart | 124 ++++++++++ lib/views/book_provider_app_view.dart | 165 +++++++++---- lib/views/dashboard/dashboard_page.dart | 33 ++- .../dashboard/fragments/ads_fragment.dart | 88 ++++++- .../fragments/appointments_fragment.dart | 33 ++- .../dashboard/fragments/home_fragment.dart | 27 ++- .../fragments/providers_fragment.dart | 152 +----------- .../dashboard/widgets/drawer_widget.dart | 2 +- 15 files changed, 955 insertions(+), 196 deletions(-) create mode 100644 lib/view_models/ad_view_model.dart create mode 100644 lib/views/advertisement/ads_detail_view.dart create mode 100644 lib/views/advertisement/ads_images_slider.dart create mode 100644 lib/views/advertisement/create_ad_progress_steps.dart create mode 100644 lib/views/advertisement/create_ad_view.dart create mode 100644 lib/views/appointment_detail_view.dart diff --git a/lib/config/customer_routes.dart b/lib/config/customer_routes.dart index ed47589..7e62e44 100644 --- a/lib/config/customer_routes.dart +++ b/lib/config/customer_routes.dart @@ -1,4 +1,7 @@ +import 'package:car_customer_app/views/advertisement/create_ad_view.dart'; +import 'package:car_customer_app/views/appointment_detail_view.dart'; import 'package:car_customer_app/views/book_provider_app_view.dart'; +import 'package:car_customer_app/views/advertisement/ads_detail_view.dart'; import 'package:car_customer_app/views/dashboard/dashboard_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:mc_common_app/config/routes.dart'; @@ -7,6 +10,9 @@ class CustomerAppRoutes { static final Map routes = { AppRoutes.dashboard: (context) => DashboardPage(), AppRoutes.bookProviderAppView: (context) => BookProviderAppView(), + AppRoutes.appointmentDetailView: (context) => AppointmentDetailView(), + AppRoutes.adsDetailView: (context) => AdsDetailView(), + AppRoutes.createAdView: (context) => CreateAdView(), }; } diff --git a/lib/main.dart b/lib/main.dart index cd4c65d..48e05f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:car_customer_app/config/customer_dependencies.dart'; import 'package:car_customer_app/config/customer_routes.dart'; +import 'package:car_customer_app/view_models/ad_view_model.dart'; import 'package:car_customer_app/view_models/dashboard_view_model.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -40,6 +41,9 @@ Future main() async { ChangeNotifierProvider( create: (_) => UserVM(userRepo: injector.get()), ), + ChangeNotifierProvider( + create: (_) => AdVM(commonServices: injector.get()), + ), ], child: const MyApp(), ).setupLocale(), @@ -73,7 +77,7 @@ class MyApp extends StatelessWidget { localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, locale: context.locale, - initialRoute: AppRoutes.initialRoute, + initialRoute: AppRoutes.createAdView, routes: CustomerAppRoutes.routes, ); }, diff --git a/lib/view_models/ad_view_model.dart b/lib/view_models/ad_view_model.dart new file mode 100644 index 0000000..86a34ce --- /dev/null +++ b/lib/view_models/ad_view_model.dart @@ -0,0 +1,43 @@ +import 'dart:io'; + +import 'package:mc_common_app/services/services.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/view_models/base_view_model.dart'; + +class AdVM extends BaseVM { + final CommonServices commonServices; + + AdVM({required this.commonServices}); + + AdCreationStepsEnum currentProgressStep = AdCreationStepsEnum.vehicleDetails; + + void updateCurrentStep(AdCreationStepsEnum stepsEnum) { + currentProgressStep = stepsEnum; + notifyListeners(); + } + + bool financeAvailableStatus = false; + + void updateFinanceAvailableStatus(bool status) { + financeAvailableStatus = status; + notifyListeners(); + } + + List pickedImages = []; + + void removeImageFromList(int index) { + pickedImages.removeAt(index); + notifyListeners(); + } + + // sourceFlag for Camera = 0 + // sourceFlag for Gallery = 1 + void pickImageFromPhone(int sourceFlag) async { + File? file = await commonServices.pickImageFromPhone(1); + + if (file != null) { + pickedImages.add(file); + notifyListeners(); + } + } +} diff --git a/lib/views/advertisement/ads_detail_view.dart b/lib/views/advertisement/ads_detail_view.dart new file mode 100644 index 0000000..a09a9fb --- /dev/null +++ b/lib/views/advertisement/ads_detail_view.dart @@ -0,0 +1,130 @@ +import 'package:car_customer_app/views/advertisement/ads_images_slider.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/theme/colors.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; + +class AdsDetailView extends StatelessWidget { + const AdsDetailView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + backgroundColor: MyColors.backgroundColor, + title: "Ads", + profileImageUrl: MyAssets.bnCar, + isRemoveBackButton: false, + isDrawerEnabled: false, + ), + body: Container( + padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CarouselWithIndicatorDemo(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + "Toyota Corolla | Silver".toText(fontSize: 18, isBold: true), + "Jeddah".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + "Model: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "2019".toText( + fontSize: 14, + isBold: true, + ), + ], + ), + "Saudi Arabia".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + "Mileage: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "10928Km".toText( + fontSize: 14, + isBold: true, + ), + ], + ), + "5 Hours ago".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ), + Row( + children: [ + "Transmission: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "Automatic".toText( + fontSize: 14, + isBold: true, + ), + ], + ), + 8.height, + "Description: ".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "No Issue in the car. All parts are genuine with no major accident. ".toText( + fontSize: 14, + isBold: true, + ), + ], + ).toWhiteContainer(width: double.infinity, allPading: 12), + Align( + alignment: Alignment.bottomCenter, + child: Container( + height: 150, + child: Column( + children: [ + Divider(thickness: 1, height: 1), + 18.height, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "35,000".toText(fontSize: 30, isBold: true), + "SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor), + ], + ), + 14.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Reserve Ad", + onPressed: () {}, + ), + ), + 12.width, + Container( + height: 55, + width: 55, + alignment: Alignment.center, + decoration: BoxDecoration(border: Border.all(color: MyColors.black, width: 3)), + child: Icon(Icons.phone, color: MyColors.black), + ), + ], + ), + ], + ), + )), + ], + ), + ), + ); + } +} diff --git a/lib/views/advertisement/ads_images_slider.dart b/lib/views/advertisement/ads_images_slider.dart new file mode 100644 index 0000000..02c799e --- /dev/null +++ b/lib/views/advertisement/ads_images_slider.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/theme/colors.dart'; + +class CarouselWithIndicatorDemo extends StatefulWidget { + @override + State createState() => _CarouselWithIndicatorState(); +} + +class _CarouselWithIndicatorState extends State { + int _current = 0; + final CarouselController _controller = CarouselController(); + + final imgList = [ + MyAssets.bnCar, + MyAssets.bnCar, + MyAssets.bnCar, + ]; + + @override + Widget build(BuildContext context) { + return Column(children: [ + CarouselSlider( + items: imgList + .map((item) => Container( + margin: EdgeInsets.all(5.0), + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + child: Image.asset(item, fit: BoxFit.cover), + ), + )) + .toList(), + carouselController: _controller, + options: CarouselOptions( + autoPlay: false, + enlargeCenterPage: false, + aspectRatio: 1.8, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + }), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: imgList.asMap().entries.map((entry) { + return GestureDetector( + onTap: () => _controller.animateToPage(entry.key), + child: Container( + width: 12.0, + height: 12.0, + margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _current == entry.key ? MyColors.darkPrimaryColor : MyColors.lightTextColor.withOpacity(0.5), + ), + ), + ); + }).toList(), + ), + ]); + } +} diff --git a/lib/views/advertisement/create_ad_progress_steps.dart b/lib/views/advertisement/create_ad_progress_steps.dart new file mode 100644 index 0000000..d40dd6a --- /dev/null +++ b/lib/views/advertisement/create_ad_progress_steps.dart @@ -0,0 +1,60 @@ +import 'package:car_customer_app/view_models/ad_view_model.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/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:provider/provider.dart'; + +class CreateAdProgressSteps extends StatelessWidget { + const CreateAdProgressSteps({Key? key}) : super(key: key); + + Widget buildStep(String icon, String title, bool isSelected) { + return Column( + children: [ + Container( + height: 50, + width: 50, + padding: EdgeInsets.all(08), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected ? MyColors.darkPrimaryColor : MyColors.white, + border: Border.all( + color: isSelected ? MyColors.darkPrimaryColor : MyColors.lightIconColor, + ), + ), + child: icon.buildSvg(color: isSelected ? MyColors.white : MyColors.lightIconColor,), + ), + 5.height, + title.toText( + textAlign: TextAlign.center, + isBold: true, + fontSize: 12, + color: isSelected ? MyColors.black : MyColors.lightIconColor, + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + AdVM adVM = context.watch(); + return Stack( + // alignment: Alignment.center, + children: [ + Divider(thickness: 2).paddingOnly(left: 21, right: 21, top: 15), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + buildStep(MyAssets.carIcon, "Vehicle \n Details", adVM.currentProgressStep == AdCreationStepsEnum.vehicleDetails), + buildStep(MyAssets.carHitIcon, "Damage \n Parts", adVM.currentProgressStep == AdCreationStepsEnum.damageParts), + buildStep(MyAssets.clockIcon, "Ad \n Duration", adVM.currentProgressStep == AdCreationStepsEnum.adDuration), + buildStep(MyAssets.reviewIcon, "Review \n Ad", adVM.currentProgressStep == AdCreationStepsEnum.reviewAd), + ], + ), + ], + ); + } +} diff --git a/lib/views/advertisement/create_ad_view.dart b/lib/views/advertisement/create_ad_view.dart new file mode 100644 index 0000000..a35acd9 --- /dev/null +++ b/lib/views/advertisement/create_ad_view.dart @@ -0,0 +1,218 @@ +import 'package:car_customer_app/main.dart'; +import 'package:car_customer_app/view_models/ad_view_model.dart'; +import 'package:car_customer_app/views/advertisement/create_ad_progress_steps.dart'; +import 'package:flutter/cupertino.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/theme/colors.dart'; +import 'package:mc_common_app/utils/enums.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/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'; +import 'package:mc_common_app/widgets/common_widgets/dotted_rect.dart'; + +class CreateAdView extends StatelessWidget { + CreateAdView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + title: "Create Ad", + isRemoveBackButton: false, + isDrawerEnabled: false, + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CreateAdProgressSteps(), + 22.height, + //TODO: Need to add a Widget Builder here, based on the Enums + VehicleDetails().toWhiteContainer(width: double.infinity, allPading: 12, margin: EdgeInsets.symmetric(horizontal: 21, vertical: 10)), + 10.height, + SizedBox( + width: double.infinity, + child: ShowFillButton( + title: "Next", + onPressed: () { + context.read().updateCurrentStep(AdCreationStepsEnum.damageParts); + }, + )), + 10.height, + ], + ), + ), + ); + } +} + +class VehicleDetails extends StatelessWidget { + const VehicleDetails({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + List dropList = [ + DropValue(0, "Maintenance", ""), + DropValue(1, "Car Wash", ""), + DropValue(2, "Monthly Checkup", ""), + DropValue(3, "Friendly Visit", ""), + DropValue(4, "Muftaa", ""), + ]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Vehicle Detail".toText(fontSize: 18, isBold: true), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Type", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Model", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Model Year", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Color", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Condition", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Category", + ), + 8.height, + TxtField( + hint: "Vehicle Mileage", + // onChanged: (v) => email = v, + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Transmission", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Seller Type", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle Country", + ), + 8.height, + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Vehicle City", + ), + 8.height, + TxtField( + hint: "Demand Amount", + // onChanged: (v) => email = v, + ), + 8.height, + TxtField( + hint: "Vehicle VIN", + // onChanged: (v) => email = v, + ), + 8.height, + TxtField( + hint: "Vehicle Title", + // onChanged: (v) => email = v, + ), + 8.height, + TxtField( + hint: "Warranty Available (No. of Years)", + // onChanged: (v) => email = v, + ), + 8.height, + TxtField( + hint: "Vehicle Description", + maxLines: 5, + // onChanged: (v) => email = v, + ), + 22.height, + "Finance Available".toText(fontSize: 16), + 8.height, + Consumer(builder: (BuildContext context, AdVM adVm, Widget? child) { + return Container( + width: 65, + height: 37, + decoration: BoxDecoration( + color: adVm.financeAvailableStatus ? MyColors.darkPrimaryColor : MyColors.white, + borderRadius: BorderRadius.circular(25.0), + border: Border.all(color: MyColors.black, width: 1.5), + ), + child: CupertinoSwitch( + activeColor: MyColors.darkPrimaryColor, + trackColor: MyColors.white, + thumbColor: MyColors.grey98Color, + value: adVm.financeAvailableStatus, + onChanged: (value) { + adVm.updateFinanceAvailableStatus(value); + }, + ), + ); + }), + 28.height, + "Vehicle Pictures".toText(fontSize: 18, isBold: true), + 8.height, + InkWell( + onTap: () { + context.read().pickImageFromPhone(1); + }, + 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, + children: [ + MyAssets.attachmentIcon.buildSvg(), + "Attach Image".toText( + fontSize: 15, + isBold: true, + color: MyColors.darkPrimaryColor, + ), + ], + ), + ), + ), + ), + 20.height, + ], + ); + } +} diff --git a/lib/views/appointment_detail_view.dart b/lib/views/appointment_detail_view.dart new file mode 100644 index 0000000..47f7b53 --- /dev/null +++ b/lib/views/appointment_detail_view.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:mc_common_app/classes/consts.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/extensions/string_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart'; + +class AppointmentDetailView extends StatelessWidget { + AppointmentDetailView({Key? key}) : super(key: key); + + final List servicesList = [ + "Mechanic", + "Electrician", + " Car Denting", + "Oil Change", + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBar( + backgroundColor: MyColors.backgroundColor, + title: "Appointment", + profileImageUrl: MyAssets.bnCar, + isRemoveBackButton: false, + isDrawerEnabled: false, + ), + body: Container( + padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Al Ahmad Maintenance".toText(fontSize: 18, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + MyAssets.miniClockDark.buildSvg( + height: 10, + width: 10, + fit: BoxFit.fill, + ), + 10.width, + "08:00 to 09:00 at 23 July, 2023".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor), + ], + ), + 13.height, + Row( + children: [ + MyAssets.maintenanceIcon.buildSvg( + height: 10, + width: 10, + fit: BoxFit.fill, + ), + 10.width, + "Maintenance".toText(fontSize: 18, isBold: true), + ], + ), + Column( + children: servicesList + .map((e) => e + .toText( + textAlign: TextAlign.start, + fontSize: 13, + isBold: true, + color: MyColors.lightTextColor, + ) + .paddingOnly(bottom: 5)) + .toList(), + ).paddingOnly(left: 15), + 15.height, + Row( + children: [ + CardButtonWithIcon( + title: "Reschedule Appointment", + onCardTapped: () {}, + icon: MyAssets.scheduleAppointmentIcon.buildSvg(), + ), + 10.width, + CardButtonWithIcon( + title: "Pay for Appointment", + onCardTapped: () {}, + icon: MyAssets.creditCardIcon.buildSvg(), + ), + ], + ), + 15.height, + ], + ).toWhiteContainer(width: double.infinity, allPading: 12), + Align( + alignment: Alignment.bottomCenter, + child: Row( + children: [ + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Cancel", + onPressed: () {}, + backgroundColor: MyColors.redColor, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + maxHeight: 55, + title: "Confirm", + onPressed: () {}, + backgroundColor: MyColors.greenColor, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/book_provider_app_view.dart b/lib/views/book_provider_app_view.dart index 7877bdf..a5174a8 100644 --- a/lib/views/book_provider_app_view.dart +++ b/lib/views/book_provider_app_view.dart @@ -1,29 +1,68 @@ -import 'package:car_customer_app/views/dashboard/fragments/providers_fragment.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/theme/colors.dart'; +import 'package:mc_common_app/widgets/common_widgets/app_bar.dart'; +import 'package:mc_common_app/widgets/common_widgets/provider_details_card.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/button/show_fill_button.dart'; -class BookProviderAppView extends StatelessWidget { +class BookProviderAppView extends StatefulWidget { const BookProviderAppView({Key? key}) : super(key: key); + @override + State createState() => _BookProviderAppViewState(); +} + +class _BookProviderAppViewState extends State { + bool isReview = false; + @override Widget build(BuildContext context) { - return Material( - child: Container( + return Scaffold( + appBar: CustomAppBar( + title: "Appointment", + profileImageUrl: MyAssets.bnCar, + isRemoveBackButton: false, + isDrawerEnabled: false, + ), + body: Container( color: MyColors.backgroundColor, width: double.infinity, height: double.infinity, - child: SingleChildScrollView( - child: Column( - children: [ - 80.height, - ProviderDetailsCard(), - 12.height, - ServicesSelectionSection(), - ], - ), + child: Column( + children: [ + Expanded( + child: ListView( + children: [ + ProviderDetailsCard( + onCardTapped: () {}, + providerImageUrl: MyAssets.bnCar, + providerLocation: "3km", + providerName: "Al Ahmed Maintenance", + providerRatings: "4.9", + ), + 12.height, + isReview ? ReviewAppointmentSection() : ServicesSelectionSection(), + 10.height, + ], + ), + ), + 10.height, + Padding( + padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), + child: ShowFillButton( + title: "Book Appointment", + maxWidth: double.infinity, + onPressed: () { + isReview = !isReview; + setState(() {}); + }, + ), + ), + ], ), ), ); @@ -33,49 +72,94 @@ class BookProviderAppView extends StatelessWidget { class ServicesSelectionSection extends StatelessWidget { const ServicesSelectionSection({Key? key}) : super(key: key); - Widget buildDropDownContainer({required Widget child}) { - return Container( - height: 48, - decoration: BoxDecoration( - border: Border.all( - width: 3, - color: MyColors.primaryColor, - ), - ), - ); - } - - @override Widget build(BuildContext context) { + List dropList = [ + DropValue(0, "Maintenance", ""), + DropValue(1, "Car Wash", ""), + DropValue(2, "Monthly Checkup", ""), + DropValue(3, "Friendly Visit", ""), + DropValue(4, "Muftaa", ""), + ]; return Container( - padding: const EdgeInsets.only( - bottom: 10, - left: 21, - right: 21, - ), + padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ "Select services you want".toText(fontSize: 18, isBold: true), 8.height, - buildDropDownContainer(child: SizedBox()), + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Select service type", + ), 8.height, - buildDropDownContainer(child: SizedBox()), - + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Select service type", + ), 8.height, - buildDropDownContainer(child: SizedBox()), - + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Select service type", + ), 22.height, - "Select Date and Time".toText(fontSize: 18, isBold: true), + "Select date and time".toText(fontSize: 18, isBold: true), 8.height, - buildDropDownContainer(child: SizedBox()), - + DropdownField( + (DropValue value) {}, + list: dropList, + hint: "Select service type", + ), 22.height, "Available slots".toText(fontSize: 15, isBold: true), 8.height, - BuildTimeSlots() + BuildTimeSlots(), + 22.height, + "Total Amount".toText(fontSize: 18, isBold: true), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "3000".toText(fontSize: 20, isBold: true), + "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ), + 10.height, + ], + ).toWhiteContainer(width: double.infinity, allPading: 12), + ); + } +} +class ReviewAppointmentSection extends StatelessWidget { + const ReviewAppointmentSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Review Appointment".toText(fontSize: 18, isBold: true), + 15.height, + "Services".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "Car Engine Check".toText(fontSize: 18, isBold: true), + 13.height, + "Date and Time".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + "2 Feb, 2023 at 09:00am".toText(fontSize: 18, isBold: true), + 13.height, + "Total Amount".toText(fontSize: 14, isBold: true, color: MyColors.lightTextColor), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + "3000".toText(fontSize: 20, isBold: true), + "SAR".toText(fontSize: 10, isBold: true, color: MyColors.lightTextColor), + ], + ), + 100.height, ], ).toWhiteContainer(width: double.infinity, allPading: 12), ); @@ -117,4 +201,3 @@ class BuildTimeSlots extends StatelessWidget { ); } } - diff --git a/lib/views/dashboard/dashboard_page.dart b/lib/views/dashboard/dashboard_page.dart index a362c0f..392ec3d 100644 --- a/lib/views/dashboard/dashboard_page.dart +++ b/lib/views/dashboard/dashboard_page.dart @@ -35,18 +35,41 @@ class _DashboardPageState extends State { const ProvidersFragment(), const AppointmentsFragment(), const HomeFragment(), - const AdsFragment(), + AdsFragment(), const SettingsFragment(), ]; + String getPageTitle(int index) { + if (index == 0) { + return "Providers"; + } + if (index == 1) { + return "Appointments"; + } + if (index == 2) { + return ""; + } + if (index == 3) { + return "Ads"; + } + if (index == 4) { + return ""; + } + return ""; + } + @override Widget build(BuildContext context) { + bool isHomePage = context.watch().selectedNavbarBarIndex == 2; return Scaffold( - appBar: context.watch().selectedNavbarBarIndex != 2 ? null : CustomAppBar( + appBar: CustomAppBar( + backgroundColor: null, + leadingWidth: 100, + title: getPageTitle(context.watch().selectedNavbarBarIndex), profileImageUrl: MyAssets.bnCar, - isRemoveBackButton: false, - isDrawerEnabled: true, - actions: [MyAssets.notificationsBellIcon.buildSvg().paddingOnly(right: 21)], + isRemoveBackButton: true, + isDrawerEnabled: isHomePage ? true : false, + actions: [(isHomePage ? MyAssets.notificationsBellIcon : MyAssets.searchIcon).buildSvg().paddingOnly(right: 21)], ), drawer: CustomDrawer(dashboardVM: context.watch()), bottomNavigationBar: CustomBottomNavbar(), diff --git a/lib/views/dashboard/fragments/ads_fragment.dart b/lib/views/dashboard/fragments/ads_fragment.dart index f437c22..a59aea7 100644 --- a/lib/views/dashboard/fragments/ads_fragment.dart +++ b/lib/views/dashboard/fragments/ads_fragment.dart @@ -1,11 +1,93 @@ import 'package:flutter/material.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; +import 'package:mc_common_app/widgets/common_widgets/ads_list.dart'; +class AdsFragment extends StatefulWidget { + AdsFragment({Key? key}) : super(key: key); -class AdsFragment extends StatelessWidget { - const AdsFragment({Key? key}) : super(key: key); + @override + State createState() => _AdsFragmentState(); +} + +class _AdsFragmentState extends State { + bool isExploreAdsTapped = true; + + bool isMyAdsTapped = false; @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + body: Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Column( + children: [ + 16.height, + Row( + children: [ + Expanded( + child: ShowFillButton( + isFilled: isExploreAdsTapped, + maxHeight: 55, + title: "Explore Ads", + txtColor: isExploreAdsTapped ? MyColors.white : MyColors.darkTextColor, + onPressed: () { + if (!isExploreAdsTapped) { + isExploreAdsTapped = true; + isMyAdsTapped = false; + } + setState(() {}); + }, + ), + ), + 12.width, + Expanded( + child: ShowFillButton( + isFilled: isMyAdsTapped, + txtColor: isMyAdsTapped ? MyColors.white : MyColors.darkTextColor, + maxHeight: 55, + title: "My Ads", + onPressed: () { + if (!isMyAdsTapped) { + isMyAdsTapped = true; + isExploreAdsTapped = false; + } + setState(() {}); + }, + ), + ), + ], + ), + 24.height, + Expanded( + child: BuildAdsList( + count: 20, + onAdPressed: () { + navigateWithName( + context, + AppRoutes.adsDetailView, + ); + }, + ), + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + navigateWithName(context, AppRoutes.createAdView); + }, + backgroundColor: MyColors.darkPrimaryColor, + child: Icon( + Icons.add, + color: MyColors.white, + ), + ), + ); } } diff --git a/lib/views/dashboard/fragments/appointments_fragment.dart b/lib/views/dashboard/fragments/appointments_fragment.dart index 277ed11..9406018 100644 --- a/lib/views/dashboard/fragments/appointments_fragment.dart +++ b/lib/views/dashboard/fragments/appointments_fragment.dart @@ -1,10 +1,41 @@ import 'package:flutter/material.dart'; +import 'package:mc_common_app/config/routes.dart'; +import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/theme/colors.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/common_widgets/customer_appointment_slider_widget.dart'; +import 'package:mc_common_app/widgets/common_widgets/categories_list.dart'; class AppointmentsFragment extends StatelessWidget { const AppointmentsFragment({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return Container(); + return Container( + color: MyColors.backgroundColor, + width: double.infinity, + height: double.infinity, + child: Column( + children: [ + 16.height, + CategoriesList(name: "Upcoming", onTapped: () {}), + 16.height, + Expanded( + child: Container( + child: ListView.builder( + shrinkWrap: true, + itemCount: 30, + itemBuilder: (BuildContext context, int index) { + return BuildAppointmentContainerForCustomer( + onTapped: () { + navigateWithName(context, AppRoutes.appointmentDetailView); + }, + ); + }), + ), + ), + ], + ), + ); } } diff --git a/lib/views/dashboard/fragments/home_fragment.dart b/lib/views/dashboard/fragments/home_fragment.dart index 1014d99..00e67da 100644 --- a/lib/views/dashboard/fragments/home_fragment.dart +++ b/lib/views/dashboard/fragments/home_fragment.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/extensions/int_extensions.dart'; +import 'package:mc_common_app/utils/navigator.dart'; +import 'package:mc_common_app/widgets/common_widgets/ads_list.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:mc_common_app/widgets/common_widgets/ad_widget.dart'; import 'package:mc_common_app/widgets/common_widgets/view_all_widget.dart'; import 'package:mc_common_app/widgets/common_widgets/my_service_provider.dart'; import 'package:mc_common_app/widgets/common_widgets/customer_appointment_slider_widget.dart'; @@ -20,6 +22,7 @@ class HomeFragment extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.max, children: [ + 16.height, ViewAllWidget(title: "Upcoming Appointment".toUpperCase(), subTitle: "View All").horPaddingMain(), const CustomerAppointmentSliderWidget(), 7.height, @@ -28,10 +31,28 @@ class HomeFragment extends StatelessWidget { 15.height, ViewAllWidget(title: "My Active Ads".toUpperCase(), subTitle: "View All").horPaddingMain(), // todo: we will replace this count with the sublist of ads - const AdWidget(count: 1).horPaddingMain(), + BuildAdsList( + count: 1, + scrollPhysics: NeverScrollableScrollPhysics(), + onAdPressed: () { + navigateWithName( + context, + AppRoutes.adsDetailView, + ); + }, + ).horPaddingMain(), 20.height, ViewAllWidget(title: "My Recommended Ads".toUpperCase(), subTitle: "View All").horPaddingMain(), - const AdWidget(count: 2).horPaddingMain(), + BuildAdsList( + count: 2, + scrollPhysics: NeverScrollableScrollPhysics(), + onAdPressed: () { + navigateWithName( + context, + AppRoutes.adsDetailView, + ); + }, + ).horPaddingMain(), ], ), ), diff --git a/lib/views/dashboard/fragments/providers_fragment.dart b/lib/views/dashboard/fragments/providers_fragment.dart index 8c90cb9..5144772 100644 --- a/lib/views/dashboard/fragments/providers_fragment.dart +++ b/lib/views/dashboard/fragments/providers_fragment.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.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'; -import 'package:mc_common_app/extensions/string_extensions.dart'; import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/navigator.dart'; -import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; +import 'package:mc_common_app/widgets/common_widgets/provider_details_card.dart'; +import 'package:mc_common_app/widgets/common_widgets/categories_list.dart'; class ProvidersFragment extends StatelessWidget { const ProvidersFragment({Key? key}) : super(key: key); @@ -18,20 +18,23 @@ class ProvidersFragment extends StatelessWidget { height: double.infinity, child: Column( children: [ - 80.height, - BuildServices(), - 5.height, + 16.height, + CategoriesList(name: "Oil Services", onTapped: () {}), + 16.height, Expanded( child: Container( child: ListView.builder( shrinkWrap: true, itemCount: 30, itemBuilder: (BuildContext context, int index) { - return InkWell( - onTap: () { + return ProviderDetailsCard( + onCardTapped: () { navigateWithName(context, AppRoutes.bookProviderAppView); }, - child: ProviderDetailsCard(), + providerImageUrl: MyAssets.bnCar, + providerLocation: " 3km", + providerName: "Al Ahmed Maintenance", + providerRatings: "4.9", ); }), ), @@ -41,136 +44,3 @@ class ProvidersFragment extends StatelessWidget { ); } } - -class BuildServices extends StatelessWidget { - const BuildServices({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SizedBox( - height: 37, - width: double.infinity, - child: ListView.builder( - itemCount: 20, - scrollDirection: Axis.horizontal, - itemBuilder: (BuildContext context, int index) { - return InkWell( - onTap: () {}, - child: Container( - alignment: Alignment.center, - margin: EdgeInsets.symmetric(horizontal: 8), - width: 85, - decoration: BoxDecoration( - color: index < 2 ? MyColors.darkIconColor : null, - border: Border.all( - color: index < 2 ? MyColors.darkIconColor : MyColors.primaryColor, - width: 2, - ), - ), - child: "Oil Services".toText( - fontSize: 12, - color: index < 2 ? MyColors.white : null, - ), - ), - ); - }), - ); - } -} - -class ProviderDetailsCard extends StatelessWidget { - const ProviderDetailsCard({Key? key}) : 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( - MyAssets.bnCar, - 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: [ - "Al Ahmed Maintenance".toText(fontSize: 16, isBold: true), - Row( - children: [ - "Location:".toText(color: MyColors.lightTextColor, fontSize: 12), - 2.width, - "9.5km".toText(fontSize: 12), - ], - ), - ], - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - "4.9".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, - "Maintenance".toText( - fontSize: 14, - isBold: true, - ), - ], - ), - Row( - children: [ - MyAssets.modificationsIcon.buildSvg(), - 8.width, - "Accessories and Modification".toText( - fontSize: 14, - isBold: true, - ), - ], - ) - ], - ), - ), - ], - ), - ], - ), - ), - ], - ).toWhiteContainer(width: double.infinity, allPading: 12)); - } -} diff --git a/lib/views/dashboard/widgets/drawer_widget.dart b/lib/views/dashboard/widgets/drawer_widget.dart index a169ac3..fb1e279 100644 --- a/lib/views/dashboard/widgets/drawer_widget.dart +++ b/lib/views/dashboard/widgets/drawer_widget.dart @@ -9,8 +9,8 @@ import 'package:mc_common_app/theme/colors.dart'; import 'package:mc_common_app/utils/navigator.dart'; import 'package:mc_common_app/utils/utils.dart'; import 'package:car_customer_app/view_models/dashboard_view_model.dart'; +import 'package:mc_common_app/widgets/button/show_fill_button.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; -import 'package:mc_common_app/widgets/show_fill_button.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart';