Initial commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import 'package:food_delivery_client/feature/home/presentation/mixins/categories_mixin.dart';
|
||||
|
||||
import '../../../../../food_delivery_client.dart';
|
||||
|
||||
class CategoriesPage extends StatelessWidget with CategoriesMixin {
|
||||
CategoriesPage({super.key});
|
||||
|
||||
show(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
|
||||
builder: (context) => Wrap(children: [this]),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<String> _titles = [
|
||||
context.loc.convenience,
|
||||
context.loc.alcohol,
|
||||
context.loc.petSupplies,
|
||||
context.loc.flowers,
|
||||
context.loc.grocery,
|
||||
context.loc.american,
|
||||
context.loc.speciality,
|
||||
context.loc.takeout,
|
||||
context.loc.asian,
|
||||
context.loc.iceCream,
|
||||
context.loc.halal,
|
||||
context.loc.retails,
|
||||
context.loc.caribbean,
|
||||
context.loc.indian,
|
||||
context.loc.french,
|
||||
context.loc.fastFoods,
|
||||
context.loc.burger,
|
||||
context.loc.ride,
|
||||
context.loc.chinese,
|
||||
context.loc.dessert,
|
||||
];
|
||||
return Material(
|
||||
color: AppColors.cFFFFFF,
|
||||
borderRadius: AppUtils.kBorderRadius20,
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
24.verticalSpace,
|
||||
Text(context.loc.allCategories, style: AppTextStyles.size20Regular),
|
||||
30.verticalSpace,
|
||||
GridView.builder(
|
||||
itemCount: images.length,
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
crossAxisSpacing: 5,
|
||||
mainAxisSpacing: 10,
|
||||
childAspectRatio: 78 / 100,
|
||||
),
|
||||
itemBuilder: (context, index) => WCategoryItem(
|
||||
onTap: () {},
|
||||
imgUrl: images[index],
|
||||
text: _titles[index],
|
||||
),
|
||||
),
|
||||
40.verticalSpace,
|
||||
],
|
||||
).paddingSymmetric(horizontal: 15),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
34
lib/feature/home/presentation/pages/home_page/home_page.dart
Normal file
34
lib/feature/home/presentation/pages/home_page/home_page.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import '../../../../../food_delivery_client.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => sl<HomeBloc>(),
|
||||
child: BlocBuilder<HomeBloc, HomeState>(
|
||||
builder: (context, state) {
|
||||
return WLayout(
|
||||
child: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(child: WHomeHeader()),
|
||||
SliverToBoxAdapter(child: Column(children: [
|
||||
WDeliveryHeader(),
|
||||
WDiscountPart(),
|
||||
WOffersCarouselSlider(),
|
||||
WDiscountPart(),
|
||||
WPopularNearYou(),
|
||||
WTodayOffers(),
|
||||
WPickItUpForFree()
|
||||
])),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WPickItUpForFree extends StatelessWidget {
|
||||
const WPickItUpForFree({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment:MainAxisAlignment.start,
|
||||
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
12.verticalSpace,
|
||||
Column(
|
||||
mainAxisAlignment:MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Pick it up for free', style: AppTextStyles.size24Bold),
|
||||
Text(
|
||||
"Skip the fees when you order pick-up",
|
||||
style: AppTextStyles.size14Regular.copyWith(
|
||||
color: AppColors.c545454,
|
||||
),
|
||||
),
|
||||
7.verticalSpace,
|
||||
],
|
||||
).paddingSymmetric(horizontal: 15),
|
||||
Container(
|
||||
height: 210,
|
||||
width: context.w,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(AppImages.imgPickUp),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: Align(
|
||||
alignment: AlignmentGeometry.topCenter,
|
||||
child: CarouselSlider.builder(
|
||||
options: CarouselOptions(
|
||||
height: 100.0,
|
||||
reverse: false,
|
||||
viewportFraction: 0.9,
|
||||
animateToClosest: true,
|
||||
autoPlay: true,
|
||||
autoPlayCurve: Curves.easeIn,
|
||||
initialPage: 0,
|
||||
padEnds: false,
|
||||
enableInfiniteScroll: true,
|
||||
scrollPhysics: const AlwaysScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
itemCount: 5,
|
||||
itemBuilder: (context, index, realIndex) {
|
||||
return Builder(
|
||||
builder: (BuildContext context) {
|
||||
return PickItUpItem().paddingOnly(left: 15);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
WFoodItem(),
|
||||
40.verticalSpace
|
||||
|
||||
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PickItUpItem extends StatelessWidget {
|
||||
const PickItUpItem({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: AppColors.cTransparent,
|
||||
child: InkWell(
|
||||
onTap: () {},
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cFFFFFF,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.c000000.newWithOpacity(.25),
|
||||
offset: const Offset(0, 1),
|
||||
blurRadius: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Image.network(
|
||||
AppLocaleKeys.imageUrl,
|
||||
height: 88,
|
||||
width: 96,
|
||||
fit: BoxFit.cover,
|
||||
).paddingAll(4),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Island Takeway", style: AppTextStyles.size17Bold),
|
||||
Text(
|
||||
"10-20 min",
|
||||
style: AppTextStyles.size14Medium.copyWith(
|
||||
color: AppColors.c6B6B6B,
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingOnly(top: 4, bottom: 4, right: 40),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter_bounceable/flutter_bounceable.dart';
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WCategoriesHeaderItem extends StatelessWidget {
|
||||
const WCategoriesHeaderItem({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.imageUrl,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final String imageUrl;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: AppUtils.kBorderRadius10,
|
||||
child: Ink(
|
||||
height: 88,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: AppUtils.kBorderRadius10,
|
||||
color: AppColors.cE6E6E6.newWithOpacity(.4),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Align(
|
||||
alignment: AlignmentGeometry.topRight,
|
||||
child: Image.asset(imageUrl).paddingOnly(top: 5, right: 5),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: AppTextStyles.size18Medium,
|
||||
).paddingOnly(left: 12, bottom: 6),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:food_delivery_client/feature/home/presentation/pages/categories_page/categories_page.dart';
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WDeliveryHeader extends StatelessWidget {
|
||||
const WDeliveryHeader({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<String> _titles = [
|
||||
context.loc.convenience,
|
||||
context.loc.alcohol,
|
||||
context.loc.petSupplies,
|
||||
context.loc.more,
|
||||
];
|
||||
return 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,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
List _images = [
|
||||
AppImages.imgConvenience,
|
||||
AppImages.imgAlcohol,
|
||||
AppImages.imgPetSupplies,
|
||||
];
|
||||
@@ -0,0 +1,25 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WDiscountPart extends StatelessWidget {
|
||||
const WDiscountPart({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
scrollDirection: Axis.vertical,
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => WFoodItem(enableTag: true),
|
||||
separatorBuilder: (context, index) => 20.verticalSpace,
|
||||
itemCount: 3,
|
||||
),
|
||||
WDivider(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WHomeHeader extends StatelessWidget {
|
||||
const WHomeHeader({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<HomeBloc, HomeState>(
|
||||
builder: (context, state) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(color: AppColors.cFFFFFF),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
15.verticalSpace,
|
||||
Stack(
|
||||
alignment: AlignmentGeometry.center,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SvgPicture.asset(AppIcons.icLocation, height: 20),
|
||||
8.horizontalSpace,
|
||||
Text("London Hall", style: AppTextStyles.size18Medium),
|
||||
5.horizontalSpace,
|
||||
SvgPicture.asset(AppIcons.icArrowBottom),
|
||||
],
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentGeometry.topRight,
|
||||
child: IconButton(
|
||||
onPressed: () {},
|
||||
icon: SvgPicture.asset(
|
||||
AppIcons.icFilter,
|
||||
height: 36,
|
||||
width: 36,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 15),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WOffersCarouselSlider extends StatelessWidget {
|
||||
WOffersCarouselSlider({super.key});
|
||||
|
||||
List _colors = [
|
||||
AppColors.cD2D7F0,
|
||||
AppColors.c9EE2B8,
|
||||
AppColors.cE2CC9E,
|
||||
AppColors.cC99EE2,
|
||||
AppColors.cE29EC7,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
16.verticalSpace,
|
||||
CarouselSlider.builder(
|
||||
options: CarouselOptions(
|
||||
height: 170.0,
|
||||
reverse: false,
|
||||
viewportFraction: 0.9,
|
||||
animateToClosest: true,
|
||||
autoPlay: true,
|
||||
autoPlayCurve: Curves.easeIn,
|
||||
initialPage: 0,
|
||||
padEnds: false,
|
||||
enableInfiniteScroll: true,
|
||||
scrollPhysics: const AlwaysScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
itemBuilder: (context, index, realIndex) => Builder(
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
margin: EdgeInsets.only(left: 15),
|
||||
decoration: BoxDecoration(
|
||||
color: _colors[index],
|
||||
borderRadius: AppUtils.kBorderRadius16,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Order from these restaurants and save",
|
||||
style: AppTextStyles.size17Bold,
|
||||
),
|
||||
const Spacer(),
|
||||
Material(
|
||||
color: AppColors.cTransparent,
|
||||
child: InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: AppUtils.kBorderRadius30,
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cFFFFFF,
|
||||
borderRadius: AppUtils.kBorderRadius30,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [Text('Browse offer')],
|
||||
).paddingSymmetric(horizontal: 8, vertical: 4),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingSymmetric(horizontal: 15, vertical: 15),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: AppUtils.kBorderRadiusTop15Bottom15,
|
||||
child: Image.network(
|
||||
AppLocaleKeys.imageUrl,
|
||||
height: 170,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
itemCount: _colors.length,
|
||||
),
|
||||
8.verticalSpace,
|
||||
WDivider(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WPopularNearYou extends StatelessWidget {
|
||||
const WPopularNearYou({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
10.verticalSpace,
|
||||
WSeeAllRaw(title: "Popular near you", onPressed: () {}),
|
||||
10.verticalSpace,
|
||||
CarouselSlider.builder(
|
||||
options: CarouselOptions(
|
||||
height: 180.0,
|
||||
reverse: false,
|
||||
viewportFraction: 0.9,
|
||||
animateToClosest: true,
|
||||
autoPlay: true,
|
||||
autoPlayCurve: Curves.easeIn,
|
||||
initialPage: 0,
|
||||
padEnds: false,
|
||||
enableInfiniteScroll: true,
|
||||
scrollPhysics: const AlwaysScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
itemCount: 5,
|
||||
itemBuilder: (context, index, realIndex) {
|
||||
return Builder(
|
||||
builder: (BuildContext context) {
|
||||
return WFoodItem(
|
||||
imageHeight: 130,
|
||||
textStyle1: AppTextStyles.size14Medium,
|
||||
textStyle2: AppTextStyles.size12Regular,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
13.verticalSpace,
|
||||
WDivider(),
|
||||
10.verticalSpace,
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemBuilder: (context, index) => WFoodItem(),
|
||||
separatorBuilder: (context, index) => 25.verticalSpace,
|
||||
itemCount: 5,
|
||||
),
|
||||
25.verticalSpace,
|
||||
WDivider(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WTodayOffers extends StatelessWidget {
|
||||
const WTodayOffers({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
12.verticalSpace,
|
||||
WSeeAllRaw(
|
||||
title: "Today's offers",
|
||||
onPressed: () {},
|
||||
),
|
||||
10.verticalSpace,
|
||||
CarouselSlider.builder(
|
||||
options: CarouselOptions(
|
||||
height: 180.0,
|
||||
reverse: false,
|
||||
viewportFraction: 0.9,
|
||||
animateToClosest: true,
|
||||
autoPlay: true,
|
||||
autoPlayCurve: Curves.easeIn,
|
||||
initialPage: 0,
|
||||
padEnds: false,
|
||||
enableInfiniteScroll: true,
|
||||
scrollPhysics: const AlwaysScrollableScrollPhysics(),
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
itemCount: 5,
|
||||
itemBuilder: (context, index, realIndex) {
|
||||
return Builder(
|
||||
builder: (BuildContext context) {
|
||||
return WFoodItem(
|
||||
imageHeight: 130,
|
||||
enableTag: true,
|
||||
textStyle1: AppTextStyles.size14Medium,
|
||||
textStyle2: AppTextStyles.size12Regular,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
10.verticalSpace,
|
||||
WDivider(),
|
||||
10.verticalSpace,
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
|
||||
scrollDirection: Axis.vertical,
|
||||
itemBuilder: (context, index) => WFoodItem(),
|
||||
separatorBuilder: (context, index) => 25.verticalSpace,
|
||||
itemCount: 3,
|
||||
),
|
||||
25.verticalSpace,
|
||||
WDivider()
|
||||
|
||||
|
||||
|
||||
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user