Files
Fondex/lib/screen_ui/ecommarce/home_e_commerce_screen.dart

1976 lines
106 KiB
Dart

import 'package:badges/badges.dart' as badges;
import 'package:customer/constant/constant.dart';
import 'package:customer/controllers/home_e_commerce_controller.dart';
import 'package:customer/controllers/theme_controller.dart';
import 'package:customer/models/advertisement_model.dart';
import 'package:customer/models/banner_model.dart';
import 'package:customer/models/brands_model.dart';
import 'package:customer/models/favourite_model.dart';
import 'package:customer/models/product_model.dart';
import 'package:customer/models/user_model.dart';
import 'package:customer/models/vendor_category_model.dart';
import 'package:customer/models/vendor_model.dart';
import 'package:customer/screen_ui/auth_screens/login_screen.dart';
import 'package:customer/screen_ui/ecommarce/all_brand_product_screen.dart';
import 'package:customer/screen_ui/ecommarce/all_category_product_screen.dart';
import 'package:customer/screen_ui/location_enable_screens/address_list_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/advertisement_screens/all_advertisement_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/cart_screen/cart_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/home_screen/category_restaurant_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/home_screen/restaurant_list_screen.dart'
show RestaurantListScreen;
import 'package:customer/screen_ui/multi_vendor_service/home_screen/view_all_category_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/restaurant_details_screen/restaurant_details_screen.dart';
import 'package:customer/screen_ui/multi_vendor_service/search_screen/search_screen.dart';
import 'package:customer/service/fire_store_utils.dart';
import 'package:customer/themes/app_them_data.dart';
import 'package:customer/themes/responsive.dart';
import 'package:customer/themes/round_button_border.dart';
import 'package:customer/themes/show_toast_dialog.dart';
import 'package:customer/themes/text_field_widget.dart';
import 'package:customer/utils/network_image_widget.dart';
import 'package:customer/widget/osm_map/map_picker_page.dart';
import 'package:customer/widget/place_picker/location_picker_screen.dart';
import 'package:customer/widget/place_picker/selected_location_model.dart';
import 'package:customer/widget/video_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:url_launcher/url_launcher.dart';
class HomeECommerceScreen extends StatelessWidget {
const HomeECommerceScreen({super.key});
@override
Widget build(BuildContext context) {
final themeController = Get.find<ThemeController>();
final isDark = themeController.isDark.value;
return GetX(
init: HomeECommerceController(),
builder: (controller) {
return Scaffold(
backgroundColor: isDark ? AppThemeData.grey900 : AppThemeData.grey50,
appBar: AppBar(
backgroundColor:
isDark ? AppThemeData.ecommerce300 : AppThemeData.ecommerce300,
titleSpacing: 0,
leading: InkWell(
onTap: () {
Get.back();
},
child: Icon(
Icons.arrow_back,
color: isDark ? AppThemeData.grey50 : AppThemeData.grey50,
size: 20,
),
),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Constant.userModel == null
? InkWell(
onTap: () {
Get.offAll(const LoginScreen());
},
child: Text(
"Login".tr,
textAlign: TextAlign.center,
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey50,
fontSize: 12,
),
),
)
: Text(
Constant.userModel!.fullName(),
textAlign: TextAlign.center,
style: AppThemeData.semiBoldTextStyle(
color:
isDark ? AppThemeData.grey50 : AppThemeData.grey50,
fontSize: 12,
),
),
InkWell(
onTap: () async {
if (Constant.userModel != null) {
Get.to(AddressListScreen())!.then((value) {
if (value != null) {
ShippingAddress shippingAddress = value;
Constant.selectedLocation = shippingAddress;
controller.getData();
}
});
} else {
Constant.checkPermission(
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr);
// ✅ declare it once here!
ShippingAddress shippingAddress = ShippingAddress();
try {
await Geolocator.requestPermission();
await Geolocator.getCurrentPosition();
ShowToastDialog.closeLoader();
if (Constant.selectedMapType == 'osm') {
final result = await Get.to(
() => MapPickerPage(),
);
if (result != null) {
final firstPlace = result;
final lat = firstPlace.coordinates.latitude;
final lng = firstPlace.coordinates.longitude;
final address = firstPlace.address;
shippingAddress.addressAs = "Home";
shippingAddress.locality = address.toString();
shippingAddress.location = UserLocation(
latitude: lat,
longitude: lng,
);
Constant.selectedLocation = shippingAddress;
controller.getData();
Get.back();
}
} else {
Get.to(LocationPickerScreen())!.then((
value,
) async {
if (value != null) {
SelectedLocationModel selectedLocationModel =
value;
shippingAddress.addressAs = "Home";
shippingAddress.location = UserLocation(
latitude:
selectedLocationModel.latLng!.latitude,
longitude:
selectedLocationModel.latLng!.longitude,
);
shippingAddress.locality =
"Picked from Map"; // You can reverse-geocode
Constant.selectedLocation = shippingAddress;
controller.getData();
}
});
}
} catch (e) {
await placemarkFromCoordinates(
19.228825,
72.854118,
).then((valuePlaceMaker) {
Placemark placeMark = valuePlaceMaker[0];
shippingAddress.location = UserLocation(
latitude: 19.228825,
longitude: 72.854118,
);
String currentLocation =
"${placeMark.name}, ${placeMark.subLocality}, ${placeMark.locality}, ${placeMark.administrativeArea}, ${placeMark.postalCode}, ${placeMark.country}";
shippingAddress.locality = currentLocation;
});
Constant.selectedLocation = shippingAddress;
ShowToastDialog.closeLoader();
controller.getData();
}
},
context: context,
);
}
},
child: Text.rich(
maxLines: 1,
overflow: TextOverflow.ellipsis,
TextSpan(
children: [
TextSpan(
text: Constant.selectedLocation.getFullAddress(),
style: AppThemeData.boldTextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey50,
fontSize: 14,
),
),
WidgetSpan(
child: SvgPicture.asset(
"assets/icons/ic_down.svg",
colorFilter: ColorFilter.mode(
AppThemeData.grey50,
BlendMode.srcIn,
),
),
),
],
),
),
),
],
),
actions: [
Obx(
() => Padding(
padding: const EdgeInsets.only(right: 15.0, left: 10),
child: badges.Badge(
showBadge: true,
badgeContent: Text(
"${cartItem.length}",
style: TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
fontFamily: AppThemeData.semiBold,
fontWeight: FontWeight.w600,
color:
isDark ? AppThemeData.grey50 : AppThemeData.grey50,
),
),
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.circle,
badgeColor: AppThemeData.info300,
),
child: InkWell(
onTap: () async {
(await Get.to(const CartScreen()));
controller.getCartData();
},
child: ClipOval(
child: Container(
width: 30,
height: 30,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color:
isDark
? AppThemeData.grey700
: AppThemeData.grey200,
),
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset(
"assets/icons/ic_shoping_cart.svg",
colorFilter: ColorFilter.mode(
isDark
? AppThemeData.grey50
: AppThemeData.grey50,
BlendMode.srcIn,
),
),
),
),
),
),
),
),
),
],
bottom: PreferredSize(
preferredSize: Size.fromHeight(
50.0,
), // height of the bottom widget
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: InkWell(
onTap: () {
Get.to(
const SearchScreen(),
arguments: {
"vendorList": controller.allNearestRestaurant,
},
);
},
child: TextFieldWidget(
hintText: 'Search the store, item and more...'.tr,
controller: null,
enable: false,
backgroundColor: AppThemeData.grey50,
hintColor:
isDark ? AppThemeData.grey400 : AppThemeData.grey400,
prefix: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SvgPicture.asset(
"assets/icons/ic_search.svg",
colorFilter: ColorFilter.mode(
isDark ? AppThemeData.grey400 : AppThemeData.grey400,
BlendMode.srcIn,
),
),
),
),
),
),
),
),
body:
controller.isLoading.value
? Constant.loader()
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: Text(
"Category".tr,
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
fontSize: 16,
),
),
),
InkWell(
onTap: () {
Get.to(const ViewAllCategoryScreen());
},
child: Text(
"View all".tr,
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(
decoration: TextDecoration.underline,
color:
isDark
? AppThemeData.multiVendorDark300
: AppThemeData.multiVendor300,
fontSize: 14,
),
),
),
],
),
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SizedBox(
height: 100,
child: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount:
controller.vendorCategoryModel.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
VendorCategoryModel vendorCategoryModel =
controller.vendorCategoryModel[index];
return InkWell(
onTap: () {
Get.to(
const CategoryRestaurantScreen(),
arguments: {
"vendorCategoryModel":
vendorCategoryModel,
"dineIn": false,
},
);
},
child: Padding(
padding: const EdgeInsets.only(right: 18),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
NetworkImageWidget(
imageUrl:
vendorCategoryModel.photo
.toString(),
height: 60,
width: 60,
fit: BoxFit.cover,
),
const SizedBox(height: 5),
Text(
vendorCategoryModel.title
.toString(),
textAlign: TextAlign.center,
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.greyDark800
: AppThemeData.grey800,
fontSize: 14,
),
),
],
),
),
);
},
),
),
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child:
controller.bannerModel.isEmpty
? const SizedBox()
: BannerView(controller: controller),
),
Visibility(
visible:
(Constant.isEnableAdsFeature == true &&
controller.advertisementList.isNotEmpty),
child: const SizedBox(height: 20),
),
Visibility(
visible: Constant.isEnableAdsFeature == true,
child:
controller.advertisementList.isEmpty
? const SizedBox()
: Container(
color: AppThemeData.primary300.withAlpha(
40,
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"Highlights for you".tr,
textAlign: TextAlign.start,
style: TextStyle(
fontFamily:
AppThemeData.semiBold,
fontSize: 16,
color:
isDark
? AppThemeData
.grey50
: AppThemeData
.grey900,
),
),
),
InkWell(
onTap: () {
Get.to(
AllAdvertisementScreen(),
)?.then((value) {
controller
.getFavouriteRestaurant();
});
},
child: Text(
"View all".tr,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily:
AppThemeData.regular,
color:
isDark
? AppThemeData
.primary300
: AppThemeData
.primary300,
),
),
),
],
),
const SizedBox(height: 16),
SizedBox(
height: 220,
child: ListView.builder(
physics:
const BouncingScrollPhysics(),
scrollDirection:
Axis.horizontal,
itemCount:
controller
.advertisementList
.length >=
10
? 10
: controller
.advertisementList
.length,
padding: EdgeInsets.all(0),
itemBuilder: (
BuildContext context,
int index,
) {
return AdvertisementHomeCard(
controller: controller,
model:
controller
.advertisementList[index],
);
},
),
),
],
),
),
),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
"New Arrivals".tr,
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
fontSize: 16,
),
),
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SizedBox(
height: 380,
child: GridView.count(
crossAxisCount: 2,
// 2 columns
mainAxisSpacing: 0,
crossAxisSpacing: 20,
childAspectRatio: 1 / 1.1,
padding: EdgeInsets.zero,
physics: NeverScrollableScrollPhysics(),
children:
controller.newArrivalRestaurantList
.take(4)
.map(
(item) => NewArrivalCard(item: item),
)
.toList(),
),
),
),
SizedBox(height: 5),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: RoundedButtonBorder(
radius: 10,
color:
isDark
? AppThemeData.greyDark100
: AppThemeData.grey100,
borderColor:
isDark
? AppThemeData.greyDark200
: AppThemeData.grey200,
title: 'View All Arrivals'.tr,
onPress: () {
Get.to(
RestaurantListScreen(),
arguments: {
"vendorList":
controller.newArrivalRestaurantList,
"title": "New Arrivals".tr,
},
);
},
),
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Top Brands".tr,
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
fontSize: 16,
),
),
SizedBox(height: 10),
GridView.builder(
padding: EdgeInsets.zero,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 4.5 / 6,
crossAxisSpacing: 2,
),
itemCount: controller.brandList.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
BrandsModel brandModel =
controller.brandList[index];
return InkWell(
onTap: () {
Get.to(
AllBrandProductScreen(),
arguments: {"brandModel": brandModel},
);
},
child: Column(
children: [
Container(
width: 80,
height: 80,
decoration: ShapeDecoration(
color:
isDark
? AppThemeData.grey900
: AppThemeData.grey50,
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
strokeAlign:
BorderSide
.strokeAlignOutside,
color:
isDark
? AppThemeData.grey800
: AppThemeData
.grey100,
),
borderRadius:
BorderRadius.circular(10),
),
),
child: Padding(
padding: const EdgeInsets.all(10),
child: ClipOval(
child: NetworkImageWidget(
imageUrl:
brandModel.photo
.toString(),
fit: BoxFit.cover,
),
),
),
),
SizedBox(height: 5),
Text(
'${brandModel.title}',
textAlign: TextAlign.center,
maxLines: 2,
style: AppThemeData.mediumTextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey900,
),
),
],
),
);
},
),
],
),
),
SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.zero,
itemCount:
controller.categoryWiseProductList.length,
itemBuilder: (context, index) {
VendorCategoryModel item =
controller.categoryWiseProductList[index];
String imagePath =
[
"assets/images/ic_product_bg_1.png",
"assets/images/ic_product_bg_2.png",
"assets/images/ic_product_bg_3.png",
][index % ["", "", ""].length];
return Container(
width: Responsive.width(100, context),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(imagePath),
fit: BoxFit.fill,
),
),
child: Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
top: 10,
bottom: 20,
),
child: FutureBuilder<List<ProductModel>>(
future:
FireStoreUtils.getProductListByCategoryId(
item.id.toString(),
),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child:
CircularProgressIndicator.adaptive(
valueColor:
AlwaysStoppedAnimation(
AppThemeData.primary300,
),
),
);
} else if ((snapshot.hasData ||
(snapshot.data?.isNotEmpty ??
false))) {
List<ProductModel> productList =
snapshot.data!;
return snapshot.data!.isEmpty
? Container()
: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [
Text(
item.title.toString(),
textAlign: TextAlign.start,
style:
AppThemeData.boldTextStyle(
color:
AppThemeData
.grey900,
fontSize: 18,
),
),
Text(
"Style up with the latest fits, now at unbeatable prices."
.tr,
textAlign: TextAlign.start,
style:
AppThemeData.regularTextStyle(
color:
AppThemeData
.grey900,
fontSize: 12,
),
),
SizedBox(height: 20),
GridView.builder(
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio:
3.5 / 6,
crossAxisSpacing: 10,
),
padding: EdgeInsets.zero,
physics:
NeverScrollableScrollPhysics(),
itemCount:
productList.length > 6
? 6
: productList.length,
itemBuilder: (
context,
index,
) {
ProductModel productModel =
productList[index];
return FutureBuilder(
future:
FireStoreUtils.getVendorById(
productModel
.vendorID
.toString(),
),
builder: (
context,
vendorSnapshot,
) {
if (!vendorSnapshot
.hasData ||
vendorSnapshot
.connectionState ==
ConnectionState
.waiting) {
return const SizedBox(); // Show placeholder or loader
}
VendorModel?
vendorModel =
vendorSnapshot.data;
String price = "0.0";
String disPrice = "0.0";
List<String>
selectedVariants = [];
List<String>
selectedIndexVariants =
[];
List<String>
selectedIndexArray = [];
if (productModel
.itemAttribute !=
null) {
if (productModel
.itemAttribute!
.attributes!
.isNotEmpty) {
for (var element
in productModel
.itemAttribute!
.attributes!) {
if (element
.attributeOptions!
.isNotEmpty) {
selectedVariants.add(
productModel
.itemAttribute!
.attributes![productModel
.itemAttribute!
.attributes!
.indexOf(
element,
)]
.attributeOptions![0]
.toString(),
);
selectedIndexVariants
.add(
'${productModel.itemAttribute!.attributes!.indexOf(element)} _${productModel.itemAttribute!.attributes![0].attributeOptions![0].toString()}',
);
selectedIndexArray
.add(
'${productModel.itemAttribute!.attributes!.indexOf(element)}_0',
);
}
}
}
if (productModel
.itemAttribute!
.variants!
.where(
(element) =>
element
.variantSku ==
selectedVariants
.join(
'-',
),
)
.isNotEmpty) {
price = Constant.productCommissionPrice(
vendorModel!,
productModel
.itemAttribute!
.variants!
.where(
(
element,
) =>
element.variantSku ==
selectedVariants.join(
'-',
),
)
.first
.variantPrice ??
'0',
);
disPrice = "0";
}
} else {
price =
Constant.productCommissionPrice(
vendorModel!,
productModel
.price
.toString(),
);
disPrice =
double.parse(
productModel
.disPrice
.toString(),
) <=
0
? "0"
: Constant.productCommissionPrice(
vendorModel,
productModel
.disPrice
.toString(),
);
}
return GestureDetector(
onTap: () async {
Get.to(
const RestaurantDetailsScreen(),
arguments: {
"vendorModel":
vendorModel,
},
);
},
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
ClipRRect(
borderRadius:
BorderRadius.circular(
10,
),
child: SizedBox(
height: 90,
width:
Responsive.width(
100,
context,
),
child: NetworkImageWidget(
imageUrl:
productModel
.photo
.toString(),
fit:
BoxFit
.cover,
),
),
),
Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
productModel
.name!
.capitalizeString(),
textAlign:
TextAlign
.start,
maxLines: 1,
style: AppThemeData.semiBoldTextStyle(
fontSize:
18,
color:
isDark
? AppThemeData.greyDark600
: AppThemeData.grey600,
),
),
disPrice ==
"" ||
disPrice ==
"0"
? Text(
Constant.amountShow(
amount:
price,
),
style: AppThemeData.semiBoldTextStyle(
fontSize:
16,
color:
AppThemeData.primary300,
),
)
: Column(
children: [
Text(
Constant.amountShow(
amount:
price,
),
style: AppThemeData.semiBoldTextStyle(
fontSize:
14,
color:
Colors.grey,
decoration:
TextDecoration.lineThrough,
),
),
const SizedBox(
width:
5,
),
Text(
Constant.amountShow(
amount:
disPrice,
),
style: AppThemeData.semiBoldTextStyle(
fontSize:
14,
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
),
),
],
),
Container(
decoration: BoxDecoration(
color:
isDark
? AppThemeData.warning50
: AppThemeData.warning50,
borderRadius:
BorderRadius.circular(
30,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal:
10,
vertical:
6,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisSize:
MainAxisSize.min,
children: [
Icon(
Icons.star,
size:
18,
color:
AppThemeData.warning400,
),
Text(
"${Constant.calculateReview(reviewCount: productModel.reviewsCount.toString(), reviewSum: productModel.reviewsSum.toString())} (${productModel.reviewsSum})",
style: AppThemeData.semiBoldTextStyle(
fontSize:
12,
color:
AppThemeData.warning400,
),
),
],
),
),
),
],
),
],
),
);
},
);
},
),
RoundedButtonBorder(
radius: 10,
color:
isDark
? AppThemeData
.greyDark100
: AppThemeData
.grey100,
borderColor:
isDark
? AppThemeData
.greyDark200
: AppThemeData
.grey200,
title: 'View All Products',
onPress: () {
Get.to(
AllCategoryProductScreen(),
arguments: {
"categoryModel": item,
},
);
},
),
],
);
} else {
return SizedBox();
}
},
),
),
);
},
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child:
controller.bannerModel.isEmpty
? const SizedBox()
: BannerBottomView(controller: controller),
),
// Visibility(
// visible: (Constant.isEnableAdsFeature == true && controller.advertisementList.isNotEmpty),
// child: const SizedBox(height: 20),
// ),
// Visibility(
// visible: Constant.isEnableAdsFeature == true,
// child:
// controller.advertisementList.isEmpty
// ? const SizedBox()
// : Container(
// color: AppThemeData.primary300.withAlpha(40),
// child: Padding(
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
// child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// Expanded(
// child: Text(
// "Highlights for you".tr,
// textAlign: TextAlign.start,
// style: TextStyle(
// fontFamily: AppThemeData.semiBold,
// fontSize: 16,
// color: isDark ? AppThemeData.grey50 : AppThemeData.grey900,
// ),
// ),
// ),
// InkWell(
// onTap: () {
// Get.to(AllAdvertisementScreen())?.then((value) {
// controller.getFavouriteRestaurant();
// });
// },
// child: Text(
// "View all".tr,
// textAlign: TextAlign.center,
// style: TextStyle(
// fontFamily: AppThemeData.regular,
// color: isDark ? AppThemeData.primary300 : AppThemeData.primary300,
// ),
// ),
// ),
// ],
// ),
// const SizedBox(height: 16),
// SizedBox(
// height: 220,
// child: ListView.builder(
// physics: const BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
// itemCount:
// controller.advertisementList.length >= 10
// ? 10
// : controller.advertisementList.length,
// padding: EdgeInsets.all(0),
// itemBuilder: (BuildContext context, int index) {
// return AdvertisementHomeCard(
// controller: controller,
// model: controller.advertisementList[index],
// );
// },
// ),
// ),
// ],
// ),
// ),
// ),
// ),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"All Store".tr,
textAlign: TextAlign.start,
style: AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData.greyDark900
: AppThemeData.grey900,
fontSize: 16,
),
),
SizedBox(height: 10),
ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount:
controller.allNearestRestaurant.length > 8
? 8
: controller
.allNearestRestaurant
.length,
itemBuilder: (context, index) {
VendorModel item =
controller.allNearestRestaurant[index];
return InkWell(
onTap: () {
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": item},
);
},
child: Padding(
padding: const EdgeInsets.only(
bottom: 20,
),
child: Row(
children: [
ClipRRect(
borderRadius:
BorderRadius.circular(10),
child: NetworkImageWidget(
imageUrl: item.photo.toString(),
height: 80,
width: 130,
fit: BoxFit.cover,
),
),
SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
item.title.toString(),
style:
AppThemeData.semiBoldTextStyle(
color:
isDark
? AppThemeData
.greyDark900
: AppThemeData
.grey900,
fontSize: 16,
),
),
Row(
children: [
Icon(
Icons.location_on,
size: 14,
color: Colors.grey,
),
SizedBox(width: 4),
Expanded(
child: Text(
item.location
.toString(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 12,
color:
isDark
? AppThemeData
.greyDark500
: AppThemeData
.grey500,
),
overflow:
TextOverflow
.ellipsis,
),
),
],
),
Container(
decoration: BoxDecoration(
color:
isDark
? AppThemeData
.warning50
: AppThemeData
.warning50,
borderRadius:
BorderRadius.circular(
30,
),
),
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.center,
crossAxisAlignment:
CrossAxisAlignment
.center,
mainAxisSize:
MainAxisSize.min,
children: [
Icon(
Icons.star,
size: 18,
color:
AppThemeData
.warning400,
),
Text(
"${Constant.calculateReview(reviewCount: item.reviewsCount.toString(), reviewSum: item.reviewsSum.toString())} (${item.reviewsSum})",
style: AppThemeData.semiBoldTextStyle(
fontSize: 12,
color:
AppThemeData
.warning400,
),
),
],
),
),
),
],
),
),
],
),
),
);
},
),
RoundedButtonBorder(
radius: 10,
color:
isDark
? AppThemeData.greyDark100
: AppThemeData.grey100,
borderColor:
isDark
? AppThemeData.greyDark200
: AppThemeData.grey200,
title: 'View All Stores'.tr,
onPress: () {
Get.to(
const RestaurantListScreen(),
arguments: {
"vendorList":
controller.allNearestRestaurant,
},
);
},
),
],
),
),
],
),
),
),
);
},
);
}
}
class NewArrivalCard extends StatelessWidget {
final VendorModel item;
const NewArrivalCard({super.key, required this.item});
@override
Widget build(BuildContext context) {
final themeController = Get.find<ThemeController>();
final isDark = themeController.isDark.value;
return InkWell(
onTap: () {
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": item},
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: NetworkImageWidget(
height: 100,
width: double.infinity,
fit: BoxFit.cover,
imageUrl:
item.photo != null && item.photo!.isNotEmpty
? item.photo.toString()
: Constant.placeHolderImage.toString(),
),
),
SizedBox(height: 5),
Text(
item.title.toString(),
style: AppThemeData.semiBoldTextStyle(
color: isDark ? AppThemeData.greyDark900 : AppThemeData.grey900,
fontSize: 14,
),
),
Row(
children: [
Icon(Icons.location_on, size: 14, color: Colors.grey),
SizedBox(width: 4),
Expanded(
child: Text(
item.location.toString(),
style: AppThemeData.semiBoldTextStyle(
fontSize: 12,
color:
isDark
? AppThemeData.greyDark500
: AppThemeData.grey500,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
Container(
decoration: BoxDecoration(
color: isDark ? AppThemeData.warning50 : AppThemeData.warning50,
borderRadius: BorderRadius.circular(30),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, size: 18, color: AppThemeData.warning400),
Text(
"${Constant.calculateReview(reviewCount: item.reviewsCount.toString(), reviewSum: item.reviewsSum.toString())} (${item.reviewsSum})",
style: AppThemeData.semiBoldTextStyle(
fontSize: 12,
color: AppThemeData.warning400,
),
),
],
),
),
),
],
),
);
}
}
class BannerView extends StatelessWidget {
final HomeECommerceController controller;
const BannerView({super.key, required this.controller});
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 160,
child: PageView.builder(
physics: const BouncingScrollPhysics(),
controller: controller.pageController.value,
scrollDirection: Axis.horizontal,
itemCount: controller.bannerModel.length,
padEnds: false,
pageSnapping: true,
allowImplicitScrolling: true,
onPageChanged: (value) {
controller.currentPage.value = value;
},
itemBuilder: (BuildContext context, int index) {
BannerModel bannerModel = controller.bannerModel[index];
return InkWell(
onTap: () async {
if (bannerModel.redirect_type == "store") {
ShowToastDialog.showLoader("Please wait...".tr);
VendorModel? vendorModel =
await FireStoreUtils.getVendorById(
bannerModel.redirect_id.toString(),
);
ShowToastDialog.closeLoader();
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": vendorModel},
);
} else if (bannerModel.redirect_type == "product") {
ShowToastDialog.showLoader("Please wait...".tr);
ProductModel? productModel =
await FireStoreUtils.getProductById(
bannerModel.redirect_id.toString(),
);
VendorModel? vendorModel =
await FireStoreUtils.getVendorById(
productModel!.vendorID.toString(),
);
ShowToastDialog.closeLoader();
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": vendorModel},
);
} else if (bannerModel.redirect_type == "external_link") {
final uri = Uri.parse(bannerModel.redirect_id.toString());
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
ShowToastDialog.showToast("Could not launch".tr);
}
}
},
child: Padding(
padding: const EdgeInsets.only(right: 14),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: NetworkImageWidget(
imageUrl: bannerModel.photo.toString(),
fit: BoxFit.cover,
),
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: List.generate(controller.bannerModel.length, (index) {
return Obx(
() => Container(
margin: const EdgeInsets.only(right: 5),
alignment: Alignment.centerLeft,
height: 9,
width: 9,
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
controller.currentPage.value == index
? AppThemeData.primary300
: Colors.black12,
),
),
);
}),
),
),
],
);
}
}
class BannerBottomView extends StatelessWidget {
final HomeECommerceController controller;
const BannerBottomView({super.key, required this.controller});
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 150,
child: PageView.builder(
physics: const BouncingScrollPhysics(),
controller: controller.pageBottomController.value,
scrollDirection: Axis.horizontal,
itemCount: controller.bannerBottomModel.length,
padEnds: false,
pageSnapping: true,
allowImplicitScrolling: true,
onPageChanged: (value) {
controller.currentBottomPage.value = value;
},
itemBuilder: (BuildContext context, int index) {
BannerModel bannerModel = controller.bannerBottomModel[index];
return InkWell(
onTap: () async {
if (bannerModel.redirect_type == "store") {
ShowToastDialog.showLoader("Please wait...".tr);
VendorModel? vendorModel =
await FireStoreUtils.getVendorById(
bannerModel.redirect_id.toString(),
);
ShowToastDialog.closeLoader();
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": vendorModel},
);
} else if (bannerModel.redirect_type == "product") {
ShowToastDialog.showLoader("Please wait...".tr);
ProductModel? productModel =
await FireStoreUtils.getProductById(
bannerModel.redirect_id.toString(),
);
VendorModel? vendorModel =
await FireStoreUtils.getVendorById(
productModel!.vendorID.toString(),
);
ShowToastDialog.closeLoader();
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": vendorModel},
);
} else if (bannerModel.redirect_type == "external_link") {
final uri = Uri.parse(bannerModel.redirect_id.toString());
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
ShowToastDialog.showToast("Could not launch".tr);
}
}
},
child: Padding(
padding: const EdgeInsets.only(right: 14),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: NetworkImageWidget(
imageUrl: bannerModel.photo.toString(),
fit: BoxFit.cover,
),
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: List.generate(controller.bannerBottomModel.length, (
index,
) {
return Obx(
() => Container(
margin: const EdgeInsets.only(right: 5),
alignment: Alignment.centerLeft,
height: 9,
width: 9,
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
controller.currentBottomPage.value == index
? AppThemeData.primary300
: Colors.black12,
),
),
);
}),
),
),
],
);
}
}
class AdvertisementHomeCard extends StatelessWidget {
final AdvertisementModel model;
final HomeECommerceController controller;
const AdvertisementHomeCard({
super.key,
required this.controller,
required this.model,
});
@override
Widget build(BuildContext context) {
final themeController = Get.find<ThemeController>();
final isDark = themeController.isDark.value;
return InkWell(
onTap: () async {
ShowToastDialog.showLoader("Please wait...".tr);
VendorModel? vendorModel = await FireStoreUtils.getVendorById(
model.vendorId!,
);
ShowToastDialog.closeLoader();
Get.to(
const RestaurantDetailsScreen(),
arguments: {"vendorModel": vendorModel},
);
},
child: Container(
margin: EdgeInsets.only(right: 16),
width: Responsive.width(70, context),
decoration: BoxDecoration(
color: isDark ? AppThemeData.info600 : AppThemeData.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: isDark ? 6 : 2,
spreadRadius: 0,
offset: Offset(0, isDark ? 3 : 1),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
model.type == 'restaurant_promotion'
? ClipRRect(
borderRadius: BorderRadius.vertical(
top: Radius.circular(16),
),
child: NetworkImageWidget(
imageUrl: model.coverImage ?? '',
height: 135,
width: double.infinity,
fit: BoxFit.cover,
),
)
: VideoAdvWidget(
url: model.video ?? '',
height: 135,
width: double.infinity,
),
if (model.type != 'video_promotion' &&
model.vendorId != null &&
(model.showRating == true || model.showReview == true))
Positioned(
bottom: 8,
right: 8,
child: FutureBuilder(
future: FireStoreUtils.getVendorById(model.vendorId!),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const SizedBox();
} else {
if (snapshot.hasError) {
return const SizedBox();
} else if (snapshot.data == null) {
return const SizedBox();
} else {
VendorModel vendorModel = snapshot.data!;
return Container(
decoration: ShapeDecoration(
color:
isDark
? AppThemeData.primary600
: AppThemeData.primary50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(120),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
child: Row(
children: [
if (model.showRating == true)
SvgPicture.asset(
"assets/icons/ic_star.svg",
colorFilter: ColorFilter.mode(
AppThemeData.primary300,
BlendMode.srcIn,
),
),
if (model.showRating == true)
const SizedBox(width: 5),
Text(
"${model.showRating == true ? Constant.calculateReview(reviewCount: vendorModel.reviewsCount!.toStringAsFixed(0), reviewSum: vendorModel.reviewsSum.toString()) : ''} ${model.showReview == true ? '(${vendorModel.reviewsCount!.toStringAsFixed(0)})' : ''}",
style: TextStyle(
fontSize: 14,
color:
isDark
? AppThemeData.primary300
: AppThemeData.primary300,
fontFamily: AppThemeData.semiBold,
fontWeight: FontWeight.w600,
),
),
],
),
),
);
}
}
},
),
),
],
),
Padding(
padding: EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (model.type == 'restaurant_promotion')
ClipRRect(
borderRadius: BorderRadius.circular(30),
child: NetworkImageWidget(
imageUrl: model.profileImage ?? '',
height: 50,
width: 50,
fit: BoxFit.cover,
),
),
SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
model.title ?? '',
style: TextStyle(
color:
isDark
? AppThemeData.grey50
: AppThemeData.grey900,
fontSize: 14,
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
),
Text(
model.description ?? '',
style: TextStyle(
fontSize: 12,
fontFamily: AppThemeData.medium,
color:
isDark
? AppThemeData.grey400
: AppThemeData.grey600,
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
],
),
),
model.type == 'restaurant_promotion'
? IconButton(
icon: Obx(
() =>
controller.favouriteList
.where(
(p0) =>
p0.restaurantId == model.vendorId,
)
.isNotEmpty
? SvgPicture.asset(
"assets/icons/ic_like_fill.svg",
)
: SvgPicture.asset(
"assets/icons/ic_like.svg",
colorFilter: ColorFilter.mode(
isDark
? AppThemeData.grey400
: AppThemeData.grey600,
BlendMode.srcIn,
),
),
),
onPressed: () async {
if (controller.favouriteList
.where((p0) => p0.restaurantId == model.vendorId)
.isNotEmpty) {
FavouriteModel favouriteModel = FavouriteModel(
restaurantId: model.vendorId,
userId: FireStoreUtils.getCurrentUid(),
);
controller.favouriteList.removeWhere(
(item) => item.restaurantId == model.vendorId,
);
await FireStoreUtils.removeFavouriteRestaurant(
favouriteModel,
);
} else {
FavouriteModel favouriteModel = FavouriteModel(
restaurantId: model.vendorId,
userId: FireStoreUtils.getCurrentUid(),
);
controller.favouriteList.add(favouriteModel);
await FireStoreUtils.setFavouriteRestaurant(
favouriteModel,
);
}
controller.update();
},
)
: Container(
decoration: ShapeDecoration(
color:
isDark
? AppThemeData.primary600
: AppThemeData.primary50,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
child: Icon(
Icons.arrow_forward,
size: 20,
color: AppThemeData.primary300,
),
),
),
],
),
),
],
),
),
);
}
}