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

1132 lines
68 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)),
),
],
),
),
],
),
),
);
}
}