feat: filters added to home page

This commit is contained in:
jahongireshonqulov
2025-10-24 14:54:08 +05:00
parent 41d8a38471
commit f2ab615b4e
30 changed files with 1159 additions and 86 deletions

View File

@@ -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<HomeBloc, HomeState>(
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<HomeBloc>().add(
HomeEvent.filtered(titles[index]),
);
}
if (index == 3) {
final response = await WRatingBottomSheet(
savedRatings: state.rating ?? [],
).show(context);
if (response != null) {
context.read<HomeBloc>().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);
);
},
);
}
}

View File

@@ -9,6 +9,8 @@ class WHomeHeader extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<HomeBloc, HomeState>(
builder: (context, state) {
return DecoratedBox(
decoration: BoxDecoration(color: AppColors.cFFFFFF),
child: Column(

View File

@@ -0,0 +1,133 @@
import '../../../../../../food_delivery_client.dart';
class WRatingBottomSheet extends StatefulWidget {
const WRatingBottomSheet({super.key, required this.savedRatings});
final List<String> savedRatings;
Future<List<String>?> show(BuildContext context) {
return showModalBottomSheet<List<String>>(
context: context,
builder: (context) => Wrap(children: [this]),
);
}
@override
State<WRatingBottomSheet> createState() => _WRatingBottomSheetState();
}
class _WRatingBottomSheetState extends State<WRatingBottomSheet> {
List<String> rating = [];
void updateRating(String value) {
final list = List<String>.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<String> 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),
),
);
}
}