diff --git a/assets/icons/ic_clock.svg b/assets/icons/ic_clock.svg
new file mode 100644
index 0000000..fdc8a5b
--- /dev/null
+++ b/assets/icons/ic_clock.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/translations/app_en.arb b/assets/translations/app_en.arb
index 90ec32a..baf37fd 100644
--- a/assets/translations/app_en.arb
+++ b/assets/translations/app_en.arb
@@ -77,7 +77,13 @@
"halal": "Halal",
"allergyFriendly": "Allergy friendly",
"atLeast":"At least",
- "apply": "Apply"
+ "apply": "Apply",
+ "pickedForYouDefault": "Picked for you (default)",
+ "popular": "Most popular",
+ "topRated": "Top rated",
+ "fast": "Fast",
+ "delivery": "Delivery"
+
diff --git a/assets/translations/app_ru.arb b/assets/translations/app_ru.arb
index e1ea54b..44e92aa 100644
--- a/assets/translations/app_ru.arb
+++ b/assets/translations/app_ru.arb
@@ -84,7 +84,13 @@
"halal": "Халяль",
"allergyFriendly": "Без аллергенов",
"atLeast":"Kак минимум",
- "apply": "Применить"
+ "apply": "Применить",
+ "pickedForYouDefault": "Выбрано для вас (по умолчанию)",
+ "popular": "Самые популярные",
+ "topRated": "Высокий рейтинг",
+ "fast": "Быстро",
+ "delivery": "Доставка"
+
diff --git a/assets/translations/app_uz.arb b/assets/translations/app_uz.arb
index 13d32ea..8b65ce5 100644
--- a/assets/translations/app_uz.arb
+++ b/assets/translations/app_uz.arb
@@ -84,7 +84,13 @@
"halal": "Halol",
"allergyFriendly": "Allergiyaga mos",
"atLeast":"Kаmida",
- "apply": "Qo‘llash"
+ "apply": "Qo‘llash",
+ "pickedForYouDefault": "Siz uchun tanlangan (standart)",
+ "popular": "Eng ommabop",
+ "topRated": "Yuqori reytingli",
+ "fast": "Tezkor",
+ "delivery": "Yetkazish"
+
}
diff --git a/lib/core/l10n/app_localizations.dart b/lib/core/l10n/app_localizations.dart
index 50461c8..f0c723d 100644
--- a/lib/core/l10n/app_localizations.dart
+++ b/lib/core/l10n/app_localizations.dart
@@ -483,6 +483,30 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Apply'**
String get apply;
+
+ /// No description provided for @pickedForYouDefault.
+ ///
+ /// In en, this message translates to:
+ /// **'Picked for you (default)'**
+ String get pickedForYouDefault;
+
+ /// No description provided for @popular.
+ ///
+ /// In en, this message translates to:
+ /// **'Most popular'**
+ String get popular;
+
+ /// No description provided for @topRated.
+ ///
+ /// In en, this message translates to:
+ /// **'Top rated'**
+ String get topRated;
+
+ /// No description provided for @fast.
+ ///
+ /// In en, this message translates to:
+ /// **'Fast'**
+ String get fast;
}
class _AppLocalizationsDelegate
diff --git a/lib/core/l10n/app_localizations_en.dart b/lib/core/l10n/app_localizations_en.dart
index c141639..87ec60a 100644
--- a/lib/core/l10n/app_localizations_en.dart
+++ b/lib/core/l10n/app_localizations_en.dart
@@ -204,4 +204,16 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get apply => 'Apply';
+
+ @override
+ String get pickedForYouDefault => 'Picked for you (default)';
+
+ @override
+ String get popular => 'Most popular';
+
+ @override
+ String get topRated => 'Top rated';
+
+ @override
+ String get fast => 'Fast';
}
diff --git a/lib/core/l10n/app_localizations_ru.dart b/lib/core/l10n/app_localizations_ru.dart
index 62a46fa..c97a2fa 100644
--- a/lib/core/l10n/app_localizations_ru.dart
+++ b/lib/core/l10n/app_localizations_ru.dart
@@ -205,4 +205,16 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get apply => 'Применить';
+
+ @override
+ String get pickedForYouDefault => 'Выбрано для вас (по умолчанию)';
+
+ @override
+ String get popular => 'Самые популярные';
+
+ @override
+ String get topRated => 'Высокий рейтинг';
+
+ @override
+ String get fast => 'Быстро';
}
diff --git a/lib/core/l10n/app_localizations_uz.dart b/lib/core/l10n/app_localizations_uz.dart
index 323e137..f5bf7ee 100644
--- a/lib/core/l10n/app_localizations_uz.dart
+++ b/lib/core/l10n/app_localizations_uz.dart
@@ -54,7 +54,7 @@ class AppLocalizationsUz extends AppLocalizations {
}
@override
- String get delivery => 'Yetkazib berish';
+ String get delivery => 'Yetkazish';
@override
String get pickUp => 'Olib ketish';
@@ -205,4 +205,16 @@ class AppLocalizationsUz extends AppLocalizations {
@override
String get apply => 'Qo‘llash';
+
+ @override
+ String get pickedForYouDefault => 'Siz uchun tanlangan (standart)';
+
+ @override
+ String get popular => 'Eng ommabop';
+
+ @override
+ String get topRated => 'Yuqori reytingli';
+
+ @override
+ String get fast => 'Tezkor';
}
diff --git a/lib/core/router/app_routes.dart b/lib/core/router/app_routes.dart
index 27faa14..62e6fe4 100644
--- a/lib/core/router/app_routes.dart
+++ b/lib/core/router/app_routes.dart
@@ -1,6 +1,4 @@
import 'package:flutter/cupertino.dart';
-import 'package:food_delivery_client/feature/home/presentation/pages/categories_page/categories_page.dart';
-import 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';
import '../../food_delivery_client.dart';
@@ -22,6 +20,12 @@ class AppRoutes {
path: Routes.categories,
pageBuilder: (context, state) => CupertinoPage(child: CategoriesPage()),
),
+ GoRoute(
+ path: Routes.filters,
+ pageBuilder: (context, state) => CupertinoPage(child: FiltersPage(
+ homeBloc: state.extra as HomeBloc,
+ )),
+ ),
],
);
}
diff --git a/lib/core/router/routes_name.dart b/lib/core/router/routes_name.dart
index 46c0f2d..e400c8a 100644
--- a/lib/core/router/routes_name.dart
+++ b/lib/core/router/routes_name.dart
@@ -4,5 +4,7 @@ abstract class Routes {
static const String register = '/register';
static const String main = '/main';
static const String categories = '/categories';
+ static const String filters= '/filters';
+
}
diff --git a/lib/core/theme/app_icons.dart b/lib/core/theme/app_icons.dart
index deb75d5..5462d8e 100644
--- a/lib/core/theme/app_icons.dart
+++ b/lib/core/theme/app_icons.dart
@@ -42,5 +42,5 @@ abstract class AppIcons {
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";
+ static const String icClock = "$baseUrl/ic_clock.svg";
}
diff --git a/lib/core/theme/app_textstyles.dart b/lib/core/theme/app_textstyles.dart
index 99b8a00..33547af 100644
--- a/lib/core/theme/app_textstyles.dart
+++ b/lib/core/theme/app_textstyles.dart
@@ -28,6 +28,13 @@ abstract class AppTextStyles {
fontWeight: FontWeight.w400,
);
+ static const TextStyle size16Regular = TextStyle(
+ color: _defaultColor,
+ fontSize: SizesCons.size_16,
+ fontFamily: _fontRegular,
+ fontWeight: FontWeight.w400,
+ );
+
static const TextStyle size20Regular = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_20,
diff --git a/lib/feature/common/presentation/widgets/app_list_tile.dart b/lib/feature/common/presentation/widgets/app_list_tile.dart
new file mode 100644
index 0000000..27eec38
--- /dev/null
+++ b/lib/feature/common/presentation/widgets/app_list_tile.dart
@@ -0,0 +1,44 @@
+import '../../../../food_delivery_client.dart';
+
+class AppListTile extends StatelessWidget {
+ const AppListTile({
+ super.key,
+ required this.onPressed,
+ required this.isSelected,
+ required this.svgPath,
+ required this.title,
+ this.contentPadding,
+ this.leading,
+ this.titleWidget,
+ this.trailing,
+ this.titleTextStyle,
+ this.subTitle,
+ });
+
+ final VoidCallback onPressed;
+ final bool isSelected;
+ final String svgPath;
+ final String title;
+ final EdgeInsets? contentPadding;
+ final Widget? leading;
+ final Widget? titleWidget;
+ final Widget? trailing;
+ final TextStyle? titleTextStyle;
+ final Widget? subTitle;
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ onTap: onPressed,
+ subtitle: subTitle,
+ contentPadding:
+ contentPadding ?? EdgeInsetsGeometry.only(left: 20, right: 27),
+ leading: leading ?? SvgPicture.asset(svgPath),
+ title:
+ titleWidget ??
+ Text(title, style: titleTextStyle ?? AppTextStyles.size16Regular),
+ trailing:
+ trailing ?? (isSelected ? SvgPicture.asset(AppIcons.icCheck) : null),
+ );
+ }
+}
diff --git a/lib/feature/common/presentation/widgets/widgets.dart b/lib/feature/common/presentation/widgets/widgets.dart
index 6261541..d4e2f78 100644
--- a/lib/feature/common/presentation/widgets/widgets.dart
+++ b/lib/feature/common/presentation/widgets/widgets.dart
@@ -5,3 +5,4 @@ export 'w_see_all_raw.dart';
export 'w_stories_list_item.dart';
export 'w_custom_modal_bottom_sheet.dart';
export 'app_button.dart';
+export 'app_list_tile.dart';
diff --git a/lib/feature/home/home.dart b/lib/feature/home/home.dart
index 31cbfa3..7fdc6e6 100644
--- a/lib/feature/home/home.dart
+++ b/lib/feature/home/home.dart
@@ -12,3 +12,11 @@ export 'package:food_delivery_client/feature/home/presentation/pages/home_page/w
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';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/filters_page.dart';
+export 'presentation/mixins/filter_mixins.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filter_app_bar.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filters_body.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_delivery_duration.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filter_dietary.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filters_deals.dart';
+export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart';
\ No newline at end of file
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 efb321f..f67a90b 100644
--- a/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart
+++ b/lib/feature/home/presentation/blocs/home_bloc/home_bloc.dart
@@ -12,6 +12,7 @@ class HomeBloc extends Bloc {
on<_Changed>(_onChanged);
on<_Filtered>(_onFiltered);
on<_Rated>(_onRated);
+ on<_DurationChanged>(_onDurationChanged);
}
void _onChanged(_Changed event, Emitter emit) {
@@ -29,9 +30,11 @@ class HomeBloc extends Bloc {
}
}
-
- void _onRated(_Rated event, Emitter emit){
+ void _onRated(_Rated event, Emitter emit) {
emit(state.copyWith(rating: event.filter));
+ }
+ void _onDurationChanged(_DurationChanged event, Emitter emit) {
+ emit(state.copyWith(deliveryDuration: 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 718c3ca..df01d4c 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,13 @@ extension HomeEventPatterns on HomeEvent {
/// }
/// ```
-@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(),}){
+@optionalTypeArgs TResult maybeMap({TResult Function( _Started value)? started,TResult Function( _Changed value)? changed,TResult Function( _DurationChanged value)? durationChanged,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 _Filtered() when filtered != null:
+return changed(_that);case _DurationChanged() when durationChanged != null:
+return durationChanged(_that);case _Filtered() when filtered != null:
return filtered(_that);case _Rated() when rated != null:
return rated(_that);case _:
return orElse();
@@ -80,12 +81,13 @@ return rated(_that);case _:
/// }
/// ```
-@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,}){
+@optionalTypeArgs TResult map({required TResult Function( _Started value) started,required TResult Function( _Changed value) changed,required TResult Function( _DurationChanged value) durationChanged,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 _Filtered():
+return changed(_that);case _DurationChanged():
+return durationChanged(_that);case _Filtered():
return filtered(_that);case _Rated():
return rated(_that);case _:
throw StateError('Unexpected subclass');
@@ -104,12 +106,13 @@ return rated(_that);case _:
/// }
/// ```
-@optionalTypeArgs TResult? mapOrNull({TResult? Function( _Started value)? started,TResult? Function( _Changed value)? changed,TResult? Function( _Filtered value)? filtered,TResult? Function( _Rated value)? rated,}){
+@optionalTypeArgs TResult? mapOrNull({TResult? Function( _Started value)? started,TResult? Function( _Changed value)? changed,TResult? Function( _DurationChanged value)? durationChanged,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 _Filtered() when filtered != null:
+return changed(_that);case _DurationChanged() when durationChanged != null:
+return durationChanged(_that);case _Filtered() when filtered != null:
return filtered(_that);case _Rated() when rated != null:
return rated(_that);case _:
return null;
@@ -128,11 +131,12 @@ return rated(_that);case _:
/// }
/// ```
-@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;
+@optionalTypeArgs TResult maybeWhen({TResult Function()? started,TResult Function( int index)? changed,TResult Function( String filter)? durationChanged,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 _Filtered() when filtered != null:
+return changed(_that.index);case _DurationChanged() when durationChanged != null:
+return durationChanged(_that.filter);case _Filtered() when filtered != null:
return filtered(_that.filter);case _Rated() when rated != null:
return rated(_that.filter);case _:
return orElse();
@@ -152,11 +156,12 @@ return rated(_that.filter);case _:
/// }
/// ```
-@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;
+@optionalTypeArgs TResult when({required TResult Function() started,required TResult Function( int index) changed,required TResult Function( String filter) durationChanged,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 _Filtered():
+return changed(_that.index);case _DurationChanged():
+return durationChanged(_that.filter);case _Filtered():
return filtered(_that.filter);case _Rated():
return rated(_that.filter);case _:
throw StateError('Unexpected subclass');
@@ -175,11 +180,12 @@ return rated(_that.filter);case _:
/// }
/// ```
-@optionalTypeArgs TResult? whenOrNull({TResult? Function()? started,TResult? Function( int index)? changed,TResult? Function( String filter)? filtered,TResult? Function( List filter)? rated,}) {final _that = this;
+@optionalTypeArgs TResult? whenOrNull({TResult? Function()? started,TResult? Function( int index)? changed,TResult? Function( String filter)? durationChanged,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 _Filtered() when filtered != null:
+return changed(_that.index);case _DurationChanged() when durationChanged != null:
+return durationChanged(_that.filter);case _Filtered() when filtered != null:
return filtered(_that.filter);case _Rated() when rated != null:
return rated(_that.filter);case _:
return null;
@@ -290,6 +296,72 @@ as int,
/// @nodoc
+class _DurationChanged implements HomeEvent {
+ const _DurationChanged(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')
+_$DurationChangedCopyWith<_DurationChanged> get copyWith => __$DurationChangedCopyWithImpl<_DurationChanged>(this, _$identity);
+
+
+
+@override
+bool operator ==(Object other) {
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _DurationChanged&&(identical(other.filter, filter) || other.filter == filter));
+}
+
+
+@override
+int get hashCode => Object.hash(runtimeType,filter);
+
+@override
+String toString() {
+ return 'HomeEvent.durationChanged(filter: $filter)';
+}
+
+
+}
+
+/// @nodoc
+abstract mixin class _$DurationChangedCopyWith<$Res> implements $HomeEventCopyWith<$Res> {
+ factory _$DurationChangedCopyWith(_DurationChanged value, $Res Function(_DurationChanged) _then) = __$DurationChangedCopyWithImpl;
+@useResult
+$Res call({
+ String filter
+});
+
+
+
+
+}
+/// @nodoc
+class __$DurationChangedCopyWithImpl<$Res>
+ implements _$DurationChangedCopyWith<$Res> {
+ __$DurationChangedCopyWithImpl(this._self, this._then);
+
+ final _DurationChanged _self;
+ final $Res Function(_DurationChanged) _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(_DurationChanged(
+null == filter ? _self.filter : filter // ignore: cast_nullable_to_non_nullable
+as String,
+ ));
+}
+
+
+}
+
+/// @nodoc
+
+
class _Filtered implements HomeEvent {
const _Filtered(this.filter);
@@ -428,7 +500,7 @@ as List,
/// @nodoc
mixin _$HomeState {
- int get currentIndex; List get filters; List get rating;
+ int get currentIndex; String get deliveryDuration; 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)
@@ -439,16 +511,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)&&const DeepCollectionEquality().equals(other.filters, filters)&&const DeepCollectionEquality().equals(other.rating, rating));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&(identical(other.deliveryDuration, deliveryDuration) || other.deliveryDuration == deliveryDuration)&&const DeepCollectionEquality().equals(other.filters, filters)&&const DeepCollectionEquality().equals(other.rating, rating));
}
@override
-int get hashCode => Object.hash(runtimeType,currentIndex,const DeepCollectionEquality().hash(filters),const DeepCollectionEquality().hash(rating));
+int get hashCode => Object.hash(runtimeType,currentIndex,deliveryDuration,const DeepCollectionEquality().hash(filters),const DeepCollectionEquality().hash(rating));
@override
String toString() {
- return 'HomeState(currentIndex: $currentIndex, filters: $filters, rating: $rating)';
+ return 'HomeState(currentIndex: $currentIndex, deliveryDuration: $deliveryDuration, filters: $filters, rating: $rating)';
}
@@ -459,7 +531,7 @@ abstract mixin class $HomeStateCopyWith<$Res> {
factory $HomeStateCopyWith(HomeState value, $Res Function(HomeState) _then) = _$HomeStateCopyWithImpl;
@useResult
$Res call({
- int currentIndex, List filters, List rating
+ int currentIndex, String deliveryDuration, List filters, List rating
});
@@ -476,10 +548,11 @@ 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,Object? filters = null,Object? rating = null,}) {
+@pragma('vm:prefer-inline') @override $Res call({Object? currentIndex = null,Object? deliveryDuration = 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,filters: null == filters ? _self.filters : filters // ignore: cast_nullable_to_non_nullable
+as int,deliveryDuration: null == deliveryDuration ? _self.deliveryDuration : deliveryDuration // ignore: cast_nullable_to_non_nullable
+as String,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,
));
@@ -566,10 +639,10 @@ return $default(_that);case _:
/// }
/// ```
-@optionalTypeArgs TResult maybeWhen(TResult Function( int currentIndex, List filters, List rating)? $default,{required TResult orElse(),}) {final _that = this;
+@optionalTypeArgs TResult maybeWhen(TResult Function( int currentIndex, String deliveryDuration, List filters, List rating)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _HomeState() when $default != null:
-return $default(_that.currentIndex,_that.filters,_that.rating);case _:
+return $default(_that.currentIndex,_that.deliveryDuration,_that.filters,_that.rating);case _:
return orElse();
}
@@ -587,10 +660,10 @@ return $default(_that.currentIndex,_that.filters,_that.rating);case _:
/// }
/// ```
-@optionalTypeArgs TResult when(TResult Function( int currentIndex, List filters, List rating) $default,) {final _that = this;
+@optionalTypeArgs TResult when(TResult Function( int currentIndex, String deliveryDuration, List filters, List rating) $default,) {final _that = this;
switch (_that) {
case _HomeState():
-return $default(_that.currentIndex,_that.filters,_that.rating);case _:
+return $default(_that.currentIndex,_that.deliveryDuration,_that.filters,_that.rating);case _:
throw StateError('Unexpected subclass');
}
@@ -607,10 +680,10 @@ return $default(_that.currentIndex,_that.filters,_that.rating);case _:
/// }
/// ```
-@optionalTypeArgs TResult? whenOrNull(TResult? Function( int currentIndex, List filters, List rating)? $default,) {final _that = this;
+@optionalTypeArgs TResult? whenOrNull(TResult? Function( int currentIndex, String deliveryDuration, List filters, List rating)? $default,) {final _that = this;
switch (_that) {
case _HomeState() when $default != null:
-return $default(_that.currentIndex,_that.filters,_that.rating);case _:
+return $default(_that.currentIndex,_that.deliveryDuration,_that.filters,_that.rating);case _:
return null;
}
@@ -622,10 +695,11 @@ return $default(_that.currentIndex,_that.filters,_that.rating);case _:
class _HomeState implements HomeState {
- const _HomeState({this.currentIndex = 0, final List filters = const [], final List rating = const []}): _filters = filters,_rating = rating;
+ const _HomeState({this.currentIndex = 0, this.deliveryDuration = "60+", final List filters = const [], final List rating = const []}): _filters = filters,_rating = rating;
@override@JsonKey() final int currentIndex;
+@override@JsonKey() final String deliveryDuration;
final List _filters;
@override@JsonKey() List get filters {
if (_filters is EqualUnmodifiableListView) return _filters;
@@ -651,16 +725,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)&&const DeepCollectionEquality().equals(other._filters, _filters)&&const DeepCollectionEquality().equals(other._rating, _rating));
+ return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeState&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&(identical(other.deliveryDuration, deliveryDuration) || other.deliveryDuration == deliveryDuration)&&const DeepCollectionEquality().equals(other._filters, _filters)&&const DeepCollectionEquality().equals(other._rating, _rating));
}
@override
-int get hashCode => Object.hash(runtimeType,currentIndex,const DeepCollectionEquality().hash(_filters),const DeepCollectionEquality().hash(_rating));
+int get hashCode => Object.hash(runtimeType,currentIndex,deliveryDuration,const DeepCollectionEquality().hash(_filters),const DeepCollectionEquality().hash(_rating));
@override
String toString() {
- return 'HomeState(currentIndex: $currentIndex, filters: $filters, rating: $rating)';
+ return 'HomeState(currentIndex: $currentIndex, deliveryDuration: $deliveryDuration, filters: $filters, rating: $rating)';
}
@@ -671,7 +745,7 @@ abstract mixin class _$HomeStateCopyWith<$Res> implements $HomeStateCopyWith<$Re
factory _$HomeStateCopyWith(_HomeState value, $Res Function(_HomeState) _then) = __$HomeStateCopyWithImpl;
@override @useResult
$Res call({
- int currentIndex, List filters, List rating
+ int currentIndex, String deliveryDuration, List filters, List rating
});
@@ -688,10 +762,11 @@ 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,Object? filters = null,Object? rating = null,}) {
+@override @pragma('vm:prefer-inline') $Res call({Object? currentIndex = null,Object? deliveryDuration = null,Object? filters = null,Object? rating = null,}) {
return _then(_HomeState(
currentIndex: null == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable
-as int,filters: null == filters ? _self._filters : filters // ignore: cast_nullable_to_non_nullable
+as int,deliveryDuration: null == deliveryDuration ? _self.deliveryDuration : deliveryDuration // ignore: cast_nullable_to_non_nullable
+as String,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 1a4661f..7414fe1 100644
--- a/lib/feature/home/presentation/blocs/home_bloc/home_event.dart
+++ b/lib/feature/home/presentation/blocs/home_bloc/home_event.dart
@@ -4,6 +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.durationChanged(String filter) = _DurationChanged;
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 280762b..d03eb3e 100644
--- a/lib/feature/home/presentation/blocs/home_bloc/home_state.dart
+++ b/lib/feature/home/presentation/blocs/home_bloc/home_state.dart
@@ -4,6 +4,7 @@ part of 'home_bloc.dart';
abstract class HomeState with _$HomeState {
const factory HomeState({
@Default(0) int currentIndex,
+ @Default("60+") String deliveryDuration,
@Default([]) List filters,
@Default([]) List rating
diff --git a/lib/feature/home/presentation/mixins/filter_mixins.dart b/lib/feature/home/presentation/mixins/filter_mixins.dart
new file mode 100644
index 0000000..82465ce
--- /dev/null
+++ b/lib/feature/home/presentation/mixins/filter_mixins.dart
@@ -0,0 +1,20 @@
+import '../../../../core/theme/app_icons.dart';
+
+mixin FilterMixins {
+ final List deliveryDurations = ["30", "45", "60", "60+"];
+ final List filterSortSvgs = [
+ AppIcons.icPicked,
+ AppIcons.icMostPopular,
+ AppIcons.icStar,
+ AppIcons.icDeliveryTime,
+ ];
+
+ final List filterDietary = [
+ AppIcons.icVegetarian,
+ AppIcons.icVegen,
+ AppIcons.icGlutenFree,
+ AppIcons.icAllergyFriendly,
+ ];
+
+ final List filterDeals = [AppIcons.icDeals, AppIcons.icBestOverall];
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/filters_page.dart b/lib/feature/home/presentation/pages/filters_page/filters_page.dart
new file mode 100644
index 0000000..6602a9c
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/filters_page.dart
@@ -0,0 +1,26 @@
+
+import '../../../../../food_delivery_client.dart';
+
+class FiltersPage extends StatefulWidget {
+ const FiltersPage({super.key, required this.homeBloc});
+
+ final HomeBloc homeBloc;
+
+ @override
+ State createState() => _FiltersPageState();
+}
+
+class _FiltersPageState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider.value(
+ value: widget.homeBloc,
+ child: BlocBuilder(
+ builder: (context, state) {
+ return WFiltersBody();
+ },
+ ),
+ );
+ }
+}
+
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_delivery_duration.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_delivery_duration.dart
new file mode 100644
index 0000000..762f619
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_delivery_duration.dart
@@ -0,0 +1,84 @@
+import '../../../../../../food_delivery_client.dart';
+
+class WDeliveryDuration extends StatelessWidget with FilterMixins {
+ WDeliveryDuration({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ context.loc.delivery,
+ style: AppTextStyles.size18Medium,
+ ).paddingSymmetric(horizontal: 20),
+ 15.verticalSpace,
+ SizedBox(
+ height: 60,
+ child: Stack(
+ alignment: AlignmentGeometry.center,
+ children: [
+ SizedBox(
+ height: 40,
+ width: context.w,
+ child: DecoratedBox(
+ decoration: BoxDecoration(
+ borderRadius: AppUtils.kBorderRadius8,
+ color: AppColors.cE6E6E6.newWithOpacity(.6),
+ ),
+ ),
+ ),
+ Material(
+ color: AppColors.cTransparent,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: List.generate(deliveryDurations.length, (
+ index,
+ ) {
+ final isActive =
+ state.deliveryDuration == deliveryDurations[index];
+ return InkWell(
+ onTap: () {
+ context.read().add(
+ HomeEvent.durationChanged(
+ deliveryDurations[index],
+ ),
+ );
+ },
+ borderRadius: AppUtils.kBorderRadius40,
+ child: Ink(
+ height: 60,
+ width: 60,
+ decoration: BoxDecoration(
+ color: isActive
+ ? AppColors.c34A853
+ : AppColors.cTransparent,
+ borderRadius: AppUtils.kBorderRadius40,
+ ),
+ child: Center(
+ child: Text(
+ deliveryDurations[index],
+ style: AppTextStyles.size16Medium.copyWith(
+ color: isActive
+ ? AppColors.cFFFFFF
+ : AppColors.c000000,
+ ),
+ ),
+ ),
+ ),
+ );
+ }),
+ ),
+ ),
+ ],
+ ),
+ ).paddingSymmetric(horizontal: 20),
+ 25.verticalSpace,
+ ],
+ );
+ },
+ );
+ }
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_app_bar.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_app_bar.dart
new file mode 100644
index 0000000..ae80c23
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_app_bar.dart
@@ -0,0 +1,25 @@
+import '../../../../../../food_delivery_client.dart';
+
+class WFiltersAppBar extends StatelessWidget {
+ const WFiltersAppBar({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return AppBar(
+ centerTitle: true,
+ elevation: 30,
+ bottomOpacity: 1,
+ scrolledUnderElevation: 10,
+ backgroundColor: AppColors.cFFFFFF,
+ surfaceTintColor: AppColors.cTransparent,
+ useDefaultSemanticsOrder: true,
+ leading: IconButton(
+ onPressed: () {
+ context.pop();
+ },
+ icon: SvgPicture.asset(AppIcons.icClose),
+ ),
+ title: Text(context.loc.allCategories, style: AppTextStyles.size20Medium),
+ );
+ }
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_dietary.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_dietary.dart
new file mode 100644
index 0000000..48cdffd
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_filter_dietary.dart
@@ -0,0 +1,38 @@
+import '../../../../../../food_delivery_client.dart';
+
+class WFilterDietary extends StatelessWidget with FilterMixins {
+ WFilterDietary({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final List dietaryTitles = [
+ context.loc.vegetarian,
+ context.loc.vegan,
+ context.loc.glutenFree,
+ context.loc.allergyFriendly,
+ ];
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 25.verticalSpace,
+ Text(
+ context.loc.dietary,
+ style: AppTextStyles.size18Medium,
+ ).paddingSymmetric(horizontal: 20),
+ 15.verticalSpace,
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: List.generate(4, (index) {
+ return AppListTile(
+ onPressed: () {},
+ isSelected: false,
+ leading: Image.asset(filterDietary[index], height: 30, width: 30),
+ svgPath: filterDietary[index],
+ title: dietaryTitles[index],
+ );
+ }),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_body.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_body.dart
new file mode 100644
index 0000000..5c5f4c6
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_body.dart
@@ -0,0 +1,42 @@
+import '../../../../../../food_delivery_client.dart';
+
+class WFiltersBody extends StatelessWidget {
+ const WFiltersBody({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return WLayout(
+ child: Scaffold(
+ appBar: PreferredSize(
+ preferredSize: Size.fromHeight(56),
+ child: WFiltersAppBar(),
+ ),
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ scrollDirection: Axis.vertical,
+ physics: const AlwaysScrollableScrollPhysics(),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 18.verticalSpace,
+ WDeliveryDuration(),
+ WFiltersSort(),
+ WFiltersDeals(),
+ WFilterDietary(),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_deals.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_deals.dart
new file mode 100644
index 0000000..74f3103
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_deals.dart
@@ -0,0 +1,59 @@
+import 'package:flutter/cupertino.dart';
+
+import '../../../../../../food_delivery_client.dart';
+
+class WFiltersDeals extends StatefulWidget {
+ const WFiltersDeals({super.key});
+
+ @override
+ State createState() => _WFiltersDealsState();
+}
+
+class _WFiltersDealsState extends State with FilterMixins {
+ List values = [false, false];
+
+ @override
+ Widget build(BuildContext context) {
+ final List dealsTitle = [
+ context.loc.deals,
+ context.loc.bestOverall,
+ ];
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ 25.verticalSpace,
+ Text(
+ "From Uber eats",
+ style: AppTextStyles.size18Medium,
+ ).paddingSymmetric(horizontal: 20),
+ 15.verticalSpace,
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: List.generate(2, (index) {
+ return AppListTile(
+ onPressed: () {
+ setState(() {
+ values[index] = !values[index];
+ });
+ },
+ isSelected: false,
+ leading: index == 0
+ ? SvgPicture.asset(filterDeals[index], height: 30, width: 30)
+ : Image.asset(filterDeals[index], height: 30, width: 30),
+ svgPath: filterDeals[index],
+ title: dealsTitle[index],
+ trailing: CupertinoSwitch(
+ value: values[index],
+ onChanged: (value) {
+ setState(() {
+ values[index] = !values[index];
+ });
+ },
+ ),
+ );
+ }),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart
new file mode 100644
index 0000000..604879d
--- /dev/null
+++ b/lib/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart
@@ -0,0 +1,60 @@
+import '../../../../../../food_delivery_client.dart';
+
+class WFiltersSort extends StatelessWidget with FilterMixins {
+ WFiltersSort({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final List filterSortTitles = [
+ context.loc.pickedForYouDefault,
+ context.loc.mostPopular,
+ context.loc.topRated,
+ context.loc.fast,
+ ];
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ context.loc.sort,
+ style: AppTextStyles.size18Medium,
+ ).paddingSymmetric(horizontal: 20),
+ 15.verticalSpace,
+ Column(
+ children: List.generate(filterSortTitles.length, (index) {
+ return AppListTile(
+ onPressed: () {},
+ isSelected: false,
+ svgPath: filterSortSvgs[index],
+ title: filterSortTitles[index],
+ );
+ }),
+ ),
+
+ // AppListTile(
+ // onPressed: () {},
+ // isSelected: true,
+ // svgPath: AppIcons.icPicked,
+ // title: context.loc.pickedForYouDefault,
+ // ),
+ // AppListTile(
+ // onPressed: () {},
+ // isSelected: false,
+ // svgPath: AppIcons.icMostPopular,
+ // title: context.loc.popular,
+ // ),
+ // AppListTile(
+ // onPressed: () {},
+ // isSelected: false,
+ // svgPath: AppIcons.icStar,
+ // title: context.loc.topRated,
+ // ),
+ // AppListTile(
+ // onPressed: () {},
+ // isSelected: false,
+ // svgPath: AppIcons.icClock,
+ // title: context.loc.fast,
+ // ),
+ ],
+ );
+ }
+}
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 06712db..4a4476b 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,8 +9,6 @@ class WHomeHeader extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder(
builder: (context, state) {
-
-
return DecoratedBox(
decoration: BoxDecoration(color: AppColors.cFFFFFF),
child: Column(
@@ -37,7 +35,12 @@ class WHomeHeader extends StatelessWidget {
Align(
alignment: AlignmentGeometry.topRight,
child: IconButton(
- onPressed: () {},
+ onPressed: () {
+ context.push(
+ Routes.filters,
+ extra: context.read(),
+ );
+ },
icon: SvgPicture.asset(
AppIcons.icFilter,
height: 36,
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
index 30d29bf..da7586b 100644
--- 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
@@ -66,6 +66,7 @@ class _WRatingBottomSheetState extends State {
15.verticalSpace,
Wrap(
spacing: 10,
+ runSpacing: 15,
children: List.generate(value.length, (index) {
return WRatingButton(
onTap: () {
diff --git a/lib/food_delivery_client.dart b/lib/food_delivery_client.dart
index 12574fe..29f8664 100644
--- a/lib/food_delivery_client.dart
+++ b/lib/food_delivery_client.dart
@@ -20,3 +20,4 @@ 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';
+export 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';