From 8c120b89847c2fbd41f0b56fe225d5df9b57db4d Mon Sep 17 00:00:00 2001 From: Abdusalom G'ayratov Date: Fri, 28 Nov 2025 15:31:06 +0500 Subject: [PATCH] BASE: Finish Cam Home Screen UI. --- lib/controllers/cab_dashboard_controller.dart | 1 - .../cab_dashboard_screen.dart | 83 +++- .../cab_service_screens/cab_home_screen.dart | 392 ++++++++++-------- pubspec.lock | 8 + pubspec.yaml | 1 + 5 files changed, 300 insertions(+), 185 deletions(-) diff --git a/lib/controllers/cab_dashboard_controller.dart b/lib/controllers/cab_dashboard_controller.dart index 309907f..2bd4e9b 100644 --- a/lib/controllers/cab_dashboard_controller.dart +++ b/lib/controllers/cab_dashboard_controller.dart @@ -13,7 +13,6 @@ class CabDashboardController extends GetxController { @override void onInit() { - // TODO: implement onInit getTaxList(); if (Constant.walletSetting == false) { pageList.value = [CabHomeScreen(), const MyCabBookingScreen(), const ProfileScreen()]; diff --git a/lib/screen_ui/cab_service_screens/cab_dashboard_screen.dart b/lib/screen_ui/cab_service_screens/cab_dashboard_screen.dart index d87addb..3f34429 100644 --- a/lib/screen_ui/cab_service_screens/cab_dashboard_screen.dart +++ b/lib/screen_ui/cab_service_screens/cab_dashboard_screen.dart @@ -3,6 +3,7 @@ import 'package:customer/controllers/cab_dashboard_controller.dart'; import 'package:customer/controllers/theme_controller.dart'; import 'package:customer/themes/app_them_data.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; @@ -23,13 +24,19 @@ class CabDashboardScreen extends StatelessWidget { type: BottomNavigationBarType.fixed, showUnselectedLabels: true, showSelectedLabels: true, - selectedFontSize: 12, - selectedLabelStyle: const TextStyle(fontFamily: AppThemeData.bold), - unselectedLabelStyle: const TextStyle(fontFamily: AppThemeData.bold), + selectedFontSize: 12.sp, + selectedLabelStyle: const TextStyle( + fontFamily: AppThemeData.bold, + ), + unselectedLabelStyle: const TextStyle( + fontFamily: AppThemeData.bold, + ), currentIndex: controller.selectedIndex.value, - backgroundColor: isDark ? AppThemeData.grey900 : AppThemeData.grey50, - selectedItemColor: isDark ? AppThemeData.primary300 : AppThemeData.primary300, - unselectedItemColor: isDark ? AppThemeData.grey300 : AppThemeData.grey600, + backgroundColor: AppThemeData.cardColor, + selectedItemColor: + isDark ? AppThemeData.primary300 : AppThemeData.primary300, + unselectedItemColor: + isDark ? AppThemeData.grey300 : AppThemeData.grey600, onTap: (int index) { if (index == 0) { Get.put(CabDashboardController()); @@ -39,15 +46,57 @@ class CabDashboardScreen extends StatelessWidget { items: Constant.walletSetting == false ? [ - navigationBarItem(isDark, index: 0, assetIcon: "assets/icons/ic_home_cab.svg", label: 'Home'.tr, controller: controller), - navigationBarItem(isDark, index: 1, assetIcon: "assets/icons/ic_booking_cab.svg", label: 'My Bookings'.tr, controller: controller), - navigationBarItem(isDark, index: 2, assetIcon: "assets/icons/ic_profile.svg", label: 'Profile'.tr, controller: controller), + navigationBarItem( + isDark, + index: 0, + assetIcon: "assets/icons/ic_home_cab.svg", + label: 'Home'.tr, + controller: controller, + ), + navigationBarItem( + isDark, + index: 1, + assetIcon: "assets/icons/ic_booking_cab.svg", + label: 'My Bookings'.tr, + controller: controller, + ), + navigationBarItem( + isDark, + index: 2, + assetIcon: "assets/icons/ic_profile.svg", + label: 'Profile'.tr, + controller: controller, + ), ] : [ - navigationBarItem(isDark, index: 0, assetIcon: "assets/icons/ic_home_cab.svg", label: 'Home'.tr, controller: controller), - navigationBarItem(isDark, index: 1, assetIcon: "assets/icons/ic_booking_cab.svg", label: 'My Bookings'.tr, controller: controller), - navigationBarItem(isDark, index: 2, assetIcon: "assets/icons/ic_wallet_cab.svg", label: 'Wallet'.tr, controller: controller), - navigationBarItem(isDark, index: 3, assetIcon: "assets/icons/ic_profile.svg", label: 'Profile'.tr, controller: controller), + navigationBarItem( + isDark, + index: 0, + assetIcon: "assets/icons/ic_home_cab.svg", + label: 'Home'.tr, + controller: controller, + ), + navigationBarItem( + isDark, + index: 1, + assetIcon: "assets/icons/ic_booking_cab.svg", + label: 'My Bookings'.tr, + controller: controller, + ), + navigationBarItem( + isDark, + index: 2, + assetIcon: "assets/icons/ic_wallet_cab.svg", + label: 'Wallet'.tr, + controller: controller, + ), + navigationBarItem( + isDark, + index: 3, + assetIcon: "assets/icons/ic_profile.svg", + label: 'Profile'.tr, + controller: controller, + ), ], ), ); @@ -56,7 +105,13 @@ class CabDashboardScreen extends StatelessWidget { }); } - BottomNavigationBarItem navigationBarItem(isDark, {required int index, required String label, required String assetIcon, required CabDashboardController controller}) { + BottomNavigationBarItem navigationBarItem( + isDark, { + required int index, + required String label, + required String assetIcon, + required CabDashboardController controller, + }) { return BottomNavigationBarItem( icon: Padding( padding: const EdgeInsets.symmetric(vertical: 5), diff --git a/lib/screen_ui/cab_service_screens/cab_home_screen.dart b/lib/screen_ui/cab_service_screens/cab_home_screen.dart index fb21871..d002912 100644 --- a/lib/screen_ui/cab_service_screens/cab_home_screen.dart +++ b/lib/screen_ui/cab_service_screens/cab_home_screen.dart @@ -4,16 +4,15 @@ import 'package:customer/controllers/theme_controller.dart'; import 'package:customer/models/banner_model.dart'; import 'package:customer/screen_ui/auth_screens/login_screen.dart'; import 'package:customer/themes/app_them_data.dart'; -import 'package:customer/themes/responsive.dart'; import 'package:customer/utils/network_image_widget.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; - import 'Intercity_home_screen.dart'; import 'cab_booking_screen.dart'; -class CabHomeScreen extends StatelessWidget { +class CabHomeScreen extends HookWidget { const CabHomeScreen({super.key}); @override @@ -26,189 +25,246 @@ class CabHomeScreen extends StatelessWidget { return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, - backgroundColor: AppThemeData.primary300, - title: Padding( - padding: const EdgeInsets.only(bottom: 10), - child: Row( - children: [ - GestureDetector( - onTap: () { - Get.back(); - }, - child: Container( - height: 42, - width: 42, - decoration: BoxDecoration(shape: BoxShape.circle, color: AppThemeData.grey50), - child: Center( - child: Padding( - padding: const EdgeInsets.only(left: 5), - child: Icon(Icons.arrow_back_ios, color: AppThemeData.grey900, size: 20), + backgroundColor: AppThemeData.cardColor, + title: Row( + children: [ + SizedBox(width: 5.w), + InkWell( + onTap: () { + Get.back(); + }, + child: Icon( + Icons.arrow_back_ios, + color: AppThemeData.grey900, + size: 20, + ), + ), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Constant.userModel == null + ? InkWell( + onTap: () { + Get.offAll(const LoginScreen()); + }, + child: Text( + "Login".tr, + textAlign: TextAlign.center, + style: AppThemeData.boldTextStyle( + color: AppThemeData.grey900, + fontSize: 17.sp, + ), + ), + ) + : Text( + Constant.userModel!.fullName(), + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + style: AppThemeData.boldTextStyle( + color: AppThemeData.grey900, + fontSize: 17.sp, + ), + ), + Text( + Constant.selectedLocation.getFullAddress(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppThemeData.regularTextStyle( + fontSize: 12.sp, + color: AppThemeData.grey900, ), ), - ), + ], ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Constant.userModel == null - ? InkWell( - onTap: () { - Get.offAll(const LoginScreen()); - }, - child: Text( - "Login".tr, - textAlign: TextAlign.center, - style: AppThemeData.boldTextStyle(color: AppThemeData.grey900, fontSize: 12), - ), - ) - : Text( - Constant.userModel!.fullName(), - textAlign: TextAlign.center, - style: AppThemeData.boldTextStyle(color: AppThemeData.grey900, fontSize: 12), - ), - Text( - Constant.selectedLocation.getFullAddress(), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppThemeData.boldTextStyle(fontSize: 18, color: AppThemeData.grey900), - ), - ], - ), - ), - ], - ), + ), + ], ), ), body: controller.isLoading.value ? Constant.loader() - : Padding( - padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BannerView(bannerList: controller.bannerTopHome), + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BannerView(bannerList: controller.bannerTopHome), - Column( + Padding( + padding: EdgeInsetsGeometry.symmetric(horizontal: 16.r), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 20), Text( - "Where are you going for?".tr, - style: AppThemeData.mediumTextStyle( - color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, - fontSize: 18, + "Cab Service Type", + style: AppThemeData.boldTextStyle( + color: + isDark + ? AppThemeData.greyDark900 + : AppThemeData.darkGrey, + fontSize: 16.sp, ), ), - SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Constant.sectionConstantModel!.rideType == "both" || Constant.sectionConstantModel!.rideType == "ride" - ? GestureDetector( - onTap: () { - Get.to(() => CabBookingScreen()); - }, - child: Container( - width: Responsive.width(40, context), - decoration: BoxDecoration( - color: AppThemeData.warning50, - borderRadius: BorderRadius.circular(15), - border: Border.all(color: AppThemeData.warning200), - ), - padding: EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset("assets/icons/ic_ride.svg", height: 38, width: 38), - SizedBox(height: 20), - Text( - "Ride".tr, - style: AppThemeData.semiBoldTextStyle(color: AppThemeData.taxiBooking500, fontSize: 16), - ), - Text( - "City rides, 24x7 availability".tr, - style: AppThemeData.mediumTextStyle(color: AppThemeData.taxiBooking600, fontSize: 14), - ), - ], - ), - ), - ) - : SizedBox(), - SizedBox(width: 20), - Constant.sectionConstantModel!.rideType == "both" || Constant.sectionConstantModel!.rideType == "intercity" - ? GestureDetector( - onTap: () { - Get.to(() => IntercityHomeScreen()); - }, - child: Container( - width: Responsive.width(44, context), - decoration: BoxDecoration( - color: AppThemeData.carRent50, - borderRadius: BorderRadius.circular(15), - border: Border.all(color: AppThemeData.carRent200), - ), - padding: EdgeInsets.all(15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset("assets/icons/ic_intercity.svg", height: 38, width: 38), - SizedBox(height: 20), - Text( - "Intercity/Outstation".tr, - style: AppThemeData.semiBoldTextStyle(color: AppThemeData.carRent500, fontSize: 16), - ), - Text( - "Long trips, prepaid options".tr, - style: AppThemeData.mediumTextStyle(color: AppThemeData.parcelService600, fontSize: 14), - ), - ], - ), - ), - ) - : SizedBox(), - ], - ), - SizedBox(height: 30), + SizedBox(height: 10.h), + // Cab Service Types Section + _buildCabServiceTypesSection(), + + SizedBox(height: 35.h), + Row( children: [ Expanded( flex: 2, child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, children: [ Text( - "Every Ride. Every Driver. Verified.".tr, + "Every Ride. Every Driver. Verified." + .tr, style: AppThemeData.boldTextStyle( - color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900, + color: + isDark + ? AppThemeData.greyDark900 + : AppThemeData.grey900, fontSize: 22, ), ), Text( - "All drivers go through ID checks and background verification for your safety.".tr, + "All drivers go through ID checks and background verification for your safety." + .tr, style: AppThemeData.mediumTextStyle( - color: isDark ? AppThemeData.greyDark700 : AppThemeData.grey700, + color: + isDark + ? AppThemeData.greyDark700 + : AppThemeData.grey700, fontSize: 14, ), ), ], ), ), - Expanded(child: Image.asset("assets/images/img_ride_driver.png", height: 118, width: 68)), + Expanded( + child: Image.asset( + "assets/images/img_ride_driver.png", + height: 118, + width: 68, + ), + ), ], ), ], ), - ], - ), + ), + ], ), ); }, ); } + + Row _buildCabServiceTypesSection() { + return Row( + spacing: 10.w, + children: [ + Constant.sectionConstantModel!.rideType == "both" || + Constant.sectionConstantModel!.rideType == "ride" + ? _cabOptionMaker( + title: "По городу", + isMain: false, + image: "assets/images/taxi_option.png", + useGradient: false, + onTap: () { + Get.to(() => CabBookingScreen()); + }, + mainColor: AppThemeData.cardColor, + ) + : Expanded(child: SizedBox()), + _cabOptionMaker( + title: "Межгород", + isMain: false, + useGradient: false, + image: "assets/images/outer_city_taxi_option.png", + onTap: () { + Get.to(() => IntercityHomeScreen()); + }, + mainColor: AppThemeData.cardColor, + ), + ], + ); + } + + Expanded _cabOptionMaker({ + required String title, + required String image, + required VoidCallback onTap, + required Color mainColor, + required useGradient, + required bool isMain, + }) { + return Expanded( + child: InkWell( + onTap: onTap, + child: Container( + height: 100.h, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: mainColor, + borderRadius: BorderRadius.circular(16.r), + gradient: + useGradient + ? LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [Color(0xFF2E2E37), Color(0xFF6A6A9E)], + ) + : null, + ), + child: Stack( + children: [ + Padding( + padding: EdgeInsets.only(left: 12.r, top: 12.r), + child: Row( + children: [ + Expanded( + child: Text( + maxLines: 2, + title, + style: TextStyle( + overflow: TextOverflow.ellipsis, + fontFamily: AppThemeData.semiBold, + fontSize: 14.sp, + fontWeight: FontWeight.w700, + color: + isMain + ? AppThemeData.grey50 + : AppThemeData.darkGrey, + ), + ), + ), + Expanded(child: SizedBox()), + ], + ), + ), + Transform.translate( + offset: Offset(25.w, 0), + child: Align( + alignment: Alignment.bottomRight, + child: Image.asset( + image, + height: 133.h, + width: 133.w, + fit: BoxFit.contain, + ), + ), + ), + ], + ), + ), + ), + ); + } } class BannerView extends StatelessWidget { @@ -242,43 +298,39 @@ class BannerView extends StatelessWidget { ? SizedBox() : Column( children: [ - SizedBox(height: 20), + SizedBox(height: 20.h), SizedBox( - height: 150, - child: ListView.separated( + height: 150.h, + child: ListView.builder( controller: scrollController, scrollDirection: Axis.horizontal, itemCount: bannerList.length, - separatorBuilder: (context, index) => const SizedBox(width: 15), + itemBuilder: (context, index) { final banner = bannerList[index]; - return ClipRRect( - borderRadius: BorderRadius.circular(15), - child: SizedBox( - width: MediaQuery.of(context).size.width * 0.8, - child: NetworkImageWidget(imageUrl: banner.photo ?? '', fit: BoxFit.cover), + return Container( + width: MediaQuery.of(context).size.width * 0.8, + margin: + index == 0 + ? EdgeInsets.only(left: 16.r, right: 10.r) + : index == bannerList.length - 1 + ? EdgeInsets.only(right: 16.r) + : EdgeInsets.only(right: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + ), + + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + child: NetworkImageWidget( + imageUrl: banner.photo ?? '', + fit: BoxFit.cover, + ), ), ); }, ), ), - const SizedBox(height: 8), - Obx(() { - return Row( - children: List.generate(bannerList.length, (index) { - bool isSelected = currentPage.value == index; - return Expanded( - child: Container( - height: 4, - decoration: BoxDecoration( - color: isSelected ? AppThemeData.grey300 : AppThemeData.grey100, - borderRadius: BorderRadius.circular(5), - ), - ), - ); - }), - ); - }), ], ); } diff --git a/pubspec.lock b/pubspec.lock index ad977d0..e5c9143 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -558,6 +558,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + sha256: "8ae1f090e5f4ef5cfa6670ce1ab5dddadd33f3533a7f9ba19d9f958aa2a89f42" + url: "https://pub.dev" + source: hosted + version: "0.21.3+1" flutter_html: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 3e74692..2365c9a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -87,6 +87,7 @@ dependencies: uuid: ^4.5.2 flutter_google_places_hoc081098: ^2.0.0 flutter_screenutil: ^5.9.3 + flutter_hooks: ^0.21.3+1 dependency_overrides: webview_flutter: ^4.9.0