diff --git a/assets/icons/ic_check1.svg b/assets/icons/ic_check1.svg new file mode 100644 index 0000000..c984c5c --- /dev/null +++ b/assets/icons/ic_check1.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/ic_clock.png b/assets/icons/ic_clock.png new file mode 100644 index 0000000..6a6769b Binary files /dev/null and b/assets/icons/ic_clock.png differ diff --git a/assets/icons/ic_close.svg b/assets/icons/ic_close.svg new file mode 100644 index 0000000..f64b147 --- /dev/null +++ b/assets/icons/ic_close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/ic_current_loc.svg b/assets/icons/ic_current_loc.svg new file mode 100644 index 0000000..8a94212 --- /dev/null +++ b/assets/icons/ic_current_loc.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/ic_search.svg b/assets/icons/ic_search.svg new file mode 100644 index 0000000..40fb2bf --- /dev/null +++ b/assets/icons/ic_search.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/translations/app_en.arb b/assets/translations/app_en.arb index e8782f2..90ec32a 100644 --- a/assets/translations/app_en.arb +++ b/assets/translations/app_en.arb @@ -50,7 +50,35 @@ "ride": "Ride", "chinese": "Chinese", "dessert": "Dessert", - "more":"More" + "more":"More", + "orderDetails": "Order details", + "deliverNow": "Deliver now", + "schedule": "Schedule", + "enterNewAddress": "Enter a new address", + "nearby": "Nearby", + "currentLocation": "Current location", + "enable": "Enable", + "recentLocations": "Recent locations", + "allFilters": "All filters", + "sort": "Sort", + "pickedForYou": "Picked for you (default)", + "mostPopular": "Most popular", + "rating": "Rating", + "deliveryTime": "Delivery time", + "fromUberEats": "From Uber Eats", + "deals": "Deals", + "bestOverall": "Best overall", + "priceRange": "Price range", + "maxDeliveryFee": "Max. Delivery Fee", + "dietary": "Dietary", + "vegetarian": "Vegetarian", + "vegan": "Vegan", + "glutenFree": "Gluten-free", + "halal": "Halal", + "allergyFriendly": "Allergy friendly", + "atLeast":"At least", + "apply": "Apply" + } \ No newline at end of file diff --git a/assets/translations/app_ru.arb b/assets/translations/app_ru.arb index d358b51..e1ea54b 100644 --- a/assets/translations/app_ru.arb +++ b/assets/translations/app_ru.arb @@ -57,6 +57,35 @@ "ride": "Поездка", "chinese": "Китайская", "dessert": "Десерт", - "more":"Ещё" + "more":"Ещё", + "orderDetails": "Детали заказа", + "deliverNow": "Доставить сейчас", + "schedule": "Запланировать", + "enterNewAddress": "Введите новый адрес", + "nearby": "Рядом", + "currentLocation": "Текущее местоположение", + "enable": "Включить", + "recentLocations": "Недавние адреса", + "allFilters": "Все фильтры", + "sort": "Сортировка", + "pickedForYou": "Подобрано для вас (по умолчанию)", + "mostPopular": "Самые популярные", + "rating": "Рейтинг", + "deliveryTime": "Время доставки", + "fromUberEats": "От Uber Eats", + "deals": "Скидки", + "bestOverall": "Лучший выбор", + "priceRange": "Диапазон цен", + "maxDeliveryFee": "Макс. стоимость доставки", + "dietary": "Диета", + "vegetarian": "Вегетарианское", + "vegan": "Веганское", + "glutenFree": "Без глютена", + "halal": "Халяль", + "allergyFriendly": "Без аллергенов", + "atLeast":"Kак минимум", + "apply": "Применить" + + } diff --git a/assets/translations/app_uz.arb b/assets/translations/app_uz.arb index 027eab4..13d32ea 100644 --- a/assets/translations/app_uz.arb +++ b/assets/translations/app_uz.arb @@ -57,5 +57,34 @@ "ride": "Yo‘l", "chinese": "Xitoy", "dessert": "Desert", - "more":"Ko'proq" + "more":"Ko'proq", + "orderDetails": "Buyurtma tafsilotlari", + "deliverNow": "Hozir yetkazish", + "schedule": "Rejalashtirish", + "enterNewAddress": "Yangi manzil kiriting", + "nearby": "Yaqin joylar", + "currentLocation": "Joriy joylashuv", + "enable": "Yoqqish", + "recentLocations": "Yaqinda ishlatilgan manzillar", + "allFilters": "Barcha filtrlar", + "sort": "Saralash", + "pickedForYou": "Siz uchun", + "mostPopular": "Eng ommabop", + "rating": "Reyting", + "deliveryTime": "Yetkazib berish vaqti", + "fromUberEats": "Uber Eats dan", + "deals": "Aksiyalar", + "bestOverall": "Eng yaxshisi", + "priceRange": "Narx oralig‘i", + "maxDeliveryFee": "Maks. yetkazish narxi", + "dietary": "Parhez", + "vegetarian": "Vegetarian", + "vegan": "Vegan", + "glutenFree": "Glutensiz", + "halal": "Halol", + "allergyFriendly": "Allergiyaga mos", + "atLeast":"Kаmida", + "apply": "Qo‘llash" + + } diff --git a/lib/core/constants/time_delay_cons.dart b/lib/core/constants/time_delay_cons.dart index a81b840..b270c00 100644 --- a/lib/core/constants/time_delay_cons.dart +++ b/lib/core/constants/time_delay_cons.dart @@ -1,4 +1,5 @@ abstract class TimeDelayConst { + static const Duration durationMill150 = Duration(milliseconds: 150); static const Duration durationMill300 = Duration(milliseconds: 300); static const Duration durationMill800 = Duration(milliseconds: 800); diff --git a/lib/core/di/injection_container.config.dart b/lib/core/di/injection_container.config.dart index 2dd17c2..75fa593 100644 --- a/lib/core/di/injection_container.config.dart +++ b/lib/core/di/injection_container.config.dart @@ -31,9 +31,9 @@ extension GetItInjectableX on _i174.GetIt { _i526.EnvironmentFilter? environmentFilter, }) { final gh = _i526.GetItHelper(this, environment, environmentFilter); + gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc()); gh.factory<_i580.MainBloc>(() => _i580.MainBloc()); gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc()); - gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc()); gh.singleton<_i306.StorageService>(() => _i306.StorageService()); gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes()); gh.factory<_i942.LanguageBloc>( diff --git a/lib/core/l10n/app_localizations.dart b/lib/core/l10n/app_localizations.dart index 4262cb9..50461c8 100644 --- a/lib/core/l10n/app_localizations.dart +++ b/lib/core/l10n/app_localizations.dart @@ -327,6 +327,162 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'More'** String get more; + + /// No description provided for @orderDetails. + /// + /// In en, this message translates to: + /// **'Order details'** + String get orderDetails; + + /// No description provided for @deliverNow. + /// + /// In en, this message translates to: + /// **'Deliver now'** + String get deliverNow; + + /// No description provided for @schedule. + /// + /// In en, this message translates to: + /// **'Schedule'** + String get schedule; + + /// No description provided for @enterNewAddress. + /// + /// In en, this message translates to: + /// **'Enter a new address'** + String get enterNewAddress; + + /// No description provided for @nearby. + /// + /// In en, this message translates to: + /// **'Nearby'** + String get nearby; + + /// No description provided for @currentLocation. + /// + /// In en, this message translates to: + /// **'Current location'** + String get currentLocation; + + /// No description provided for @enable. + /// + /// In en, this message translates to: + /// **'Enable'** + String get enable; + + /// No description provided for @recentLocations. + /// + /// In en, this message translates to: + /// **'Recent locations'** + String get recentLocations; + + /// No description provided for @allFilters. + /// + /// In en, this message translates to: + /// **'All filters'** + String get allFilters; + + /// No description provided for @sort. + /// + /// In en, this message translates to: + /// **'Sort'** + String get sort; + + /// No description provided for @pickedForYou. + /// + /// In en, this message translates to: + /// **'Picked for you (default)'** + String get pickedForYou; + + /// No description provided for @mostPopular. + /// + /// In en, this message translates to: + /// **'Most popular'** + String get mostPopular; + + /// No description provided for @rating. + /// + /// In en, this message translates to: + /// **'Rating'** + String get rating; + + /// No description provided for @deliveryTime. + /// + /// In en, this message translates to: + /// **'Delivery time'** + String get deliveryTime; + + /// No description provided for @fromUberEats. + /// + /// In en, this message translates to: + /// **'From Uber Eats'** + String get fromUberEats; + + /// No description provided for @deals. + /// + /// In en, this message translates to: + /// **'Deals'** + String get deals; + + /// No description provided for @bestOverall. + /// + /// In en, this message translates to: + /// **'Best overall'** + String get bestOverall; + + /// No description provided for @priceRange. + /// + /// In en, this message translates to: + /// **'Price range'** + String get priceRange; + + /// No description provided for @maxDeliveryFee. + /// + /// In en, this message translates to: + /// **'Max. Delivery Fee'** + String get maxDeliveryFee; + + /// No description provided for @dietary. + /// + /// In en, this message translates to: + /// **'Dietary'** + String get dietary; + + /// No description provided for @vegetarian. + /// + /// In en, this message translates to: + /// **'Vegetarian'** + String get vegetarian; + + /// No description provided for @vegan. + /// + /// In en, this message translates to: + /// **'Vegan'** + String get vegan; + + /// No description provided for @glutenFree. + /// + /// In en, this message translates to: + /// **'Gluten-free'** + String get glutenFree; + + /// No description provided for @allergyFriendly. + /// + /// In en, this message translates to: + /// **'Allergy friendly'** + String get allergyFriendly; + + /// No description provided for @atLeast. + /// + /// In en, this message translates to: + /// **'At least'** + String get atLeast; + + /// No description provided for @apply. + /// + /// In en, this message translates to: + /// **'Apply'** + String get apply; } class _AppLocalizationsDelegate diff --git a/lib/core/l10n/app_localizations_en.dart b/lib/core/l10n/app_localizations_en.dart index b931f9e..c141639 100644 --- a/lib/core/l10n/app_localizations_en.dart +++ b/lib/core/l10n/app_localizations_en.dart @@ -126,4 +126,82 @@ class AppLocalizationsEn extends AppLocalizations { @override String get more => 'More'; + + @override + String get orderDetails => 'Order details'; + + @override + String get deliverNow => 'Deliver now'; + + @override + String get schedule => 'Schedule'; + + @override + String get enterNewAddress => 'Enter a new address'; + + @override + String get nearby => 'Nearby'; + + @override + String get currentLocation => 'Current location'; + + @override + String get enable => 'Enable'; + + @override + String get recentLocations => 'Recent locations'; + + @override + String get allFilters => 'All filters'; + + @override + String get sort => 'Sort'; + + @override + String get pickedForYou => 'Picked for you (default)'; + + @override + String get mostPopular => 'Most popular'; + + @override + String get rating => 'Rating'; + + @override + String get deliveryTime => 'Delivery time'; + + @override + String get fromUberEats => 'From Uber Eats'; + + @override + String get deals => 'Deals'; + + @override + String get bestOverall => 'Best overall'; + + @override + String get priceRange => 'Price range'; + + @override + String get maxDeliveryFee => 'Max. Delivery Fee'; + + @override + String get dietary => 'Dietary'; + + @override + String get vegetarian => 'Vegetarian'; + + @override + String get vegan => 'Vegan'; + + @override + String get glutenFree => 'Gluten-free'; + + @override + String get allergyFriendly => 'Allergy friendly'; + + @override + String get atLeast => 'At least'; + + @override + String get apply => 'Apply'; } diff --git a/lib/core/l10n/app_localizations_ru.dart b/lib/core/l10n/app_localizations_ru.dart index 3798ca9..62a46fa 100644 --- a/lib/core/l10n/app_localizations_ru.dart +++ b/lib/core/l10n/app_localizations_ru.dart @@ -127,4 +127,82 @@ class AppLocalizationsRu extends AppLocalizations { @override String get more => 'Ещё'; + + @override + String get orderDetails => 'Детали заказа'; + + @override + String get deliverNow => 'Доставить сейчас'; + + @override + String get schedule => 'Запланировать'; + + @override + String get enterNewAddress => 'Введите новый адрес'; + + @override + String get nearby => 'Рядом'; + + @override + String get currentLocation => 'Текущее местоположение'; + + @override + String get enable => 'Включить'; + + @override + String get recentLocations => 'Недавние адреса'; + + @override + String get allFilters => 'Все фильтры'; + + @override + String get sort => 'Сортировка'; + + @override + String get pickedForYou => 'Подобрано для вас (по умолчанию)'; + + @override + String get mostPopular => 'Самые популярные'; + + @override + String get rating => 'Рейтинг'; + + @override + String get deliveryTime => 'Время доставки'; + + @override + String get fromUberEats => 'От Uber Eats'; + + @override + String get deals => 'Скидки'; + + @override + String get bestOverall => 'Лучший выбор'; + + @override + String get priceRange => 'Диапазон цен'; + + @override + String get maxDeliveryFee => 'Макс. стоимость доставки'; + + @override + String get dietary => 'Диета'; + + @override + String get vegetarian => 'Вегетарианское'; + + @override + String get vegan => 'Веганское'; + + @override + String get glutenFree => 'Без глютена'; + + @override + String get allergyFriendly => 'Без аллергенов'; + + @override + String get atLeast => 'Kак минимум'; + + @override + String get apply => 'Применить'; } diff --git a/lib/core/l10n/app_localizations_uz.dart b/lib/core/l10n/app_localizations_uz.dart index 4f53b63..323e137 100644 --- a/lib/core/l10n/app_localizations_uz.dart +++ b/lib/core/l10n/app_localizations_uz.dart @@ -127,4 +127,82 @@ class AppLocalizationsUz extends AppLocalizations { @override String get more => 'Ko\'proq'; + + @override + String get orderDetails => 'Buyurtma tafsilotlari'; + + @override + String get deliverNow => 'Hozir yetkazish'; + + @override + String get schedule => 'Rejalashtirish'; + + @override + String get enterNewAddress => 'Yangi manzil kiriting'; + + @override + String get nearby => 'Yaqin joylar'; + + @override + String get currentLocation => 'Joriy joylashuv'; + + @override + String get enable => 'Yoqqish'; + + @override + String get recentLocations => 'Yaqinda ishlatilgan manzillar'; + + @override + String get allFilters => 'Barcha filtrlar'; + + @override + String get sort => 'Saralash'; + + @override + String get pickedForYou => 'Siz uchun'; + + @override + String get mostPopular => 'Eng ommabop'; + + @override + String get rating => 'Reyting'; + + @override + String get deliveryTime => 'Yetkazib berish vaqti'; + + @override + String get fromUberEats => 'Uber Eats dan'; + + @override + String get deals => 'Aksiyalar'; + + @override + String get bestOverall => 'Eng yaxshisi'; + + @override + String get priceRange => 'Narx oralig‘i'; + + @override + String get maxDeliveryFee => 'Maks. yetkazish narxi'; + + @override + String get dietary => 'Parhez'; + + @override + String get vegetarian => 'Vegetarian'; + + @override + String get vegan => 'Vegan'; + + @override + String get glutenFree => 'Glutensiz'; + + @override + String get allergyFriendly => 'Allergiyaga mos'; + + @override + String get atLeast => 'Kаmida'; + + @override + String get apply => 'Qo‘llash'; } diff --git a/lib/core/theme/app_colors.dart b/lib/core/theme/app_colors.dart index 0774c90..c424557 100644 --- a/lib/core/theme/app_colors.dart +++ b/lib/core/theme/app_colors.dart @@ -3,6 +3,8 @@ import '../../food_delivery_client.dart'; abstract class AppColors { static const Color cTransparent = Colors.transparent; static const Color cRed = Colors.red; + static const Color cYellow = Colors.yellow; + static const Color cFFFFFF = Color(0xFFFFFFFF); static const Color c000000 = Color(0xFF000000); diff --git a/lib/core/theme/app_icons.dart b/lib/core/theme/app_icons.dart index 9b53a26..deb75d5 100644 --- a/lib/core/theme/app_icons.dart +++ b/lib/core/theme/app_icons.dart @@ -23,5 +23,24 @@ abstract class AppIcons { static const String icLocation = "$baseUrl/ic_location.svg"; static const String icArrowBottom = "$baseUrl/ic_arrow_btm.svg"; + static const String icPicked = "$baseUrl/ic_picked.svg"; + static const String icMostPopular = "$baseUrl/ic_popular.svg"; + static const String icStar = "$baseUrl/ic_rating.svg"; + static const String icDeliveryTime = "$baseUrl/ic_delivery_time.svg"; + static const String icDeals = "$baseUrl/ic_deals.svg"; + static const String icClose = "$baseUrl/ic_close.svg"; + static const String icCurrentLocation = "$baseUrl/ic_current_loc.svg"; + static const String icEdit = "$baseUrl/ic_edit.svg"; + static const String icSearch = "$baseUrl/ic_search.svg"; + static const String icCheck= "$baseUrl/ic_check.svg"; + static const String icCheck1= "$baseUrl/ic_check1.svg"; + + ///.png icons + static const String icBestOverall = "$baseUrl/ic_best.png"; + static const String icVegetarian = "$baseUrl/ic_vegetarian.png"; + static const String icVegen = "$baseUrl/ic_vegen.png"; + static const String icGlutenFree = "$baseUrl/ic_gluten_free.png"; + static const String icAllergyFriendly = "$baseUrl/ic_allergy_friendly.png"; + static const String icClock = "$baseUrl/ic_clock.png"; } diff --git a/lib/core/theme/app_textstyles.dart b/lib/core/theme/app_textstyles.dart index 7eaa8a5..99b8a00 100644 --- a/lib/core/theme/app_textstyles.dart +++ b/lib/core/theme/app_textstyles.dart @@ -63,6 +63,20 @@ abstract class AppTextStyles { fontWeight: FontWeight.w500, ); + static const TextStyle size20Medium = TextStyle( + color: _defaultColor, + fontSize: SizesCons.size_20, + fontFamily: _fontMedium, + fontWeight: FontWeight.w500, + ); + + static const TextStyle size16Bold= TextStyle( + color: _defaultColor, + fontSize: SizesCons.size_16, + fontFamily: _fontBold, + fontWeight: FontWeight.w700, + ); + static const TextStyle size17Bold = TextStyle( color: _defaultColor, fontSize: SizesCons.size_17, diff --git a/lib/core/utils/app_utils.dart b/lib/core/utils/app_utils.dart index 773c076..cb447f7 100644 --- a/lib/core/utils/app_utils.dart +++ b/lib/core/utils/app_utils.dart @@ -1,6 +1,8 @@ import '../../food_delivery_client.dart'; abstract class AppUtils { + static const SizedBox kSizedBox = SizedBox.shrink(); + static const Radius kRadius = Radius.zero; static const Radius kRadius8 = Radius.circular(8); static const Radius kRadius12 = Radius.circular(12); @@ -79,6 +81,10 @@ abstract class AppUtils { static const BorderRadius kBorderRadius40 = BorderRadius.all( Radius.circular(40), ); + static const BorderRadius kBorderRadiusTop20 = BorderRadius.only( + topLeft: kRadius20, + topRight: kRadius20, + ); static const BorderRadius kBorderRadiusTop20Bottom20 = BorderRadius.only( bottomRight: kRadius20, topRight: kRadius20, diff --git a/lib/feature/common/presentation/widgets/app_button.dart b/lib/feature/common/presentation/widgets/app_button.dart new file mode 100644 index 0000000..6bb5f46 --- /dev/null +++ b/lib/feature/common/presentation/widgets/app_button.dart @@ -0,0 +1,61 @@ + +import '../../../../food_delivery_client.dart'; + + +class AppButton extends StatelessWidget { + const AppButton({ + super.key, + required this.name, + required this.onPressed, + this.margin, + this.backgroundColor, + this.borderRadius, + this.height, + this.textColor, + this.width, + this.action, + this.trailing, + this.mainAxisAlignment, + }); + + final String name; + final VoidCallback onPressed; + final EdgeInsets? margin; + final Color? backgroundColor; + final Color? textColor; + final double? borderRadius; + final double? width; + final double? height; + final Widget? action; + final Widget? trailing; + final MainAxisAlignment? mainAxisAlignment; + + @override + Widget build(BuildContext context) { + return Bounceable( + onTap: onPressed, + duration: TimeDelayConst.durationMill150, + child: Container( + width: width ?? double.infinity, + height: height ?? 55, + margin: margin, + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: backgroundColor ?? AppColors.c000000, + borderRadius: BorderRadius.circular(borderRadius ?? 0), + ), + child: Row( + mainAxisAlignment: mainAxisAlignment ?? MainAxisAlignment.center, + children: [ + action ?? AppUtils.kSizedBox, + Text(name, style: AppTextStyles.size16Bold.copyWith( + color: AppColors.cFFFFFF + )), + trailing ?? AppUtils.kSizedBox, + ], + ), + ), + ); + } +} diff --git a/lib/feature/common/presentation/widgets/w_custom_modal_bottom_sheet.dart b/lib/feature/common/presentation/widgets/w_custom_modal_bottom_sheet.dart new file mode 100644 index 0000000..de320a6 --- /dev/null +++ b/lib/feature/common/presentation/widgets/w_custom_modal_bottom_sheet.dart @@ -0,0 +1,37 @@ +import '../../../../../../food_delivery_client.dart'; + +class WCustomModalBottomSheet extends StatelessWidget { + const WCustomModalBottomSheet({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Material( + color: AppColors.cFFFFFF, + borderRadius: AppUtils.kBorderRadiusTop20, + child: SafeArea( + child: SizedBox( + width: context.w, + child: Column( + children: [ + 10.verticalSpace, + SizedBox( + height: 6, + width: 100, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: AppUtils.kBorderRadius6, + color: AppColors.cE6E6E6.newWithOpacity(.6), + ), + ), + ), + 10.verticalSpace, + child, + ], + ), + ), + ), + ); + } +} diff --git a/lib/feature/common/presentation/widgets/widgets.dart b/lib/feature/common/presentation/widgets/widgets.dart index 8de4376..6261541 100644 --- a/lib/feature/common/presentation/widgets/widgets.dart +++ b/lib/feature/common/presentation/widgets/widgets.dart @@ -3,3 +3,5 @@ export 'w_food_item.dart'; export 'w_divider.dart'; export 'w_see_all_raw.dart'; export 'w_stories_list_item.dart'; +export 'w_custom_modal_bottom_sheet.dart'; +export 'app_button.dart'; diff --git a/lib/feature/home/home.dart b/lib/feature/home/home.dart index be74602..31cbfa3 100644 --- a/lib/feature/home/home.dart +++ b/lib/feature/home/home.dart @@ -9,3 +9,6 @@ export 'presentation/pages/home_page/widgets/w_offers_carouseL_slider.dart'; export 'presentation/pages/home_page/widgets/w_popular_near_you.dart'; export 'presentation/pages/home_page/widgets/w_todays_offers.dart'; export 'package:food_delivery_client/feature/home/presentation/pages/home_page/widgets/pick_it_for_free.dart'; +export 'package:flutter_svg/flutter_svg.dart'; +export 'package:food_delivery_client/feature/home/presentation/pages/categories_page/categories_page.dart'; +export 'package:food_delivery_client/feature/home/presentation/pages/home_page/widgets/w_rating_btm_sheet.dart'; diff --git a/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart b/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart index 1f98db5..efb321f 100644 --- a/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart +++ b/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart @@ -5,13 +5,33 @@ part 'home_event.dart'; part 'home_state.dart'; part 'home_bloc.freezed.dart'; + @injectable class HomeBloc extends Bloc { HomeBloc() : super(const HomeState()) { on<_Changed>(_onChanged); + on<_Filtered>(_onFiltered); + on<_Rated>(_onRated); } void _onChanged(_Changed event, Emitter emit) { emit(state.copyWith(currentIndex: event.index)); } + + void _onFiltered(_Filtered event, Emitter emit) { + final oldFilters = List.from(state.filters); + if (oldFilters.contains(event.filter)) { + final newFilters = oldFilters..remove(event.filter); + emit(state.copyWith(filters: newFilters)); + } else { + final newFilters = oldFilters..add(event.filter); + emit(state.copyWith(filters: newFilters)); + } + } + + + void _onRated(_Rated event, Emitter emit){ + emit(state.copyWith(rating: event.filter)); + + } } diff --git a/lib/feature/home/presentation/blocs/home_bloc/home_bloc.freezed.dart b/lib/feature/home/presentation/blocs/home_bloc/home_bloc.freezed.dart index 3365c1f..718c3ca 100644 --- a/lib/feature/home/presentation/blocs/home_bloc/home_bloc.freezed.dart +++ b/lib/feature/home/presentation/blocs/home_bloc/home_bloc.freezed.dart @@ -55,12 +55,14 @@ extension HomeEventPatterns on HomeEvent { /// } /// ``` -@optionalTypeArgs TResult maybeMap({TResult Function( _Started value)? started,TResult Function( _Changed value)? changed,required TResult orElse(),}){ +@optionalTypeArgs TResult maybeMap({TResult Function( _Started value)? started,TResult Function( _Changed value)? changed,TResult Function( _Filtered value)? filtered,TResult Function( _Rated value)? rated,required TResult orElse(),}){ final _that = this; switch (_that) { case _Started() when started != null: return started(_that);case _Changed() when changed != null: -return changed(_that);case _: +return changed(_that);case _Filtered() when filtered != null: +return filtered(_that);case _Rated() when rated != null: +return rated(_that);case _: return orElse(); } @@ -78,12 +80,14 @@ return changed(_that);case _: /// } /// ``` -@optionalTypeArgs TResult map({required TResult Function( _Started value) started,required TResult Function( _Changed value) changed,}){ +@optionalTypeArgs TResult map({required TResult Function( _Started value) started,required TResult Function( _Changed value) changed,required TResult Function( _Filtered value) filtered,required TResult Function( _Rated value) rated,}){ final _that = this; switch (_that) { case _Started(): return started(_that);case _Changed(): -return changed(_that);case _: +return changed(_that);case _Filtered(): +return filtered(_that);case _Rated(): +return rated(_that);case _: throw StateError('Unexpected subclass'); } @@ -100,12 +104,14 @@ return changed(_that);case _: /// } /// ``` -@optionalTypeArgs TResult? mapOrNull({TResult? Function( _Started value)? started,TResult? Function( _Changed value)? changed,}){ +@optionalTypeArgs TResult? mapOrNull({TResult? Function( _Started value)? started,TResult? Function( _Changed value)? changed,TResult? Function( _Filtered value)? filtered,TResult? Function( _Rated value)? rated,}){ final _that = this; switch (_that) { case _Started() when started != null: return started(_that);case _Changed() when changed != null: -return changed(_that);case _: +return changed(_that);case _Filtered() when filtered != null: +return filtered(_that);case _Rated() when rated != null: +return rated(_that);case _: return null; } @@ -122,11 +128,13 @@ return changed(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen({TResult Function()? started,TResult Function( int index)? changed,required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen({TResult Function()? started,TResult Function( int index)? changed,TResult Function( String filter)? filtered,TResult Function( List filter)? rated,required TResult orElse(),}) {final _that = this; switch (_that) { case _Started() when started != null: return started();case _Changed() when changed != null: -return changed(_that.index);case _: +return changed(_that.index);case _Filtered() when filtered != null: +return filtered(_that.filter);case _Rated() when rated != null: +return rated(_that.filter);case _: return orElse(); } @@ -144,11 +152,13 @@ return changed(_that.index);case _: /// } /// ``` -@optionalTypeArgs TResult when({required TResult Function() started,required TResult Function( int index) changed,}) {final _that = this; +@optionalTypeArgs TResult when({required TResult Function() started,required TResult Function( int index) changed,required TResult Function( String filter) filtered,required TResult Function( List filter) rated,}) {final _that = this; switch (_that) { case _Started(): return started();case _Changed(): -return changed(_that.index);case _: +return changed(_that.index);case _Filtered(): +return filtered(_that.filter);case _Rated(): +return rated(_that.filter);case _: throw StateError('Unexpected subclass'); } @@ -165,11 +175,13 @@ return changed(_that.index);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull({TResult? Function()? started,TResult? Function( int index)? changed,}) {final _that = this; +@optionalTypeArgs TResult? whenOrNull({TResult? Function()? started,TResult? Function( int index)? changed,TResult? Function( String filter)? filtered,TResult? Function( List filter)? rated,}) {final _that = this; switch (_that) { case _Started() when started != null: return started();case _Changed() when changed != null: -return changed(_that.index);case _: +return changed(_that.index);case _Filtered() when filtered != null: +return filtered(_that.filter);case _Rated() when rated != null: +return rated(_that.filter);case _: return null; } @@ -273,12 +285,150 @@ as int, } +} + +/// @nodoc + + +class _Filtered implements HomeEvent { + const _Filtered(this.filter); + + + final String filter; + +/// Create a copy of HomeEvent +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$FilteredCopyWith<_Filtered> get copyWith => __$FilteredCopyWithImpl<_Filtered>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Filtered&&(identical(other.filter, filter) || other.filter == filter)); +} + + +@override +int get hashCode => Object.hash(runtimeType,filter); + +@override +String toString() { + return 'HomeEvent.filtered(filter: $filter)'; +} + + +} + +/// @nodoc +abstract mixin class _$FilteredCopyWith<$Res> implements $HomeEventCopyWith<$Res> { + factory _$FilteredCopyWith(_Filtered value, $Res Function(_Filtered) _then) = __$FilteredCopyWithImpl; +@useResult +$Res call({ + String filter +}); + + + + +} +/// @nodoc +class __$FilteredCopyWithImpl<$Res> + implements _$FilteredCopyWith<$Res> { + __$FilteredCopyWithImpl(this._self, this._then); + + final _Filtered _self; + final $Res Function(_Filtered) _then; + +/// Create a copy of HomeEvent +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') $Res call({Object? filter = null,}) { + return _then(_Filtered( +null == filter ? _self.filter : filter // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +/// @nodoc + + +class _Rated implements HomeEvent { + const _Rated(final List filter): _filter = filter; + + + final List _filter; + List get filter { + if (_filter is EqualUnmodifiableListView) return _filter; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_filter); +} + + +/// Create a copy of HomeEvent +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RatedCopyWith<_Rated> get copyWith => __$RatedCopyWithImpl<_Rated>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Rated&&const DeepCollectionEquality().equals(other._filter, _filter)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_filter)); + +@override +String toString() { + return 'HomeEvent.rated(filter: $filter)'; +} + + +} + +/// @nodoc +abstract mixin class _$RatedCopyWith<$Res> implements $HomeEventCopyWith<$Res> { + factory _$RatedCopyWith(_Rated value, $Res Function(_Rated) _then) = __$RatedCopyWithImpl; +@useResult +$Res call({ + List filter +}); + + + + +} +/// @nodoc +class __$RatedCopyWithImpl<$Res> + implements _$RatedCopyWith<$Res> { + __$RatedCopyWithImpl(this._self, this._then); + + final _Rated _self; + final $Res Function(_Rated) _then; + +/// Create a copy of HomeEvent +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') $Res call({Object? filter = null,}) { + return _then(_Rated( +null == filter ? _self._filter : filter // ignore: cast_nullable_to_non_nullable +as List, + )); +} + + } /// @nodoc mixin _$HomeState { - int get currentIndex; + int get currentIndex; List get filters; List get rating; /// Create a copy of HomeState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -289,16 +439,16 @@ $HomeStateCopyWith get copyWith => _$HomeStateCopyWithImpl @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&const DeepCollectionEquality().equals(other.filters, filters)&&const DeepCollectionEquality().equals(other.rating, rating)); } @override -int get hashCode => Object.hash(runtimeType,currentIndex); +int get hashCode => Object.hash(runtimeType,currentIndex,const DeepCollectionEquality().hash(filters),const DeepCollectionEquality().hash(rating)); @override String toString() { - return 'HomeState(currentIndex: $currentIndex)'; + return 'HomeState(currentIndex: $currentIndex, filters: $filters, rating: $rating)'; } @@ -309,7 +459,7 @@ abstract mixin class $HomeStateCopyWith<$Res> { factory $HomeStateCopyWith(HomeState value, $Res Function(HomeState) _then) = _$HomeStateCopyWithImpl; @useResult $Res call({ - int currentIndex + int currentIndex, List filters, List rating }); @@ -326,10 +476,12 @@ class _$HomeStateCopyWithImpl<$Res> /// Create a copy of HomeState /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? currentIndex = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? currentIndex = null,Object? filters = null,Object? rating = null,}) { return _then(_self.copyWith( currentIndex: null == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable -as int, +as int,filters: null == filters ? _self.filters : filters // ignore: cast_nullable_to_non_nullable +as List,rating: null == rating ? _self.rating : rating // ignore: cast_nullable_to_non_nullable +as List, )); } @@ -414,10 +566,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( int currentIndex)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( int currentIndex, List filters, List rating)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _HomeState() when $default != null: -return $default(_that.currentIndex);case _: +return $default(_that.currentIndex,_that.filters,_that.rating);case _: return orElse(); } @@ -435,10 +587,10 @@ return $default(_that.currentIndex);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( int currentIndex) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( int currentIndex, List filters, List rating) $default,) {final _that = this; switch (_that) { case _HomeState(): -return $default(_that.currentIndex);case _: +return $default(_that.currentIndex,_that.filters,_that.rating);case _: throw StateError('Unexpected subclass'); } @@ -455,10 +607,10 @@ return $default(_that.currentIndex);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( int currentIndex)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( int currentIndex, List filters, List rating)? $default,) {final _that = this; switch (_that) { case _HomeState() when $default != null: -return $default(_that.currentIndex);case _: +return $default(_that.currentIndex,_that.filters,_that.rating);case _: return null; } @@ -470,10 +622,24 @@ return $default(_that.currentIndex);case _: class _HomeState implements HomeState { - const _HomeState({this.currentIndex = 0}); + const _HomeState({this.currentIndex = 0, final List filters = const [], final List rating = const []}): _filters = filters,_rating = rating; @override@JsonKey() final int currentIndex; + final List _filters; +@override@JsonKey() List get filters { + if (_filters is EqualUnmodifiableListView) return _filters; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_filters); +} + + final List _rating; +@override@JsonKey() List get rating { + if (_rating is EqualUnmodifiableListView) return _rating; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_rating); +} + /// Create a copy of HomeState /// with the given fields replaced by the non-null parameter values. @@ -485,16 +651,16 @@ _$HomeStateCopyWith<_HomeState> get copyWith => __$HomeStateCopyWithImpl<_HomeSt @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&const DeepCollectionEquality().equals(other._filters, _filters)&&const DeepCollectionEquality().equals(other._rating, _rating)); } @override -int get hashCode => Object.hash(runtimeType,currentIndex); +int get hashCode => Object.hash(runtimeType,currentIndex,const DeepCollectionEquality().hash(_filters),const DeepCollectionEquality().hash(_rating)); @override String toString() { - return 'HomeState(currentIndex: $currentIndex)'; + return 'HomeState(currentIndex: $currentIndex, filters: $filters, rating: $rating)'; } @@ -505,7 +671,7 @@ abstract mixin class _$HomeStateCopyWith<$Res> implements $HomeStateCopyWith<$Re factory _$HomeStateCopyWith(_HomeState value, $Res Function(_HomeState) _then) = __$HomeStateCopyWithImpl; @override @useResult $Res call({ - int currentIndex + int currentIndex, List filters, List rating }); @@ -522,10 +688,12 @@ class __$HomeStateCopyWithImpl<$Res> /// Create a copy of HomeState /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? currentIndex = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? currentIndex = null,Object? filters = null,Object? rating = null,}) { return _then(_HomeState( currentIndex: null == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable -as int, +as int,filters: null == filters ? _self._filters : filters // ignore: cast_nullable_to_non_nullable +as List,rating: null == rating ? _self._rating : rating // ignore: cast_nullable_to_non_nullable +as List, )); } diff --git a/lib/feature/home/presentation/blocs/home_bloc/home_event.dart b/lib/feature/home/presentation/blocs/home_bloc/home_event.dart index 051abcd..1a4661f 100644 --- a/lib/feature/home/presentation/blocs/home_bloc/home_event.dart +++ b/lib/feature/home/presentation/blocs/home_bloc/home_event.dart @@ -4,5 +4,7 @@ part of 'home_bloc.dart'; class HomeEvent with _$HomeEvent { const factory HomeEvent.started() = _Started; const factory HomeEvent.changed(int index) = _Changed; + const factory HomeEvent.filtered(String filter) = _Filtered; + const factory HomeEvent.rated(List filter) = _Rated; } diff --git a/lib/feature/home/presentation/blocs/home_bloc/home_state.dart b/lib/feature/home/presentation/blocs/home_bloc/home_state.dart index 2890caf..280762b 100644 --- a/lib/feature/home/presentation/blocs/home_bloc/home_state.dart +++ b/lib/feature/home/presentation/blocs/home_bloc/home_state.dart @@ -3,6 +3,9 @@ part of 'home_bloc.dart'; @freezed abstract class HomeState with _$HomeState { const factory HomeState({ - @Default(0) int currentIndex -}) = _HomeState; + @Default(0) int currentIndex, + @Default([]) List filters, + @Default([]) List rating + + }) = _HomeState; } diff --git a/lib/feature/home/presentation/pages/home_page/widgets/w_delivery_header.dart b/lib/feature/home/presentation/pages/home_page/widgets/w_delivery_header.dart index 87839a6..8908fac 100644 --- a/lib/feature/home/presentation/pages/home_page/widgets/w_delivery_header.dart +++ b/lib/feature/home/presentation/pages/home_page/widgets/w_delivery_header.dart @@ -1,5 +1,3 @@ -import 'package:food_delivery_client/feature/home/presentation/pages/categories_page/categories_page.dart'; - import '../../../../../../food_delivery_client.dart'; class WDeliveryHeader extends StatelessWidget { @@ -13,55 +11,167 @@ class WDeliveryHeader extends StatelessWidget { context.loc.petSupplies, context.loc.more, ]; - return Column( - children: [ - 15.verticalSpace, - Row( - spacing: 12, + /* + Siz uchun + Eng ommabop, + Reyting + Yetkazib berish vaqti, + Aksiyalar + + + */ + List titles = [ + '', + context.loc.pickedForYou, + context.loc.mostPopular, + context.loc.rating, + context.loc.deliveryTime, + context.loc.deals, + ]; + return BlocBuilder( + builder: (context, state) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - WCategoriesHeaderItem( - onTap: () {}, - text: context.loc.american, - imageUrl: AppImages.imgAmerican, - ), - WCategoriesHeaderItem( - onTap: () {}, - text: context.loc.grocery, - imageUrl: AppImages.imgGrocery, + Column( + children: [ + 15.verticalSpace, + Row( + spacing: 12, + children: [ + WCategoriesHeaderItem( + onTap: () {}, + text: context.loc.american, + imageUrl: AppImages.imgAmerican, + ), + WCategoriesHeaderItem( + onTap: () {}, + text: context.loc.grocery, + imageUrl: AppImages.imgGrocery, + ), + ], + ), + 8.verticalSpace, + GridView.builder( + shrinkWrap: true, + itemCount: _titles.length, + padding: EdgeInsets.zero, + scrollDirection: Axis.vertical, + physics: const NeverScrollableScrollPhysics(), + keyboardDismissBehavior: + ScrollViewKeyboardDismissBehavior.onDrag, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 5, + mainAxisSpacing: 10, + mainAxisExtent: 118, + // childAspectRatio: 78 / 100, + ), + itemBuilder: (context, index) => WCategoryItem( + onTap: () { + if (index == 3) { + CategoriesPage().show(context); + } + }, + imgUrl: index != 3 ? _images[index] : null, + text: _titles[index], + child: index == 3 + ? SizedBox( + height: 55, + width: 55, + child: Icon(Icons.more_horiz), + ) + : null, + ), + ), + ], + ).paddingSymmetric(horizontal: 15), + 15.verticalSpace, + + SizedBox( + height: 40, + child: ListView.separated( + padding: EdgeInsets.symmetric(horizontal: 15), + scrollDirection: Axis.horizontal, + itemCount: titles.length, + physics: const AlwaysScrollableScrollPhysics(), + separatorBuilder: (context, index) => 10.horizontalSpace, + itemBuilder: (context, index) => InkWell( + onTap: () async { + if (index != 3 && index != 0) { + context.read().add( + HomeEvent.filtered(titles[index]), + ); + } + + if (index == 3) { + final response = await WRatingBottomSheet( + savedRatings: state.rating ?? [], + ).show(context); + + if (response != null) { + context.read().add( + HomeEvent.rated(response ?? []), + ); + } + } + }, + borderRadius: AppUtils.kBorderRadius25, + child: Ink( + padding: EdgeInsets.zero, + decoration: BoxDecoration( + color: AppColors.cEEEEEE, + borderRadius: AppUtils.kBorderRadius25, + ), + child: Row( + children: [ + if (index != 0 && state.filters.contains(titles[index])) + SvgPicture.asset( + AppIcons.icCheck1, + ).paddingOnly(right: 5), + if (index == 0) + Badge( + isLabelVisible: + state.filters.isNotEmpty || + state.rating.isNotEmpty, + backgroundColor: AppColors.c34A853, + child: SvgPicture.asset(AppIcons.icFilter), + ).paddingSymmetric(vertical: 6), + + if (index == 3 && state.rating.isNotEmpty) + SizedBox( + height: 25, + width: 25, + child: DecoratedBox( + decoration: BoxDecoration( + color: AppColors.c34A853, + borderRadius: AppUtils.kBorderRadius16, + ), + child: Center( + child: Text( + "${state.rating.length}", + style: AppTextStyles.size14Regular.copyWith( + color: AppColors.cFFFFFF, + ), + ), + ), + ), + ).paddingOnly(right: 8), + Text(titles[index], style: AppTextStyles.size14Medium), + if (index == 3) Icon(Icons.keyboard_arrow_down), + ], + ).paddingSymmetric(vertical: 0, horizontal: 15), + ), + ), + ), ), + + 10.verticalSpace, + WDivider(), ], - ), - 8.verticalSpace, - GridView.builder( - shrinkWrap: true, - itemCount: _titles.length, - padding: EdgeInsets.zero, - scrollDirection: Axis.vertical, - physics: const NeverScrollableScrollPhysics(), - keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 5, - mainAxisSpacing: 10, - childAspectRatio: 78 / 100, - ), - itemBuilder: (context, index) => WCategoryItem( - onTap: () { - if (index == 3) { - CategoriesPage().show(context); - } - }, - imgUrl: index != 3 ? _images[index] : null, - text: _titles[index], - child: index == 3 - ? SizedBox(height: 55, width: 55, child: Icon(Icons.more_horiz)) - : null, - ), - ), - 8.verticalSpace, - WDivider() - ], - ).paddingSymmetric(horizontal: 15); + ); + }, + ); } } diff --git a/lib/feature/home/presentation/pages/home_page/widgets/w_home_headers.dart b/lib/feature/home/presentation/pages/home_page/widgets/w_home_headers.dart index cede191..06712db 100644 --- a/lib/feature/home/presentation/pages/home_page/widgets/w_home_headers.dart +++ b/lib/feature/home/presentation/pages/home_page/widgets/w_home_headers.dart @@ -9,6 +9,8 @@ class WHomeHeader extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { + + return DecoratedBox( decoration: BoxDecoration(color: AppColors.cFFFFFF), child: Column( diff --git a/lib/feature/home/presentation/pages/home_page/widgets/w_rating_btm_sheet.dart b/lib/feature/home/presentation/pages/home_page/widgets/w_rating_btm_sheet.dart new file mode 100644 index 0000000..30d29bf --- /dev/null +++ b/lib/feature/home/presentation/pages/home_page/widgets/w_rating_btm_sheet.dart @@ -0,0 +1,133 @@ +import '../../../../../../food_delivery_client.dart'; + +class WRatingBottomSheet extends StatefulWidget { + const WRatingBottomSheet({super.key, required this.savedRatings}); + + final List savedRatings; + + Future?> show(BuildContext context) { + return showModalBottomSheet>( + context: context, + builder: (context) => Wrap(children: [this]), + ); + } + + @override + State createState() => _WRatingBottomSheetState(); +} + +class _WRatingBottomSheetState extends State { + List rating = []; + + void updateRating(String value) { + final list = List.from(rating); + if (list.contains(value)) { + list.remove(value); + setState(() { + rating = list; + }); + } else { + list.add(value); + setState(() { + rating = list; + }); + } + } + + @override + void initState() { + rating = widget.savedRatings; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final List value = [ + "${context.loc.atLeast} 4,9", + "${context.loc.atLeast} 4,7", + "${context.loc.atLeast} 4,5", + ]; + + return WCustomModalBottomSheet( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(context.loc.rating, style: AppTextStyles.size20Medium), + IconButton( + onPressed: () { + context.pop(null); + }, + icon: SvgPicture.asset(AppIcons.icClose, height: 15), + ), + ], + ), + 15.verticalSpace, + Wrap( + spacing: 10, + children: List.generate(value.length, (index) { + return WRatingButton( + onTap: () { + updateRating(value[index]); + }, + isActive: rating.contains(value[index]), + rating: value[index], + ); + }), + ), + 25.verticalSpace, + AppButton( + name: context.loc.apply, + onPressed: () { + context.pop(rating); + }, + ), + 20.verticalSpace, + ], + ).paddingSymmetric(horizontal: 15), + ); + } +} + +class WRatingButton extends StatelessWidget { + const WRatingButton({ + super.key, + required this.onTap, + required this.isActive, + required this.rating, + }); + + final VoidCallback onTap; + final bool isActive; + final String rating; + + @override + Widget build(BuildContext context) { + return InkWell( + borderRadius: AppUtils.kBorderRadius25, + onTap: onTap, + child: Ink( + decoration: BoxDecoration( + color: isActive + ? AppColors.c34A853 + : AppColors.cE6E6E6.newWithOpacity(.6), + borderRadius: AppUtils.kBorderRadius25, + ), + child: Row( + spacing: 4, + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.star, color: AppColors.cYellow), + Text( + rating, + style: AppTextStyles.size14Medium.copyWith( + color: isActive ? AppColors.cFFFFFF : AppColors.c000000, + ), + ), + ], + ).paddingSymmetric(vertical: 6, horizontal: 10), + ), + ); + } +} diff --git a/lib/food_delivery_client.dart b/lib/food_delivery_client.dart index 4605f52..12574fe 100644 --- a/lib/food_delivery_client.dart +++ b/lib/food_delivery_client.dart @@ -19,3 +19,4 @@ export 'package:freezed_annotation/freezed_annotation.dart'; export 'package:shared_preferences/shared_preferences.dart'; export 'package:cached_network_image/cached_network_image.dart'; export 'package:carousel_slider/carousel_slider.dart'; +export 'package:flutter_bounceable/flutter_bounceable.dart';