feat:restaurants by category page done

This commit is contained in:
jahongireshonqulov
2025-10-24 19:44:52 +05:00
parent e0f3d900d7
commit ffbc153b55
20 changed files with 409 additions and 30 deletions

View File

@@ -0,0 +1,5 @@
<svg width="23" height="21" viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.5174 3.10349C18.1037 3.10349 19.6554 5.06903 19.6554 7.44837C19.6554 8.68976 19.0347 9.82771 18.3106 10.6553C17.0692 11.8967 11.3795 16.5519 11.3795 16.5519C11.3795 16.5519 5.68973 11.8967 4.44833 10.6553C3.62073 9.82771 3.10349 8.68976 3.10349 7.44837C3.10349 5.06903 4.65523 3.10349 7.24147 3.10349C9.00011 3.10349 10.6553 4.75868 11.3795 6.20697C12.1036 4.75868 13.7588 3.10349 15.5174 3.10349ZM15.5174 0C13.9657 0 12.5174 0.620697 11.3795 1.44829C10.2415 0.517248 8.79321 0 7.24147 0C3.10349 0 0 3.20694 0 7.44837C0 9.41391 0.827596 11.276 2.27589 12.8277C3.72418 14.3795 11.3795 20.5865 11.3795 20.5865C11.3795 20.5865 19.0347 14.3795 20.483 12.8277C21.9313 11.276 22.7589 9.41391 22.7589 7.44837C22.7589 3.20694 19.6554 0 15.5174 0Z"
fill="#8A8A8A" />
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@@ -82,9 +82,34 @@
"popular": "Most popular", "popular": "Most popular",
"topRated": "Top rated", "topRated": "Top rated",
"fast": "Fast", "fast": "Fast",
"delivery": "Delivery" "delivery": "Delivery",
"featuredStores": "Featured stores",
"fromUberEats": "From {name}",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Opens at {time}",
"@opensAt": {
"placeholders":{
"time": {
"type": "String"
}
}
},
"spendAndSave": "Spend {spend}, save {save}",
"@spendAndSave": {
"placeholders":{
"spend": {
"type": "String"
},
"save": {
"type": "String"
}
}
}
} }

View File

@@ -89,7 +89,26 @@
"popular": "Самые популярные", "popular": "Самые популярные",
"topRated": "Высокий рейтинг", "topRated": "Высокий рейтинг",
"fast": "Быстро", "fast": "Быстро",
"delivery": "Доставка" "delivery": "Доставка",
"featuredStores": "Популярные магазины",
"fromUberEats": "От {name}",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Открывается в {time}",
"opensAt@placeholders": {
"time": {}
},
"spendAndSave": "Потратьте {spend}, сэкономьте {save}",
"spendAndSave@placeholders": {
"spend": {},
"save": {}
}

View File

@@ -59,13 +59,13 @@
"dessert": "Desert", "dessert": "Desert",
"more":"Ko'proq", "more":"Ko'proq",
"orderDetails": "Buyurtma tafsilotlari", "orderDetails": "Buyurtma tafsilotlari",
"deliverNow": "Hozir yetkazish", "deliverNow": "Hozir yetkazish",
"schedule": "Rejalashtirish", "schedule": "Rejalashtirish",
"enterNewAddress": "Yangi manzil kiriting", "enterNewAddress": "Yangi manzil kiriting",
"nearby": "Yaqin joylar", "nearby": "Yaqin joylar",
"currentLocation": "Joriy joylashuv", "currentLocation": "Joriy joylashuv",
"enable": "Yoqqish", "enable": "Yoqqish",
"recentLocations": "Yaqinda ishlatilgan manzillar", "recentLocations": "Yaqinda ishlatilgan manzillar",
"allFilters": "Barcha filtrlar", "allFilters": "Barcha filtrlar",
"sort": "Saralash", "sort": "Saralash",
"pickedForYou": "Siz uchun", "pickedForYou": "Siz uchun",
@@ -89,7 +89,29 @@
"popular": "Eng ommabop", "popular": "Eng ommabop",
"topRated": "Yuqori reytingli", "topRated": "Yuqori reytingli",
"fast": "Tezkor", "fast": "Tezkor",
"delivery": "Yetkazish" "delivery": "Yetkazish",
"featuredStores": "Mashhur dokonlar",
"fromUberEats": "{name} tomonidan",
"@fromUberEats":{
"placeholders": {
"name": {
"type": "String"
}
}
},
"opensAt": "Soat {time} dan ochiladi",
"opensAt@placeholders": {
"time": {}
},
"spendAndSave": "{spend} sarflang, {save} tejang",
"spendAndSave@placeholders": {
"spend": {},
"save": {}
}

View File

@@ -415,8 +415,8 @@ abstract class AppLocalizations {
/// No description provided for @fromUberEats. /// No description provided for @fromUberEats.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'From Uber Eats'** /// **'From {name}'**
String get fromUberEats; String fromUberEats(String name);
/// No description provided for @deals. /// No description provided for @deals.
/// ///
@@ -507,6 +507,24 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Fast'** /// **'Fast'**
String get fast; String get fast;
/// No description provided for @featuredStores.
///
/// In en, this message translates to:
/// **'Featured stores'**
String get featuredStores;
/// No description provided for @opensAt.
///
/// In en, this message translates to:
/// **'Opens at {time}'**
String opensAt(String time);
/// No description provided for @spendAndSave.
///
/// In en, this message translates to:
/// **'Spend {spend}, save {save}'**
String spendAndSave(String spend, String save);
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate

View File

@@ -170,7 +170,9 @@ class AppLocalizationsEn extends AppLocalizations {
String get deliveryTime => 'Delivery time'; String get deliveryTime => 'Delivery time';
@override @override
String get fromUberEats => 'From Uber Eats'; String fromUberEats(String name) {
return 'From $name';
}
@override @override
String get deals => 'Deals'; String get deals => 'Deals';
@@ -216,4 +218,17 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get fast => 'Fast'; String get fast => 'Fast';
@override
String get featuredStores => 'Featured stores';
@override
String opensAt(String time) {
return 'Opens at $time';
}
@override
String spendAndSave(String spend, String save) {
return 'Spend $spend, save $save';
}
} }

View File

@@ -171,7 +171,9 @@ class AppLocalizationsRu extends AppLocalizations {
String get deliveryTime => 'Время доставки'; String get deliveryTime => 'Время доставки';
@override @override
String get fromUberEats => 'От Uber Eats'; String fromUberEats(String name) {
return 'От $name';
}
@override @override
String get deals => 'Скидки'; String get deals => 'Скидки';
@@ -217,4 +219,17 @@ class AppLocalizationsRu extends AppLocalizations {
@override @override
String get fast => 'Быстро'; String get fast => 'Быстро';
@override
String get featuredStores => 'Популярные магазины';
@override
String opensAt(String time) {
return 'Открывается в $time';
}
@override
String spendAndSave(String spend, String save) {
return 'Потратьте $spend, сэкономьте $save';
}
} }

View File

@@ -171,7 +171,9 @@ class AppLocalizationsUz extends AppLocalizations {
String get deliveryTime => 'Yetkazib berish vaqti'; String get deliveryTime => 'Yetkazib berish vaqti';
@override @override
String get fromUberEats => 'Uber Eats dan'; String fromUberEats(String name) {
return '$name tomonidan';
}
@override @override
String get deals => 'Aksiyalar'; String get deals => 'Aksiyalar';
@@ -217,4 +219,17 @@ class AppLocalizationsUz extends AppLocalizations {
@override @override
String get fast => 'Tezkor'; String get fast => 'Tezkor';
@override
String get featuredStores => 'Mashhur dokonlar';
@override
String opensAt(String time) {
return 'Soat $time dan ochiladi';
}
@override
String spendAndSave(String spend, String save) {
return '$spend sarflang, $save tejang';
}
} }

View File

@@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/restaurants_by_category_page.dart';
import '../../food_delivery_client.dart'; import '../../food_delivery_client.dart';
@@ -22,9 +23,15 @@ class AppRoutes {
), ),
GoRoute( GoRoute(
path: Routes.filters, path: Routes.filters,
pageBuilder: (context, state) => CupertinoPage(child: FiltersPage( pageBuilder: (context, state) => CupertinoPage(
homeBloc: state.extra as HomeBloc, child: FiltersPage(homeBloc: state.extra as HomeBloc),
)), ),
),
GoRoute(
path: Routes.restaurantsByCategory,
pageBuilder: (context, state) => CupertinoPage(
child: RestaurantsByCategoryPage(categoryName: state.extra as String),
),
), ),
], ],
); );

View File

@@ -4,7 +4,6 @@ abstract class Routes {
static const String register = '/register'; static const String register = '/register';
static const String main = '/main'; static const String main = '/main';
static const String categories = '/categories'; static const String categories = '/categories';
static const String filters= '/filters'; static const String filters = '/filters';
static const String restaurantsByCategory = '/restaurants-by-category';
} }

View File

@@ -5,7 +5,6 @@ abstract class AppColors {
static const Color cRed = Colors.red; static const Color cRed = Colors.red;
static const Color cYellow = Colors.yellow; static const Color cYellow = Colors.yellow;
static const Color cFFFFFF = Color(0xFFFFFFFF); static const Color cFFFFFF = Color(0xFFFFFFFF);
static const Color c000000 = Color(0xFF000000); static const Color c000000 = Color(0xFF000000);
static const Color cB5B5B5 = Color(0xFFB5B5B5); static const Color cB5B5B5 = Color(0xFFB5B5B5);
@@ -21,5 +20,6 @@ abstract class AppColors {
static const Color cC99EE2 = Color(0xFFC99EE2); static const Color cC99EE2 = Color(0xFFC99EE2);
static const Color cE29EC7 = Color(0xFFE29EC7); static const Color cE29EC7 = Color(0xFFE29EC7);
static const Color c545454 = Color(0xFF545454); static const Color c545454 = Color(0xFF545454);
static const Color cEFF3FE = Color(0xFFEFF3FE);
static const Color c05A357 = Color(0xFF05A357);
} }

View File

@@ -13,6 +13,7 @@ abstract class AppIcons {
static const String icAccountActive = "$baseUrl/ic_account_active.svg"; static const String icAccountActive = "$baseUrl/ic_account_active.svg";
static const String icBack = "$baseUrl/ic_back.svg"; static const String icBack = "$baseUrl/ic_back.svg";
static const String icDislike = "$baseUrl/ic_dislike.svg"; static const String icDislike = "$baseUrl/ic_dislike.svg";
static const String icDislikeGrey = "$baseUrl/ic_dislike_grey.svg";
static const String icEat = "$baseUrl/ic_eat.svg"; static const String icEat = "$baseUrl/ic_eat.svg";
static const String icEye = "$baseUrl/ic_eye.svg"; static const String icEye = "$baseUrl/ic_eye.svg";
static const String icFilter = "$baseUrl/ic_filter.svg"; static const String icFilter = "$baseUrl/ic_filter.svg";

View File

@@ -97,6 +97,20 @@ abstract class AppTextStyles {
fontFamily: _fontBold, fontFamily: _fontBold,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
); );
static const TextStyle size30Bold = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_30,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
static const TextStyle size36Bold = TextStyle(
color: _defaultColor,
fontSize: SizesCons.size_36,
fontFamily: _fontBold,
fontWeight: FontWeight.w700,
);
} }
/* /*

View File

@@ -19,4 +19,7 @@ export 'package:food_delivery_client/feature/home/presentation/pages/filters_pag
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_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_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_deals.dart';
export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart'; export 'package:food_delivery_client/feature/home/presentation/pages/filters_page/widgets/w_filters_sort.dart';
export 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/widgets/w_restaurants_by_category_body.dart';
export 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/widgets/w_featured_stores.dart';
export 'package:food_delivery_client/feature/home/presentation/pages/restaurants_by_category_page/widgets/w_stores_list.dart';

View File

@@ -59,7 +59,12 @@ class CategoriesPage extends StatelessWidget with CategoriesMixin {
childAspectRatio: 78 / 100, childAspectRatio: 78 / 100,
), ),
itemBuilder: (context, index) => WCategoryItem( itemBuilder: (context, index) => WCategoryItem(
onTap: () {}, onTap: () {
context.push(
Routes.restaurantsByCategory,
extra: _titles[index],
);
},
imgUrl: images[index], imgUrl: images[index],
text: _titles[index], text: _titles[index],
), ),

View File

@@ -40,12 +40,22 @@ class WDeliveryHeader extends StatelessWidget {
spacing: 12, spacing: 12,
children: [ children: [
WCategoriesHeaderItem( WCategoriesHeaderItem(
onTap: () {}, onTap: () {
context.push(
Routes.restaurantsByCategory,
extra: context.loc.american,
);
},
text: context.loc.american, text: context.loc.american,
imageUrl: AppImages.imgAmerican, imageUrl: AppImages.imgAmerican,
), ),
WCategoriesHeaderItem( WCategoriesHeaderItem(
onTap: () {}, onTap: () {
context.push(
Routes.restaurantsByCategory,
extra: context.loc.grocery,
);
},
text: context.loc.grocery, text: context.loc.grocery,
imageUrl: AppImages.imgGrocery, imageUrl: AppImages.imgGrocery,
), ),
@@ -71,6 +81,11 @@ class WDeliveryHeader extends StatelessWidget {
onTap: () { onTap: () {
if (index == 3) { if (index == 3) {
CategoriesPage().show(context); CategoriesPage().show(context);
} else {
context.push(
Routes.restaurantsByCategory,
extra: _titles[index],
);
} }
}, },
imgUrl: index != 3 ? _images[index] : null, imgUrl: index != 3 ? _images[index] : null,

View File

@@ -0,0 +1,24 @@
import '../../../../../food_delivery_client.dart';
class RestaurantsByCategoryPage extends StatelessWidget {
const RestaurantsByCategoryPage({super.key, required this.categoryName});
final String categoryName;
@override
Widget build(BuildContext context) {
return WLayout(
child: Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {
context.pop();
},
icon: SvgPicture.asset(AppIcons.icBack),
),
),
body: WRestaurantsByCategoryBody(categoryName: categoryName),
),
);
}
}

View File

@@ -0,0 +1,66 @@
import '../../../../../../food_delivery_client.dart';
class WFeaturedStores extends StatelessWidget {
const WFeaturedStores({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
child: ListView.separated(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 20),
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) => WFeaturedStoresItem(),
separatorBuilder: (context, index) => 7.horizontalSpace,
itemCount: 10,
),
);
}
}
class WFeaturedStoresItem extends StatelessWidget {
const WFeaturedStoresItem({super.key});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
borderRadius: AppUtils.kBorderRadius16,
child: Ink(
height: 200,
width: 165,
decoration: BoxDecoration(
color: AppColors.cEFF3FE,
borderRadius: AppUtils.kBorderRadius16,
),
child: Column(
spacing: 20,
children: [
Expanded(
child: CachedNetworkImage(imageUrl: AppLocaleKeys.imageUrl),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("7Eleven", style: AppTextStyles.size16Medium),
Text(
context.loc.opensAt("10:00 AM"),
textAlign: TextAlign.center,
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
],
),
),
],
).paddingAll(20),
),
);
}
}

View File

@@ -0,0 +1,42 @@
import '../../../../../../food_delivery_client.dart';
class WRestaurantsByCategoryBody extends StatelessWidget {
const WRestaurantsByCategoryBody({super.key, required this.categoryName});
final String categoryName;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
categoryName,
style: AppTextStyles.size36Bold.copyWith(
height: 44/36
),
).paddingSymmetric(horizontal: 15),
15.verticalSpace,
Text(
context.loc.featuredStores,
style: AppTextStyles.size30Bold.copyWith(
height: 44/30
),
).paddingSymmetric(horizontal: 15),
15.verticalSpace,
WFeaturedStores(),
16.verticalSpace,
WDivider(),
WStoresList()
],
),
);
}
}

View File

@@ -0,0 +1,69 @@
import '../../../../../../food_delivery_client.dart';
class WStoresList extends StatelessWidget {
const WStoresList({super.key});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 20,
shrinkWrap: true,
padding: EdgeInsets.symmetric(vertical: 17),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return WStoreItem();
},
);
}
}
class WStoreItem extends StatelessWidget {
const WStoreItem({super.key});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Ink(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadius36,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.imageUrl,
height: 70,
width: 70,
fit: BoxFit.cover,
),
),
16.horizontalSpace,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Begs & Megs", style: AppTextStyles.size16Medium),
Text(
context.loc.opensAt("10:00"),
style: AppTextStyles.size14Regular.copyWith(
color: AppColors.c6B6B6B,
),
),
Text(
context.loc.spendAndSave("\$20", "\$5"),
style: AppTextStyles.size14Medium.copyWith(
color: AppColors.c05A357,
),
),
],
),
const Spacer(),
IconButton(
onPressed: () {},
icon: SvgPicture.asset(AppIcons.icDislikeGrey),
),
],
).paddingSymmetric(vertical: 10, horizontal: 18),
),
);
}
}