From 1f7254ecaa5b4088ba2c93f19e9d6ff71528dc65 Mon Sep 17 00:00:00 2001 From: bestonemitRam Date: Mon, 3 Feb 2025 01:29:42 +0530 Subject: [PATCH] updateProfile --- .DS_Store | Bin 10244 -> 10244 bytes .dart_tool/dartpad/web_plugin_registrant.dart | 4 + .dart_tool/package_config.json | 420 ++++--- .dart_tool/package_config_subset | 630 ++++++---- .dart_tool/version | 2 +- .flutter-plugins | 75 +- .flutter-plugins-dependencies | 2 +- android/app/src/main/AndroidManifest.xml | 31 + lib/main.dart | 12 +- lib/src/common_widget/name_text_field.dart | 5 +- lib/src/common_widget/network_image.dart | 7 +- lib/src/core/constant/api.dart | 27 +- lib/src/core/routes/routes.dart | 65 +- lib/src/data/address.dart | 182 +++ lib/src/data/upload_image.dart | 53 + lib/src/data/user_profile.dart | 110 ++ lib/src/data/wish_list_model.dart | 491 +++++++- .../logic/provider/addTocart_provider.dart | 202 +++- lib/src/logic/provider/address_provider.dart | 74 ++ .../provider/bottom_navbar_provider.dart | 56 +- lib/src/logic/provider/home_provider.dart | 155 ++- lib/src/logic/provider/profile_provider.dart | 94 ++ lib/src/logic/repo/auth_repo.dart | 22 +- lib/src/logic/repo/product_repo.dart | 126 +- .../logic/services/auth_service_locator.dart | 74 +- lib/src/logic/services/home_locator.dart | 40 + lib/src/ui/bestdeal/bestdeal_screen.dart | 44 +- .../bottomnavigation/bottom_bar_widget.dart | 2 + lib/src/ui/cart/cartview_screen.dart | 1031 +++++++++++++--- lib/src/ui/coupons/coupons_screen.dart | 135 +++ .../ui/edit_profile/edit_profile_screen.dart | 279 +++-- lib/src/ui/favourite/favourite_screen.dart | 948 ++++++++------- .../fruitvegidetail/fruit_veggie_detail.dart | 96 +- lib/src/ui/home/home_screen.dart | 1070 +++++++++++------ lib/src/ui/map/add_locations.dart | 466 +++++++ lib/src/ui/map/google_map.dart | 330 ----- .../ui/productdetails/product_details.dart | 753 ++++++------ lib/src/ui/profilepage/profile_screen.dart | 131 +- lib/src/ui/splash/splash_screen.dart | 6 + lib/utils/constants/shared_pref_utils.dart | 49 +- lib/utils/constants/string_constant.dart | 15 +- linux/flutter/generated_plugin_registrant.cc | 8 + linux/flutter/generated_plugins.cmake | 2 + macos/Flutter/GeneratedPluginRegistrant.swift | 4 + pubspec.lock | 220 +++- pubspec.yaml | 5 +- .../flutter/generated_plugin_registrant.cc | 6 + windows/flutter/generated_plugins.cmake | 2 + 48 files changed, 6088 insertions(+), 2473 deletions(-) create mode 100644 lib/src/data/address.dart create mode 100644 lib/src/data/upload_image.dart create mode 100644 lib/src/data/user_profile.dart create mode 100644 lib/src/logic/provider/address_provider.dart create mode 100644 lib/src/logic/provider/profile_provider.dart create mode 100644 lib/src/ui/coupons/coupons_screen.dart create mode 100644 lib/src/ui/map/add_locations.dart delete mode 100644 lib/src/ui/map/google_map.dart diff --git a/.DS_Store b/.DS_Store index 098ff8d4e21ce04fe4d9e1d61c9e35107f58d9f5..7793275c58ee2c055f92392c0d5acd318c88d299 100644 GIT binary patch delta 99 zcmZn(XbIS$EzG!MvW{?}yF_)huBnNRf~jS#jzYDefvKU6g1M1FZ7nB + + + + + + + + + + + + @@ -59,4 +72,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/lib/main.dart b/lib/main.dart index fc52d18..f6d217e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,9 +3,11 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:grocery_app/src/core/network_services/service_locator.dart'; import 'package:grocery_app/src/core/routes/routes.dart'; import 'package:grocery_app/src/logic/provider/addTocart_provider.dart'; +import 'package:grocery_app/src/logic/provider/address_provider.dart'; import 'package:grocery_app/src/logic/provider/auth_provider.dart'; import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; import 'package:grocery_app/src/logic/provider/home_provider.dart'; +import 'package:grocery_app/src/logic/provider/profile_provider.dart'; import 'package:grocery_app/src/ui/splash/splash_screen.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; import 'package:grocery_app/utils/constants/string_constant.dart'; @@ -30,21 +32,23 @@ class MyApplication extends StatelessWidget { splitScreenMode: true, builder: (context, child) => GlobalLoaderOverlay( overlayColor: APPCOLOR.whiteFBFEFB.withOpacity(0.5), + useDefaultLoading: false, // overlayWidgetBuilder: (progress) => const GlobalLoader(), child: MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AuthProvider()), - ChangeNotifierProvider(create: (_) => ProductProvider()), + ChangeNotifierProvider(create: (_) => ProductProvider()), ChangeNotifierProvider(create: (_) => AddtocartProvider()), - ChangeNotifierProvider(create: (_) => BottomNavProvider()), - // ChangeNotifierProvider(create: (_) => HomeProvider()), + ChangeNotifierProvider(create: (_) => BottomNavProvider()), + ChangeNotifierProvider(create: (_) => AddressProvider()), + ChangeNotifierProvider(create: (_) => ProfileProvider()), ], child: MaterialApp.router( routerConfig: MyRoutes.router, debugShowCheckedModeBanner: false, theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightGreen), scaffoldBackgroundColor: Colors.white, canvasColor: const Color.fromRGBO(255, 255, 255, 1), fontFamily: 'GoogleSans', diff --git a/lib/src/common_widget/name_text_field.dart b/lib/src/common_widget/name_text_field.dart index 4ebe6da..f755a10 100644 --- a/lib/src/common_widget/name_text_field.dart +++ b/lib/src/common_widget/name_text_field.dart @@ -9,7 +9,8 @@ class NameTextField extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return + Container( height: 60, width: MediaQuery.sizeOf(context).width, decoration: BoxDecoration(border: Border.all(color: APPCOLOR.lightGreen), borderRadius: BorderRadius.circular(15)), @@ -40,5 +41,7 @@ class NameTextField extends StatelessWidget { ), ), ); + + } } diff --git a/lib/src/common_widget/network_image.dart b/lib/src/common_widget/network_image.dart index 0089ac2..078ca9f 100644 --- a/lib/src/common_widget/network_image.dart +++ b/lib/src/common_widget/network_image.dart @@ -60,8 +60,10 @@ class AppNetworkImage extends StatelessWidget { )), ); }, - placeholder: (context, url) { - return Container( + placeholder: (context, url) + { + return + Container( width: width, height: height, decoration: BoxDecoration( @@ -76,6 +78,7 @@ class AppNetworkImage extends StatelessWidget { ), ); }, + imageBuilder: (context, cIMage) { return Container( width: width, diff --git a/lib/src/core/constant/api.dart b/lib/src/core/constant/api.dart index 859e6fa..e1bdd7b 100644 --- a/lib/src/core/constant/api.dart +++ b/lib/src/core/constant/api.dart @@ -1,33 +1,36 @@ class APIURL { static const BASE_URL = "http://210.89.44.183:3333/xam/"; static const String sendOtp = "${BASE_URL}auth/send-otp/customer"; - static const String verifyOtp = "${BASE_URL}auth/verify-otp/customer"; - - static const String loginOtp = "${BASE_URL}auth/login/customer"; - + static const String loginOtp = "${BASE_URL}auth/login/customer"; static const String login = "${BASE_URL}auth/login/vendor"; static const String customerRegister = "${BASE_URL}auth/register/customer"; static const String getAllProduct = "${BASE_URL}products"; - static const String getProductDetails = "${BASE_URL}products/"; + static const String getProductDetails = "${BASE_URL}products/"; static const String getBanners = "${BASE_URL}banners"; static const String customerLogOut = "${BASE_URL}auth/logout/customer"; static const String getBestDealProduct = "${BASE_URL}products/best-deals"; static const String getAllcategory = "${BASE_URL}categories"; static const String addToWish = "${BASE_URL}carts/wishlist/items"; - static const String deleteToWish = "${BASE_URL}carts/wishlist/items"; + static const String deleteToWish = "${BASE_URL}carts/wishlist/items"; static const String addToCart = "${BASE_URL}carts/items"; static const String gettAllWishList = "${BASE_URL}carts/wishlist"; static const String similarProduct = "${BASE_URL}products/"; static const String getItemCards = "${BASE_URL}carts/current"; static const String checkPin = "${BASE_URL}pin-codes/check/"; static const String deleteItem = "${BASE_URL}carts/items/"; - - + static const String userAddress = "${BASE_URL}user/addresses"; + static const String addAddress = "${BASE_URL}user/addresses"; + static const String getprofile = "${BASE_URL}user/profile/customer"; + static const String refresh_token = "${BASE_URL}auth/refresh-token"; + static const String uploadImage = "${BASE_URL}images/upload"; + static const String updateProfile = "${BASE_URL}user/profile"; + + + - - static const String updateStore = "${BASE_URL}stores/"; + static const String forgetPassword = "${BASE_URL}auth/forgot-password/vendor"; static const String verifyForgetPassword = "${BASE_URL}auth/forgot-password-verify-otp/vendor"; @@ -36,10 +39,10 @@ class APIURL { static const String getProduct = "${BASE_URL}products"; static const String getCategoryByLevel = "${BASE_URL}categories/by-level/1"; static const String getMe = "${BASE_URL}auth/me"; - static const String refresh_token = "${BASE_URL}auth/refresh-token"; + static const String createProduct = "${BASE_URL}products"; - static const String uploadImage = "${BASE_URL}images/upload"; + static const String deleteProduct = "${BASE_URL}products/"; static const String updateProduct = "${BASE_URL}products/"; } diff --git a/lib/src/core/routes/routes.dart b/lib/src/core/routes/routes.dart index ead3c7e..3e11369 100644 --- a/lib/src/core/routes/routes.dart +++ b/lib/src/core/routes/routes.dart @@ -4,10 +4,12 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:grocery_app/src/data/allProduct_model.dart'; import 'package:grocery_app/src/ui/bottomnavigation/bottom_bar_widget.dart'; +import 'package:grocery_app/src/ui/coupons/coupons_screen.dart'; import 'package:grocery_app/src/ui/entername/enter_fullname_screen.dart'; import 'package:grocery_app/src/ui/fruitvegidetail/fruit_veggie_detail.dart'; import 'package:grocery_app/src/ui/login/login_screen.dart'; import 'package:grocery_app/src/ui/login/signup_screen.dart'; +import 'package:grocery_app/src/ui/map/add_locations.dart'; import 'package:grocery_app/src/ui/onboarding/on_boarding_screen.dart'; import 'package:grocery_app/src/ui/otp/login_otp.dart'; import 'package:grocery_app/src/ui/otp/otp_screen.dart'; @@ -72,14 +74,16 @@ class MyRoutes { pageBuilder: (context, state) => const FruitVeggieDetail(), ), - // animatedGoRoute( - // path: PRODUCTDETAILS, - // name: PRODUCTDETAILS, - // pageBuilder: (context, state) - // { - // return const ProductDetails(); - // } - // ), + animatedGoRoute( + path: COUPONSSCREEN, + name: COUPONSSCREEN, + pageBuilder: (context, state) => CouponsScreen(), + ), + animatedGoRoute( + path: ADDRESSS, + name: ADDRESSS, + pageBuilder: (context, state) => AddLocationAddress(), + ), animatedGoRoute( path: PRODUCTDETAILS, @@ -219,44 +223,39 @@ class MyRoutes { static const FRUITVEGGIEDETAIL = "/FruitVeggieDetail"; static const PRODUCTDETAILS = "/productdetails"; static const LOGINOTPSCREEN = "/loginotpscreen"; - - - - static const SELECTACCOUNT = "/selectAccount"; - static const DASHBOARD = "/dashboard"; - - + static const COUPONSSCREEN = "/CouponsScreen"; + static const ADDRESSS = "/address"; static const LOGIN = "/login"; static const SIGNUP = "/signup"; - static const ONBOARDING = "/onboarding"; - static const TERMANDCONDITIONS = "/termsandcondition"; - static const SETUPBUSSINESS = "/setupbussiness"; - static const CREATESTORE = "/createStore"; - static const SUBMITSCREEN = "/submitscreen"; - static const APPROVEDSTATUS = "/approvedstatus"; - static const DASHBOARDSCREEN = "/dashboardscreen"; - static const CUSTOMERORDER = "/customerorder"; + // static const TERMANDCONDITIONS = "/termsandcondition"; + // static const SETUPBUSSINESS = "/setupbussiness"; + // static const CREATESTORE = "/createStore"; + // static const SUBMITSCREEN = "/submitscreen"; + // static const APPROVEDSTATUS = "/approvedstatus"; - static const PRODUCTFORMSCREEN = "/productformscreen"; + // static const DASHBOARDSCREEN = "/dashboardscreen"; + // static const CUSTOMERORDER = "/customerorder"; - static const TRANSACTIONHISTORY = "/transationhistory"; + // static const PRODUCTFORMSCREEN = "/productformscreen"; - static const INSIGHTSHISTORY = "/insightshistory"; + // static const TRANSACTIONHISTORY = "/transationhistory"; - static const DETAILSBUSSINESS = "/detailsbussiness"; + // static const INSIGHTSHISTORY = "/insightshistory"; - static const STOREMANAGEMENT = "/storemanagement"; + // static const DETAILSBUSSINESS = "/detailsbussiness"; - static const SETTING = "/settings"; + // static const STOREMANAGEMENT = "/storemanagement"; - static const FORGETPASSWORD = "/forgetpassword"; - static const VERIFYPASSWORD = "/verifypassword"; + // static const SETTING = "/settings"; - static const FORGETNEWPASSWORD = "/forgetnewpassword"; + // static const FORGETPASSWORD = "/forgetpassword"; + // static const VERIFYPASSWORD = "/verifypassword"; - static const UPDATESTORE = "/updatestore"; + // static const FORGETNEWPASSWORD = "/forgetnewpassword"; + + // static const UPDATESTORE = "/updatestore"; static const OTPSCREEN = "/otpscreen"; } diff --git a/lib/src/data/address.dart b/lib/src/data/address.dart new file mode 100644 index 0000000..5a7f3fd --- /dev/null +++ b/lib/src/data/address.dart @@ -0,0 +1,182 @@ + + +import 'dart:convert'; + +AddressResponse addressResponseFromJson(dynamic str) => + AddressResponse.fromJson(json.decode(str)); + +dynamic addressResponseToJson(AddressResponse data) => + json.encode(data.toJson()); + +class AddressResponse { + List? data; + Meta? meta; + + AddressResponse({ + this.data, + this.meta, + }); + + factory AddressResponse.fromJson(Map json) => + AddressResponse( + data: List.from(json["data"].map((x) => Datum.fromJson(x))), + meta: Meta.fromJson(json["meta"]), + ); + + Map toJson() => { + "data": List.from(data!.map((x) => x.toJson())), + "meta": meta!.toJson(), + }; +} + +class Datum { + dynamic id; + dynamic pincode; + dynamic phoneNumber; + dynamic alternatePhoneNumber; + dynamic addressLine; + dynamic landmark; + dynamic addressType; + dynamic city; + dynamic district; + dynamic name; + dynamic state; + dynamic country; + bool? isDeliverable; + bool? isDefault; + dynamic additionalInstructions; + DateTime? createdAt; + DateTime? updatedAt; + dynamic userId; + User? user; + + Datum({ + this.id, + this.pincode, + this.phoneNumber, + this.alternatePhoneNumber, + this.addressLine, + this.landmark, + this.addressType, + this.city, + this.district, + this.name, + this.state, + this.country, + this.isDeliverable, + this.isDefault, + this.additionalInstructions, + this.createdAt, + this.updatedAt, + this.userId, + this.user, + }); + + factory Datum.fromJson(Map json) => Datum( + id: json["id"], + pincode: json["pincode"], + phoneNumber: json["phoneNumber"], + alternatePhoneNumber: json["alternatePhoneNumber"], + addressLine: json["addressLine"], + landmark: json["landmark"], + addressType: json["addressType"], + city: json["city"], + district: json["district"], + name: json["name"], + state: json["state"], + country: json["country"], + isDeliverable: json["isDeliverable"], + isDefault: json["isDefault"], + additionalInstructions: json["additionalInstructions"], + createdAt: DateTime.parse(json["createdAt"]), + updatedAt: DateTime.parse(json["updatedAt"]), + userId: json["userId"], + user: User.fromJson(json["user"]), + ); + + Map toJson() => { + "id": id, + "pincode": pincode, + "phoneNumber": phoneNumber, + "alternatePhoneNumber": alternatePhoneNumber, + "addressLine": addressLine, + "landmark": landmark, + "addressType": addressType, + "city": city, + "district": district, + "name": name, + "state": state, + "country": country, + "isDeliverable": isDeliverable, + "isDefault": isDefault, + "additionalInstructions": additionalInstructions, + "createdAt": createdAt, + "updatedAt": updatedAt, + "userId": userId, + "user": user!.toJson(), + }; +} + +class User { + dynamic firstName; + dynamic lastName; + dynamic email; + dynamic phone; + + User({ + this.firstName, + this.lastName, + this.email, + this.phone, + }); + + factory User.fromJson(Map json) => User( + firstName: json["firstName"], + lastName: json["lastName"], + email: json["email"], + phone: json["phone"], + ); + + Map toJson() => { + "firstName": firstName, + "lastName": lastName, + "email": email, + "phone": phone, + }; +} + +class Meta { + int? total; + int? page; + int? limit; + int? lastPage; + bool? hasNextPage; + bool? hasPreviousPage; + + Meta({ + this.total, + this.page, + this.limit, + this.lastPage, + this.hasNextPage, + this.hasPreviousPage, + }); + + factory Meta.fromJson(Map json) => Meta( + total: json["total"], + page: json["page"], + limit: json["limit"], + lastPage: json["lastPage"], + hasNextPage: json["hasNextPage"], + hasPreviousPage: json["hasPreviousPage"], + ); + + Map toJson() => { + "total": total, + "page": page, + "limit": limit, + "lastPage": lastPage, + "hasNextPage": hasNextPage, + "hasPreviousPage": hasPreviousPage, + }; +} diff --git a/lib/src/data/upload_image.dart b/lib/src/data/upload_image.dart new file mode 100644 index 0000000..188379e --- /dev/null +++ b/lib/src/data/upload_image.dart @@ -0,0 +1,53 @@ +// To parse this JSON data, do +// +// final uploadImage = uploadImageFromJson(jsonString); + +import 'dart:convert'; + +UploadImage uploadImageFromJson(String str) => UploadImage.fromJson(json.decode(str)); + +String uploadImageToJson(UploadImage data) => json.encode(data.toJson()); + +class UploadImage { + int? status; + String? message; + Image? data; + + UploadImage({ + this.status, + this.message, + this.data, + }); + + factory UploadImage.fromJson(Map json) => UploadImage( + status: json["status"], + message: json["message"], + data: Image.fromJson(json["data"]), + ); + + Map toJson() => { + "status": status, + "message": message, + "data": data!.toJson(), + }; +} + +class Image { + String? url; + String? publicId; + + Image({ + this.url, + this.publicId, + }); + + factory Image.fromJson(Map json) => Image( + url: json["url"], + publicId: json["publicId"], + ); + + Map toJson() => { + "url": url, + "publicId": publicId, + }; +} diff --git a/lib/src/data/user_profile.dart b/lib/src/data/user_profile.dart new file mode 100644 index 0000000..9f0b057 --- /dev/null +++ b/lib/src/data/user_profile.dart @@ -0,0 +1,110 @@ +// To parse this JSON data, do +// +// final userProfile = userProfileFromJson(jsondynamic); + +import 'dart:convert'; + +UserProfile userProfileFromJson(dynamic str) => + UserProfile.fromJson(json.decode(str)); + +dynamic userProfileToJson(UserProfile data) => json.encode(data.toJson()); + +class UserProfile { + dynamic id; + dynamic email; + dynamic firstName; + dynamic lastName; + dynamic name; + dynamic img; + dynamic authType; + dynamic role; + dynamic phone; + dynamic password; + bool? isActive; + bool? isPhoneVerified; + dynamic vendorType; + dynamic businessId; + bool? isVendorAccountCreated; + bool? isVendorAccountActive; + bool? vendorTermsAccepted; + DateTime? createdAt; + DateTime? updatedAt; + dynamic rtHash; + dynamic resetToken; + dynamic resetTokenExpiresAt; + + UserProfile({ + this.id, + this.email, + this.firstName, + this.lastName, + this.name, + this.img, + this.authType, + this.role, + this.phone, + this.password, + this.isActive, + this.isPhoneVerified, + this.vendorType, + this.businessId, + this.isVendorAccountCreated, + this.isVendorAccountActive, + this.vendorTermsAccepted, + this.createdAt, + this.updatedAt, + this.rtHash, + this.resetToken, + this.resetTokenExpiresAt, + }); + + factory UserProfile.fromJson(Map json) => UserProfile( + id: json["id"], + email: json["email"], + firstName: json["firstName"], + lastName: json["lastName"], + name: json["name"], + img: json["img"], + authType: json["authType"], + role: json["role"], + phone: json["phone"], + password: json["password"], + isActive: json["isActive"], + isPhoneVerified: json["isPhoneVerified"], + vendorType: json["vendorType"], + businessId: json["businessId"], + isVendorAccountCreated: json["isVendorAccountCreated"], + isVendorAccountActive: json["isVendorAccountActive"], + vendorTermsAccepted: json["vendorTermsAccepted"], + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), + rtHash: json["rtHash"], + resetToken: json["resetToken"], + resetTokenExpiresAt: json["resetTokenExpiresAt"], + ); + + Map toJson() => { + "id": id, + "email": email, + "firstName": firstName, + "lastName": lastName, + "name": name, + "img": img, + "authType": authType, + "role": role, + "phone": phone, + "password": password, + "isActive": isActive, + "isPhoneVerified": isPhoneVerified, + "vendorType": vendorType, + "businessId": businessId, + "isVendorAccountCreated": isVendorAccountCreated, + "isVendorAccountActive": isVendorAccountActive, + "vendorTermsAccepted": vendorTermsAccepted, + "createdAt": createdAt, + "updatedAt": updatedAt, + "rtHash": rtHash, + "resetToken": resetToken, + "resetTokenExpiresAt": resetTokenExpiresAt, + }; +} diff --git a/lib/src/data/wish_list_model.dart b/lib/src/data/wish_list_model.dart index 68405df..4521af3 100644 --- a/lib/src/data/wish_list_model.dart +++ b/lib/src/data/wish_list_model.dart @@ -1,3 +1,256 @@ +// // To parse this JSON data, do +// // +// // final wishListModel = wishListModelFromJson(jsondynamic); + +// import 'dart:convert'; + +// WishListModel wishListModelFromJson(dynamic str) => WishListModel.fromJson(json.decode(str)); + +// dynamic wishListModelToJson(WishListModel data) => json.encode(data.toJson()); + +// class WishListModel { +// dynamic id; +// dynamic userId; +// DateTime?? createdAt; +// DateTime?? updatedAt; +// List? items; +// dynamic? totalItems; + +// WishListModel({ +// this.id, +// this.userId, +// this.createdAt, +// this.updatedAt, +// this.items, +// this.totalItems, +// }); + +// factory WishListModel.fromJson(Map json) => WishListModel( +// id: json["id"], +// userId: json["userId"], +// createdAt: DateTime?.parse(json["createdAt"]), +// updatedAt: DateTime?.parse(json["updatedAt"]), +// items: List.from(json["items"].map((x) => WishListItem.fromJson(x))), +// totalItems: json["totalItems"], +// ); + +// Map toJson() => { +// "id": id, +// "userId": userId, +// "createdAt": createdAt, +// "updatedAt": updatedAt, +// "items": List.from(items!.map((x) => x.toJson())), +// "totalItems": totalItems, +// }; +// } + +// class WishListItem { +// dynamic id; +// dynamic wishlistId; +// dynamic productId; +// dynamic storeId; +// DateTime?? createdAt; +// DateTime?? updatedAt; +// ProductDatum? product; +// Store? store; + +// WishListItem({ +// this.id, +// this.wishlistId, +// this.productId, +// this.storeId, +// this.createdAt, +// this.updatedAt, +// this.product, +// this.store, +// }); + +// factory WishListItem.fromJson(Map json) => WishListItem( +// id: json["id"], +// wishlistId: json["wishlistId"], +// productId: json["productId"], +// storeId: json["storeId"], +// createdAt: DateTime?.parse(json["createdAt"]), +// updatedAt: DateTime?.parse(json["updatedAt"]), +// product: ProductDatum.fromJson(json["product"]), +// store: Store.fromJson(json["store"]), +// ); + +// Map toJson() => { +// "id": id, +// "wishlistId": wishlistId, +// "productId": productId, +// "storeId": storeId, +// "createdAt": createdAt, +// "updatedAt": updatedAt, +// "product": product!.toJson(), +// "store": store!.toJson(), +// }; +// } + +// class ProductDatum { +// dynamic id; +// dynamic name; +// dynamic description; +// dynamic additionalInfo; +// dynamic brand; +// dynamic basePrice; +// dynamic discountPrice; +// dynamic stock; +// dynamic quantity; +// dynamic unit; +// dynamic slug; +// dynamic rating; +// bool? isInStock; +// bool? isActive; +// bool? isInWishlist; +// DateTime?? createdAt; +// DateTime?? updatedAt; +// dynamic storeId; +// dynamic categoryId; +// dynamic productTypeId; +// dynamic timeSlotId; + +// ProductDatum({ +// this.id, +// this.name, +// this.description, +// this.additionalInfo, +// this.brand, +// this.basePrice, +// this.discountPrice, +// this.stock, +// this.quantity, +// this.unit, +// this.slug, +// this.rating, +// this.isInStock, +// this.isActive, +// this.isInWishlist, +// this.createdAt, +// this.updatedAt, +// this.storeId, +// this.categoryId, +// this.productTypeId, +// this.timeSlotId, +// }); + +// factory ProductDatum.fromJson(Map json) => ProductDatum( +// id: json["id"], +// name: json["name"], +// description: json["description"], +// additionalInfo: json["additionalInfo"], +// brand: json["brand"], +// basePrice: json["basePrice"], +// discountPrice: json["discountPrice"], +// stock: json["stock"], +// quantity: json["quantity"], +// unit: json["unit"], +// slug: json["slug"], +// rating: json["rating"], +// isInStock: json["isInStock"], +// isActive: json["isActive"], +// isInWishlist: json["isInWishlist"], +// createdAt: DateTime?.parse(json["createdAt"]), +// updatedAt: DateTime?.parse(json["updatedAt"]), +// storeId: json["storeId"], +// categoryId: json["categoryId"], +// productTypeId: json["productTypeId"], +// timeSlotId: json["timeSlotId"], +// ); + +// Map toJson() => { +// "id": id, +// "name": name, +// "description": description, +// "additionalInfo": additionalInfo, +// "brand": brand, +// "basePrice": basePrice, +// "discountPrice": discountPrice, +// "stock": stock, +// "quantity": quantity, +// "unit": unit, +// "slug": slug, +// "rating": rating, +// "isInStock": isInStock, +// "isActive": isActive, +// "isInWishlist": isInWishlist, +// "createdAt": createdAt, +// "updatedAt": updatedAt, +// "storeId": storeId, +// "categoryId": categoryId, +// "productTypeId": productTypeId, +// "timeSlotId": timeSlotId, +// }; + +// void add(ProductDatum productDatum) {} +// } + +// class Store { +// dynamic id; +// dynamic storeName; +// dynamic storeDescription; +// dynamic officialPhoneNumber; +// dynamic storeAddress; +// dynamic gstNumber; +// dynamic gumastaNumber; +// dynamic storePicture; +// DateTime?? createdAt; +// DateTime?? updatedAt; +// dynamic vendorId; +// bool? isActive; +// dynamic couponId; + +// Store({ +// this.id, +// this.storeName, +// this.storeDescription, +// this.officialPhoneNumber, +// this.storeAddress, +// this.gstNumber, +// this.gumastaNumber, +// this.storePicture, +// this.createdAt, +// this.updatedAt, +// this.vendorId, +// this.isActive, +// this.couponId, +// }); + +// factory Store.fromJson(Map json) => Store( +// id: json["id"], +// storeName: json["storeName"], +// storeDescription: json["storeDescription"], +// officialPhoneNumber: json["officialPhoneNumber"], +// storeAddress: json["storeAddress"], +// gstNumber: json["gstNumber"], +// gumastaNumber: json["gumastaNumber"], +// storePicture: json["storePicture"], +// createdAt: DateTime?.parse(json["createdAt"]), +// updatedAt: DateTime?.parse(json["updatedAt"]), +// vendorId: json["vendorId"], +// isActive: json["isActive"], +// couponId: json["couponId"], +// ); + +// Map toJson() => { +// "id": id, +// "storeName": storeName, +// "storeDescription": storeDescription, +// "officialPhoneNumber": officialPhoneNumber, +// "storeAddress": storeAddress, +// "gstNumber": gstNumber, +// "gumastaNumber": gumastaNumber, +// "storePicture": storePicture, +// "createdAt": createdAt, +// "updatedAt": updatedAt, +// "vendorId": vendorId, +// "isActive": isActive, +// "couponId": couponId, +// }; +// } + + // To parse this JSON data, do // // final wishListModel = wishListModelFromJson(jsondynamic); @@ -14,7 +267,7 @@ class WishListModel { DateTime? createdAt; DateTime? updatedAt; List? items; - dynamic? totalItems; + dynamic totalItems; WishListModel({ this.id, @@ -28,8 +281,8 @@ class WishListModel { factory WishListModel.fromJson(Map json) => WishListModel( id: json["id"], userId: json["userId"], - createdAt: DateTime.parse(json["createdAt"]), - updatedAt: DateTime.parse(json["updatedAt"]), + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), items: List.from(json["items"].map((x) => WishListItem.fromJson(x))), totalItems: json["totalItems"], ); @@ -70,8 +323,8 @@ class WishListItem { wishlistId: json["wishlistId"], productId: json["productId"], storeId: json["storeId"], - createdAt: DateTime.parse(json["createdAt"]), - updatedAt: DateTime.parse(json["updatedAt"]), + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), product: ProductDatum.fromJson(json["product"]), store: Store.fromJson(json["store"]), ); @@ -96,20 +349,24 @@ class ProductDatum { dynamic brand; dynamic basePrice; dynamic discountPrice; - dynamic stock; - dynamic quantity; + dynamic? stock; + dynamic? quantity; dynamic unit; dynamic slug; - dynamic rating; + dynamic averageRating; bool? isInStock; bool? isActive; - bool? isInWishlist; DateTime? createdAt; DateTime? updatedAt; dynamic storeId; dynamic categoryId; dynamic productTypeId; dynamic timeSlotId; + List? productImages; + Category? category; + List? productTags; + List? zones; + List? productReview; ProductDatum({ this.id, @@ -123,16 +380,20 @@ class ProductDatum { this.quantity, this.unit, this.slug, - this.rating, + this.averageRating, this.isInStock, this.isActive, - this.isInWishlist, this.createdAt, this.updatedAt, this.storeId, this.categoryId, this.productTypeId, this.timeSlotId, + this.productImages, + this.category, + this.productTags, + this.zones, + this.productReview, }); factory ProductDatum.fromJson(Map json) => ProductDatum( @@ -147,16 +408,20 @@ class ProductDatum { quantity: json["quantity"], unit: json["unit"], slug: json["slug"], - rating: json["rating"], + averageRating: json["averageRating"], isInStock: json["isInStock"], isActive: json["isActive"], - isInWishlist: json["isInWishlist"], - createdAt: DateTime.parse(json["createdAt"]), - updatedAt: DateTime.parse(json["updatedAt"]), + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), storeId: json["storeId"], categoryId: json["categoryId"], productTypeId: json["productTypeId"], timeSlotId: json["timeSlotId"], + productImages: List.from(json["productImages"].map((x) => ProductImage.fromJson(x))), + category: Category.fromJson(json["category"]), + productTags: List.from(json["productTags"].map((x) => ProductTag.fromJson(x))), + zones: List.from(json["zones"].map((x) => x)), + productReview: List.from(json["ProductReview"].map((x) => ProductReview.fromJson(x))), ); Map toJson() => { @@ -171,16 +436,204 @@ class ProductDatum { "quantity": quantity, "unit": unit, "slug": slug, - "rating": rating, + "averageRating": averageRating, "isInStock": isInStock, "isActive": isActive, - "isInWishlist": isInWishlist, "createdAt": createdAt, "updatedAt": updatedAt, "storeId": storeId, "categoryId": categoryId, "productTypeId": productTypeId, "timeSlotId": timeSlotId, + "productImages": List.from(productImages!.map((x) => x.toJson())), + "category": category!.toJson(), + "productTags": List.from(productTags!.map((x) => x.toJson())), + "zones": List.from(zones!.map((x) => x)), + "ProductReview": List.from(productReview!.map((x) => x.toJson())), + }; +} + +class Category { + dynamic id; + dynamic name; + dynamic description; + dynamic image; + dynamic slug; + dynamic? level; + bool? isActive; + DateTime? createdAt; + DateTime? updatedAt; + dynamic parentCategoryId; + dynamic path; + + Category({ + this.id, + this.name, + this.description, + this.image, + this.slug, + this.level, + this.isActive, + this.createdAt, + this.updatedAt, + this.parentCategoryId, + this.path, + }); + + factory Category.fromJson(Map json) => Category( + id: json["id"], + name: json["name"], + description: json["description"], + image: json["image"], + slug: json["slug"], + level: json["level"], + isActive: json["isActive"], + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), + parentCategoryId: json["parentCategoryId"], + path: json["path"], + ); + + Map toJson() => { + "id": id, + "name": name, + "description": description, + "image": image, + "slug": slug, + "level": level, + "isActive": isActive, + "createdAt": createdAt, + "updatedAt": updatedAt, + "parentCategoryId": parentCategoryId, + "path": path, + }; +} + +class ProductImage { + dynamic id; + dynamic url; + bool? isDefault; + dynamic productId; + + ProductImage({ + this.id, + this.url, + this.isDefault, + this.productId, + }); + + factory ProductImage.fromJson(Map json) => ProductImage( + id: json["id"], + url: json["url"], + isDefault: json["isDefault"], + productId: json["productId"], + ); + + Map toJson() => { + "id": id, + "url": url, + "isDefault": isDefault, + "productId": productId, + }; +} + +class ProductReview { + dynamic id; + dynamic userId; + dynamic productId; + dynamic rating; + dynamic title; + dynamic description; + dynamic? likes; + dynamic? dislikes; + dynamic? helpfulCount; + bool? verifiedPurchase; + dynamic status; + DateTime? createdAt; + DateTime? updatedAt; + + ProductReview({ + this.id, + this.userId, + this.productId, + this.rating, + this.title, + this.description, + this.likes, + this.dislikes, + this.helpfulCount, + this.verifiedPurchase, + this.status, + this.createdAt, + this.updatedAt, + }); + + factory ProductReview.fromJson(Map json) => ProductReview( + id: json["id"], + userId: json["userId"], + productId: json["productId"], + rating: json["rating"], + title: json["title"], + description: json["description"], + likes: json["likes"], + dislikes: json["dislikes"], + helpfulCount: json["helpfulCount"], + verifiedPurchase: json["verifiedPurchase"], + status: json["status"], + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), + ); + + Map toJson() => { + "id": id, + "userId": userId, + "productId": productId, + "rating": rating, + "title": title, + "description": description, + "likes": likes, + "dislikes": dislikes, + "helpfulCount": helpfulCount, + "verifiedPurchase": verifiedPurchase, + "status": status, + "createdAt": createdAt, + "updatedAt": updatedAt, + }; +} + +class ProductTag { + dynamic id; + dynamic name; + dynamic description; + bool? isActive; + DateTime? createdAt; + DateTime? updatedAt; + + ProductTag({ + this.id, + this.name, + this.description, + this.isActive, + this.createdAt, + this.updatedAt, + }); + + factory ProductTag.fromJson(Map json) => ProductTag( + id: json["id"], + name: json["name"], + description: json["description"], + isActive: json["isActive"], + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), + ); + + Map toJson() => { + "id": id, + "name": name, + "description": description, + "isActive": isActive, + "createdAt": createdAt, + "updatedAt": updatedAt, }; } @@ -224,8 +677,8 @@ class Store { gstNumber: json["gstNumber"], gumastaNumber: json["gumastaNumber"], storePicture: json["storePicture"], - createdAt: DateTime.parse(json["createdAt"]), - updatedAt: DateTime.parse(json["updatedAt"]), + createdAt: DateTime?.parse(json["createdAt"]), + updatedAt: DateTime?.parse(json["updatedAt"]), vendorId: json["vendorId"], isActive: json["isActive"], couponId: json["couponId"], diff --git a/lib/src/logic/provider/addTocart_provider.dart b/lib/src/logic/provider/addTocart_provider.dart index 7209f34..3e71878 100644 --- a/lib/src/logic/provider/addTocart_provider.dart +++ b/lib/src/logic/provider/addTocart_provider.dart @@ -1,10 +1,13 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:grocery_app/src/core/network_services/service_locator.dart'; +import 'package:grocery_app/src/data/address.dart'; import 'package:grocery_app/src/data/all_cart_items.dart'; import 'package:grocery_app/src/logic/repo/product_repo.dart'; +import 'package:grocery_app/utils/extensions/extensions.dart'; import 'package:http/http.dart' as http; class AddtocartProvider extends ChangeNotifier { @@ -15,6 +18,7 @@ class AddtocartProvider extends ChangeNotifier { String get pinCode => _pinCode; bool get isLoading => _isLoading; bool get isDeliverable => _isDeliverable; + TextEditingController checkPinCode = TextEditingController(); Future getCurrentLocation(BuildContext context) async { _isLoading = true; @@ -23,16 +27,6 @@ class AddtocartProvider extends ChangeNotifier { try { bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { - _pinCode = "Location services disabled."; - _isLoading = false; - notifyListeners(); - - return; - } - - LocationPermission permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.denied) { - _pinCode = "Permission denied."; _isLoading = false; notifyListeners(); @@ -52,54 +46,58 @@ class AddtocartProvider extends ChangeNotifier { if (placemarks.isNotEmpty) { _pinCode = placemarks.first.postalCode ?? "Unknown"; + checkPinCode.text = _pinCode; print("Pincode found: $_pinCode"); // Now check if this pin code is deliverable await checkPin(context, _pinCode); } else { - _pinCode = "Could not fetch pin code."; + _pinCode = "unable to current pi code"; print("Error: No placemarks found."); } } catch (e) { - _pinCode = "Error: ${e.toString()}"; + _pinCode = "unable to current pi code"; print("Error: ${e.toString()}"); } - + _pinCode = "unable to current pi code"; _isLoading = false; notifyListeners(); } + bool ischeckpin = false; Future checkPin(BuildContext context, pin) async { + ischeckpin = true; + _pinCode = pin; + notifyListeners(); var data = {}; try { var result = await _homeRepo.checkPin(data, pin); return result.fold( (error) { + ischeckpin = false; _isDeliverable = false; isLoaddcartItem = false; notifyListeners(); }, (response) { - print("kdhfgkjfkghkfghkj ${response.isDeliverable!}"); if (response.isDeliverable!) { _isDeliverable = true; } - + ischeckpin = false; isLoaddcartItem = false; notifyListeners(); }, ); } catch (e) { + ischeckpin = false; _isDeliverable = false; isLoaddcartItem = false; notifyListeners(); } } - - - Map isRemoveItem = {}; + Map isRemoveItem = {}; Future deleteItem(BuildContext context, id) async { isRemoveItem[id] = true; @@ -109,18 +107,17 @@ class AddtocartProvider extends ChangeNotifier { var result = await _homeRepo.deleteItem(data, id); return result.fold( (error) { - isRemoveItem[id] = false; notifyListeners(); }, (response) { getItemCards(context); - isRemoveItem[id] = false; + isRemoveItem[id] = false; notifyListeners(); }, ); } catch (e) { - isRemoveItem[id] = false; + isRemoveItem[id] = false; notifyListeners(); } @@ -140,12 +137,10 @@ class AddtocartProvider extends ChangeNotifier { return result.fold( (error) { - print("dsjfgkjhkdfgdkjfhg"); isLoaddcartItem = false; notifyListeners(); }, (response) { - print("dsjfgkjhkdjsfjkdhfsgfgdkjfhg"); allitem = response!; isLoaddcartItem = false; notifyListeners(); @@ -157,4 +152,165 @@ class AddtocartProvider extends ChangeNotifier { notifyListeners(); } } + + ///////////////////////////////// address///////////////////////// + List addresslist = []; + + Future getAddress(BuildContext context) async { + var data = {}; + try { + var result = await _homeRepo.getAddress(data); + + return result.fold( + (error) { + print("dsjfgkjhkdfgdkjfhg"); + + notifyListeners(); + }, + (response) { + addresslist = response.data!; + if (response.data!.isNotEmpty) { + _selectedAddress = addresslist.last.id ?? ""; + } else { + _selectedAddress = ""; + } + + notifyListeners(); + }, + ); + } catch (e) { + print("sfddsfdfff"); + + notifyListeners(); + } + } + + String _selectedAddress = ""; + + String get selectedAddress => _selectedAddress; + + void selectAddress(String address) { + _selectedAddress = address; + notifyListeners(); + } + + Set cartItems = {}; + Map isLoadings = {}; + + bool isLoadingCart = false; + bool iscardAdded = false; + + Future addToCart( + BuildContext context, String productId, int quantity) async { + context.showLoader(show: true); + + isLoadingCart = true; + isLoadings[productId] = true; + notifyListeners(); + + var data = {"productId": productId, "quantity": quantity}; + + try { + var result = await _homeRepo.addToCart(data); + context.showLoader( + show: false, + ); + + result.fold( + (error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(error.message), + backgroundColor: Colors.red, + ), + ); + }, + (response) async { + await getItemCards(context); + cartItems.add(productId); // Add product to cart + // Fluttertoast.showToast( + // msg: "Added to cart successfully!", + // toastLength: Toast.LENGTH_SHORT, + // gravity: ToastGravity.BOTTOM, + // backgroundColor: Colors.green, + // textColor: Colors.white, + // fontSize: 14.0, + // ); + iscardAdded = true; + notifyListeners(); // Update UI after adding to cart + }, + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Something went wrong"), + backgroundColor: Colors.red, + ), + ); + } finally { + isLoadingCart = false; + isLoadings[productId] = false; + notifyListeners(); // Ensure UI updates after operation + } + } + + Future decreaseCartQuantity( + BuildContext context, String itemId, int quantity) async { + context.showLoader(show: true); + + isLoadingCart = true; + + notifyListeners(); + + // var data = {"productId": productId, "quantity": quantity}; + + final Map cartData = { + "items": [ + {"itemId": itemId, "quantity": quantity} + ] + }; + + try { + var result = await _homeRepo.decreaseQuantity(cartData); + context.showLoader( + show: false, + ); + + result.fold( + (error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(error.message), + backgroundColor: Colors.red, + ), + ); + }, + (response) async { + await getItemCards(context); + + // Fluttertoast.showToast( + // msg: "Added to cart successfully!", + // toastLength: Toast.LENGTH_SHORT, + // gravity: ToastGravity.BOTTOM, + // backgroundColor: Colors.green, + // textColor: Colors.white, + // fontSize: 14.0, + // ); + iscardAdded = true; + notifyListeners(); // Update UI after adding to cart + }, + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Something went wrong"), + backgroundColor: Colors.red, + ), + ); + } finally { + isLoadingCart = false; + + notifyListeners(); // Ensure UI updates after operation + } + } } diff --git a/lib/src/logic/provider/address_provider.dart b/lib/src/logic/provider/address_provider.dart new file mode 100644 index 0000000..abd4f73 --- /dev/null +++ b/lib/src/logic/provider/address_provider.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:grocery_app/src/core/network_services/service_locator.dart'; +import 'package:grocery_app/src/logic/repo/product_repo.dart'; + +class AddressProvider extends ChangeNotifier { + bool ischeckpin = false; + + Future checkPin(BuildContext context, pin) async { + final _homeRepo = getIt(); + ischeckpin = true; + notifyListeners(); + var data = {}; + try { + var result = await _homeRepo.checkPin(data, pin); + + return result.fold( + (error) { + ischeckpin = false; + ischeckpin = false; + return false; + }, + (response) { + ischeckpin = false; + notifyListeners(); + return true; + }, + ); + } catch (e) { + ischeckpin = false; + notifyListeners(); + return false; + } + } + + Future addAddress(BuildContext context, name, pincode, phone, + alternatePhoneNumber, address, landmark, addresstype) async { + ischeckpin = false; + + final _homeRepo = getIt(); + + notifyListeners(); + var data = { + "name": name, + "pincode": pincode, + "phoneNumber": "+91$phone", + "alternatePhoneNumber": "+91$alternatePhoneNumber", + "addressLine": address, + "landmark": landmark, + "addressType": addresstype, + "isDefault": false, + "additionalInstructions": "Please ring doorbell twice" + }; + try { + var result = await _homeRepo.addAddress(data); + + return result.fold( + (error) { + ischeckpin = false; + + return false; + }, + (response) { + ischeckpin = false; + notifyListeners(); + return true; + }, + ); + } catch (e) { + ischeckpin = false; + notifyListeners(); + return false; + } + } +} diff --git a/lib/src/logic/provider/bottom_navbar_provider.dart b/lib/src/logic/provider/bottom_navbar_provider.dart index 082f2e5..35a4610 100644 --- a/lib/src/logic/provider/bottom_navbar_provider.dart +++ b/lib/src/logic/provider/bottom_navbar_provider.dart @@ -1,4 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:grocery_app/src/core/network_services/service_locator.dart'; +import 'package:grocery_app/src/data/user_profile.dart'; +import 'package:grocery_app/src/logic/repo/product_repo.dart'; +import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; class BottomNavProvider with ChangeNotifier { int _currentIndex = 0; @@ -7,10 +11,58 @@ class BottomNavProvider with ChangeNotifier { int get currentIndex => _currentIndex; PageController get pageController => _pageController; - void setIndex(int index) - { + void setIndex(int index) { _currentIndex = index; _pageController.jumpToPage(index); notifyListeners(); } + + UserProfile allitem = UserProfile(); + final _homeRepo = getIt(); + bool isLoading = true; + + Future getProfile(BuildContext context) async { + print("kjdkjghdfjglhjdfhgldflghjkldfjgh"); + isLoading = true; + notifyListeners(); + var data = {}; + try { + var result = await _homeRepo.getProfile(data); + + return result.fold( + (error) { + isLoading = false; + notifyListeners(); + }, + (response) async { + print("kjdshgkjhdfkjg ${response.firstName}"); + + await SharedPrefUtils.saveUser(user: response); + allitem = response!; + isLoading = false; + notifyListeners(); + }, + ); + } catch (e) { + isLoading = false; + notifyListeners(); + } + } + + Future refreshToken(BuildContext context) async { + var data = {"refresh_token": "${await SharedPrefUtils.getRefreshToken()}"}; + + + var result = await _homeRepo.refreshToken(data, context); + return result.fold( + (error) { + + return true; + }, + (response) { + + return true; + }, + ); + } } diff --git a/lib/src/logic/provider/home_provider.dart b/lib/src/logic/provider/home_provider.dart index 8f7b689..a57ba9c 100644 --- a/lib/src/logic/provider/home_provider.dart +++ b/lib/src/logic/provider/home_provider.dart @@ -46,6 +46,8 @@ class ProductProvider extends ChangeNotifier { var data = {}; productDetails = ProductDetailsData(); isProductLoading = true; + quantitys = 1; + _totalPrice = 0.0; notifyListeners(); var result = await _homeRepo.getProductDetails(data, context, id); @@ -186,8 +188,6 @@ class ProductProvider extends ChangeNotifier { // Mock API call Future addToWish(BuildContext context, String productId) async { - print("jsdkjfhkdfkg ${productId}"); - var data = { "productId": productId, }; @@ -206,6 +206,7 @@ class ProductProvider extends ChangeNotifier { return false; }, (response) { + iswishloading = false; Fluttertoast.showToast( msg: "Wishlist updated successfully!", toastLength: Toast.LENGTH_SHORT, @@ -223,18 +224,24 @@ class ProductProvider extends ChangeNotifier { } } - Set wishlist = {}; // To store product IDs in the wishlist + Set wishlist = {}; + + bool iswishloading = false; Future toggleWishlist(BuildContext context, String productId) async { + iswishloading = true; + notifyListeners(); try { if (wishlist.contains(productId)) { wishlist.remove(productId); + iswishloading = false; } else { var result = await addToWish(context, productId); - wishlist.add(productId); // Add the product ID to the wishlist + wishlist.add(productId); } - notifyListeners(); // Notify listeners to update the UI + iswishloading = false; + notifyListeners(); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -297,13 +304,16 @@ class ProductProvider extends ChangeNotifier { Set cartItems = {}; Map isLoading = {}; - Future addToCart(BuildContext context, String productId) async { - //if (cartItems.contains(productId)) return; // Prevent duplicate additions + bool isLoadingCart=false; + bool iscardAdded=false; + Future addToCart(BuildContext context, String productId,int quantity) async { + //if (cartItems.contains(productId)) return; // Prevent duplicate additions +isLoadingCart=true; isLoading[productId] = true; notifyListeners(); // Notify UI to show loading indicator - var data = {"productId": productId, "quantity": 1}; + var data = {"productId": productId, "quantity": quantity}; try { var result = await _homeRepo.addToCart(data); @@ -327,6 +337,7 @@ class ProductProvider extends ChangeNotifier { textColor: Colors.white, fontSize: 14.0, ); + iscardAdded=true; notifyListeners(); // Update UI after adding to cart }, ); @@ -338,19 +349,20 @@ class ProductProvider extends ChangeNotifier { ), ); } finally { + isLoadingCart=false; isLoading[productId] = false; notifyListeners(); // Ensure UI updates after operation } } List countList = []; + String lastImageurl = ''; - Future addToWithCart( - BuildContext context, String productId, BestDeal bestdealproduct) async { - //if (cartItems.contains(productId)) return; // Prevent duplicate additions - + Future addToWithCart(BuildContext context, String productId, + BestDeal bestdealproduct, url) async { + isLoading[productId] = true; - notifyListeners(); // Notify UI to show loading indicator + notifyListeners(); var data = {"productId": productId, "quantity": 1}; @@ -368,6 +380,7 @@ class ProductProvider extends ChangeNotifier { }, (response) { countList.add(bestdealproduct); + lastImageurl = url; cartItems.add(productId); // Add product to cart Fluttertoast.showToast( msg: "Added to cart successfully!", @@ -393,6 +406,63 @@ class ProductProvider extends ChangeNotifier { } } + + List productDatum = []; + String productDatumlastImageurl = ''; + + Future addToCartWithWishlist(BuildContext context, String productId,ProductDatum productdataum, + url) async { + + isLoading[productId] = true; + notifyListeners(); + + var data = {"productId": productId, "quantity": 1}; + + try { + var result = await _homeRepo.addToCart(data); + + result.fold( + (error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(error.message), + backgroundColor: Colors.red, + ), + ); + }, + (response) { + productDatum.add(productdataum); + productDatumlastImageurl = url; + cartItems.add(productId); // Add product to cart + Fluttertoast.showToast( + msg: "Added to cart successfully!", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.green, + textColor: Colors.white, + fontSize: 14.0, + ); + notifyListeners(); // Update UI after adding to cart + }, + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Something went wrong"), + backgroundColor: Colors.red, + ), + ); + } finally { + isLoading[productId] = false; + notifyListeners(); // Ensure UI updates after operation + } + } + + + + + + bool isWishListItemLoadingg = true; List wishListItem = []; @@ -427,30 +497,69 @@ class ProductProvider extends ChangeNotifier { } ////////////////////////////// product increase //////////////////////////////////// - int _quantity = 1; + int quantitys = 1; double _unitPrice = 0.0; double _totalPrice = 0.0; - int get quantity => _quantity; + int get quantity => quantitys; double get totalPrice => _totalPrice; void setProductPrice(double price) { _unitPrice = price; - _totalPrice = _unitPrice * _quantity; + _totalPrice = _unitPrice * quantitys; notifyListeners(); } + int productQuantity = 0; + + // void increaseQuantity() + // { + // if(quantity<10) + // if (_quantity < 10) + // { + // // Limit to 10 + // _quantity++; + // _totalPrice = _unitPrice * _quantity; + // notifyListeners(); + // } + // { + // Fluttertoast.showToast( + // msg: "Sorry cart successfully!", + // toastLength: Toast.LENGTH_SHORT, + // gravity: ToastGravity.BOTTOM, + // backgroundColor: Colors.green, + // textColor: Colors.white, + // fontSize: 14.0, + // ); + + // } + // } + void increaseQuantity() { - print("kjfgkhkdfhgkjdhfg"); - _quantity++; - _totalPrice = _unitPrice * _quantity; - notifyListeners(); + int maxAllowed = productQuantity >= 100 + ? 10 + : productQuantity; // Max limit based on stock + + if (quantitys < maxAllowed) { + quantitys++; + _totalPrice = _unitPrice * quantitys; + notifyListeners(); + } else { + Fluttertoast.showToast( + msg: "Sorry, you can only add up to $maxAllowed items!", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 14.0, + ); + } } void decreaseQuantity() { - if (_quantity > 1) { - _quantity--; - _totalPrice = _unitPrice * _quantity; + if (quantitys > 1) { + quantitys--; + _totalPrice = _unitPrice * quantitys; notifyListeners(); } } diff --git a/lib/src/logic/provider/profile_provider.dart b/lib/src/logic/provider/profile_provider.dart new file mode 100644 index 0000000..5de433a --- /dev/null +++ b/lib/src/logic/provider/profile_provider.dart @@ -0,0 +1,94 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:grocery_app/src/core/network_services/service_locator.dart'; +import 'package:grocery_app/src/core/utils/snack_bar.dart'; +import 'package:grocery_app/src/data/user_profile.dart'; +import 'package:grocery_app/src/logic/repo/auth_repo.dart'; +import 'package:grocery_app/src/logic/repo/product_repo.dart'; +import 'package:grocery_app/utils/extensions/extensions.dart'; + +class ProfileProvider extends ChangeNotifier { + bool _isImageLoading = false; + bool get isImageLoading => _isImageLoading; + + String _uploadedUrl = ''; + + final _productRepo = getIt(); + + Future uploadImage(BuildContext context, File? _selectedImage) async { + context.showLoader(show: true); + _isImageLoading = false; + final result = await _productRepo.uploadImage(_selectedImage!); + context.showLoader(show: false); + + return result.fold( + (error) { + _showSnackBar(context, error.message, Colors.red); + return false; + }, + (uploadImage) { + _isImageLoading = true; + _uploadedUrl = uploadImage.data!.url.toString(); + notifyListeners(); + + _showSnackBar(context, "Image uploaxded successfully!", Colors.green); + return true; + }, + ); + } + + void _showSnackBar(BuildContext context, String message, Color color) { + showTopSnackBar(context, message, color); + } + + Future createStore( + BuildContext context, String firstName, String lastName) async { + context.showLoader(show: true); + + var data = { + "firstName": firstName, + "lastName": lastName, + "img": _uploadedUrl + }; + + try { + var result = await _productRepo.updateProfile(data); + + context.showLoader(show: false); + + return result.fold( + (error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(error.message), + backgroundColor: Colors.red, + ), + ); + return false; + }, + (response) { + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Profile updated"), + backgroundColor: Colors.green, + ), + ); + return true; + }, + ); + } catch (e) + { + context.showLoader(show: false); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text("Something went wrong. Please try again."), + backgroundColor: Colors.red, + ), + ); + return false; + } + } +} diff --git a/lib/src/logic/repo/auth_repo.dart b/lib/src/logic/repo/auth_repo.dart index 2439ad9..4efb1ad 100644 --- a/lib/src/logic/repo/auth_repo.dart +++ b/lib/src/logic/repo/auth_repo.dart @@ -7,6 +7,7 @@ import 'package:grocery_app/src/core/utils/response_type_def.dart'; import 'package:grocery_app/src/data/OTPResponseModel.dart'; import 'package:grocery_app/src/data/login_response.dart'; import 'package:grocery_app/src/data/registration_response.dart'; +import 'package:grocery_app/src/data/user_profile.dart'; import 'package:grocery_app/src/data/vendor_otpModel.dart'; import 'package:grocery_app/src/logic/services/auth_service_locator.dart'; import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; @@ -20,7 +21,6 @@ class AuthRepo { try { var response = await _authServices.sendOtp(data); final String model = response.toString(); - return right(model); } on DioException catch (e) { @@ -40,10 +40,10 @@ class AuthRepo { if (vendorOtpModel.data != null) { await SharedPrefUtils.setToken( authToken: vendorOtpModel.data!.accessToken ?? ""); + await SharedPrefUtils.setRefreshToken( + refresh_token: vendorOtpModel.data!.refreshToken ?? ""); } - - return right(vendorOtpModel); } on DioException catch (e) { var error = CustomDioExceptions.handleError(e); @@ -51,16 +51,17 @@ class AuthRepo { } } - FutureResult loginOtp(data) async { + FutureResult loginOtp(data) async { try { var response = await _authServices.loginOtp(data); LoginResponse loginResponse = loginResponseFromJson(response.toString()); - if (loginResponse.accessToken != null) - { + if (loginResponse.accessToken != null) { await SharedPrefUtils.setToken( authToken: loginResponse.accessToken ?? ""); + await SharedPrefUtils.setRefreshToken( + refresh_token: loginResponse.refreshToken ?? ""); } // final String model = response.toString(); @@ -119,12 +120,9 @@ class AuthRepo { await SharedPrefUtils.setToken( authToken: registrationResponse.accessToken ?? ""); - print("dsfklgjkfgbfgkfdgjkhkfdjg ${registrationResponse.accessToken}"); - // if (response.statCode) { - // print("dsfklgjkfgbfgkfdgjkhkfdjg"); - // } - - final String model = response.toString(); + await SharedPrefUtils.setRefreshToken( + refresh_token: registrationResponse.refreshToken ?? ""); + final String model = response.toString(); return right(registrationResponse); } on DioException catch (e) { var error = CustomDioExceptions.handleError(e); diff --git a/lib/src/logic/repo/product_repo.dart b/lib/src/logic/repo/product_repo.dart index b7f2c20..8de14d2 100644 --- a/lib/src/logic/repo/product_repo.dart +++ b/lib/src/logic/repo/product_repo.dart @@ -1,18 +1,27 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:fpdart/fpdart.dart'; +import 'package:grocery_app/src/core/routes/routes.dart'; import 'package:grocery_app/src/core/utils/custom_dio_exception.dart'; import 'package:grocery_app/src/core/utils/response_type_def.dart'; +import 'package:grocery_app/src/data/address.dart'; import 'package:grocery_app/src/data/allProduct_model.dart'; import 'package:grocery_app/src/data/all_cart_items.dart'; import 'package:grocery_app/src/data/banners.dart'; import 'package:grocery_app/src/data/best_dealProduct.dart'; import 'package:grocery_app/src/data/check_pin_response.dart'; +import 'package:grocery_app/src/data/login_response.dart'; import 'package:grocery_app/src/data/product_category.dart'; import 'package:grocery_app/src/data/product_details.dart'; +import 'package:grocery_app/src/data/upload_image.dart'; +import 'package:grocery_app/src/data/user_profile.dart'; import 'package:grocery_app/src/data/wish_list_model.dart'; import 'package:grocery_app/src/logic/services/home_locator.dart'; import 'package:grocery_app/src/ui/productdetails/product_details.dart'; +import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; +import 'package:grocery_app/utils/extensions/extensions.dart'; class ProductRepo { final ProductService _productService; @@ -36,12 +45,13 @@ class ProductRepo { } } - FutureResult getProductDetails( + FutureResult getProductDetails( data, BuildContext context, id) async { try { var response = await _productService.getProductDetails(data, id); - ProductDetailsData loginResponse = productDetailsdataFromJson(response.toString()); + ProductDetailsData loginResponse = + productDetailsdataFromJson(response.toString()); final String model = response.toString(); @@ -52,8 +62,6 @@ class ProductRepo { } } - - FutureResult getBestDealProduct( data, BuildContext context) async { try { @@ -112,8 +120,19 @@ class ProductRepo { var response = await _productService.getItemCards(data); AllCartItems allCartItems = allCartItemsFromJson(response.toString()); + return right(allCartItems); + } on DioException catch (e) { + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } - print("jdfgjkdf${allCartItems}"); + FutureResult getAddress(data) async { + try { + var response = await _productService.getAddress(data); + + AddressResponse allCartItems = + addressResponseFromJson(response.toString()); return right(allCartItems); } on DioException catch (e) { @@ -123,6 +142,47 @@ class ProductRepo { } } + FutureResult getProfile(data) async { + try { + var response = await _productService.getProfile(data); + + print("kdjfgkljfdkjlghflkgjh ${response}"); + UserProfile userProfile = userProfileFromJson(response.toString()); + print("kdjfgkljfdkjlghflkgjhrerrrerr ${userProfile.createdAt}"); + return right(userProfile); + } on DioException catch (e) { + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } +FutureResult updateProfile(data) async { + try { + var response = await _productService.updateProfile(data); + + print("kdjfgkljfdkjlghflkgjh ${response}"); + final String model = response.toString(); + return right(model); + } on DioException catch (e) { + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } + + + + FutureResult uploadImage(File imageFile) + async { + try { + final response = await _productService.uploadImage(imageFile); + UploadImage upload=uploadImageFromJson(response.toString()); + return right(upload); + } on DioException catch (e) { + final error = CustomDioExceptions.handleError(e); + return left(error); + } + } + + FutureResult checkPin(data, pin) async { try { var response = await _productService.checkPin(data, pin); @@ -148,6 +208,20 @@ class ProductRepo { } } + FutureResult addAddress(data) async { + try { + var response = await _productService.addAddress(data); + + final String model = response.toString(); + + return right(model); + } on DioException catch (e) { + print("djhgfjdfhjg ${e}"); + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } + FutureResult addToWish(data) async { try { var response = await _productService.addToWish(data); @@ -175,6 +249,22 @@ class ProductRepo { return left(error); } } +FutureResult decreaseQuantity(data) async { + try { + var response = await _productService.decreaseQuantity(data); + + final String model = response.toString(); + + return right(model); + } on DioException catch (e) { + print("djhgfjdfhjg ${e}"); + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } + + + FutureResult gettAllWishList(data) async { try { @@ -221,6 +311,32 @@ class ProductRepo { } } + FutureResult refreshToken(data, BuildContext context) async { + try { + var response = await _productService.refresh_token(data); + LoginResponse loginResponse = loginResponseFromJson(response.toString()); + + if (loginResponse.accessToken != null) + { + + await SharedPrefUtils.setToken( + authToken: loginResponse.accessToken ?? ""); + await SharedPrefUtils.setRefreshToken( + refresh_token: loginResponse.refreshToken ?? ""); + } + + final String model = response.toString(); + + return right(model); + } on DioException catch (e) + { + + + var error = CustomDioExceptions.handleError(e); + return left(error); + } + } + // FutureResult getMe(data) async { // try { // var response = await _homeService.getMe(data); diff --git a/lib/src/logic/services/auth_service_locator.dart b/lib/src/logic/services/auth_service_locator.dart index 54614ce..6889a19 100644 --- a/lib/src/logic/services/auth_service_locator.dart +++ b/lib/src/logic/services/auth_service_locator.dart @@ -1,82 +1,58 @@ - import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:grocery_app/src/core/constant/api.dart'; import 'package:grocery_app/src/core/network_services/api_services.dart'; - - class AuthServices extends ApiService { /// Login - Future sendOtp(data) async - { + Future sendOtp(data) async { var response = await api.post(APIURL.sendOtp, data: jsonEncode(data)); return response; } - - - - - Future verifyOtp(data) async { + Future verifyOtp(data) async { var response = await api.post(APIURL.verifyOtp, data: jsonEncode(data)); return response; } - Future loginOtp(data) async { + + Future loginOtp(data) async { var response = await api.post(APIURL.loginOtp, data: jsonEncode(data)); return response; } - - Future login(data) async - { + Future login(data) async { var response = await api.post(APIURL.login, data: jsonEncode(data)); //response.statusCode - - return response; - } - - - - - Future userRegister(data) async - { - var response = await api.post(APIURL.customerRegister, data: jsonEncode(data)); - return response; - } - - - - - Future forgetPassword(data) async - { - var response = await api.post(APIURL.forgetPassword, data: jsonEncode(data)); - return response; - } - - Future verifyForgetPassword(data) async - { - var response = await api.post(APIURL.verifyForgetPassword, data: jsonEncode(data)); - return response; - } - - - Future reset_password(data) async - { - var response = await api.post(APIURL.reset_password, data: jsonEncode(data)); return response; } + Future userRegister(data) async { + var response = + await api.post(APIURL.customerRegister, data: jsonEncode(data)); + return response; + } - + Future forgetPassword(data) async { + var response = + await api.post(APIURL.forgetPassword, data: jsonEncode(data)); + return response; + } + Future verifyForgetPassword(data) async { + var response = + await api.post(APIURL.verifyForgetPassword, data: jsonEncode(data)); + return response; + } - - + Future reset_password(data) async { + var response = + await api.post(APIURL.reset_password, data: jsonEncode(data)); + return response; + } /// Login // Future profileUpdate(data) async { diff --git a/lib/src/logic/services/home_locator.dart b/lib/src/logic/services/home_locator.dart index d88c6d0..38abea6 100644 --- a/lib/src/logic/services/home_locator.dart +++ b/lib/src/logic/services/home_locator.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'dart:io'; +import 'package:dio/dio.dart'; import 'package:grocery_app/src/core/constant/api.dart'; import 'package:grocery_app/src/core/network_services/api_services.dart'; @@ -76,7 +78,39 @@ class ProductService extends ApiService { await api.delete(APIURL.deleteItem + id, data: jsonEncode(data)); return response; } + Future addAddress(data) async { + var response = await api.post(APIURL.addAddress, data: jsonEncode(data)); + return response; + } + + Future getProfile(data) async { + var response = await api.get(APIURL.getprofile, data: jsonEncode(data)); + return response; + } + Future updateProfile(data) async { + var response = await api.patch(APIURL.updateProfile, data: jsonEncode(data)); + return response; + } + + + Future uploadImage(File imageFile, + {Map? additionalFields}) async { + const String url = APIURL.uploadImage; + return await api.uploadImage( + url, + imageFile, + additionalFields: additionalFields, + ); + } + + + Future getAddress + (data) async { + var response = + await api.get(APIURL.userAddress, data: jsonEncode(data)); + return response; + } Future addToWish(data) async { var response = await api.post(APIURL.addToWish, data: jsonEncode(data)); @@ -89,6 +123,12 @@ class ProductService extends ApiService { return response; } + Future decreaseQuantity(data) async { + var response = await api.patch(APIURL.addToCart, data: jsonEncode(data)); + + return response; + } + Future gettAllWishList(data) async { var response = await api.get(APIURL.gettAllWishList, data: jsonEncode(data)); diff --git a/lib/src/ui/bestdeal/bestdeal_screen.dart b/lib/src/ui/bestdeal/bestdeal_screen.dart index fd33ae1..d55dbb0 100644 --- a/lib/src/ui/bestdeal/bestdeal_screen.dart +++ b/lib/src/ui/bestdeal/bestdeal_screen.dart @@ -62,14 +62,21 @@ class _BestDealScreenState extends State { ], ), floatingActionButton: floatingAction(), - body: itemBestdeal()); + body: Padding( + padding: const EdgeInsets.only(bottom: 100), + child: itemBestdeal(), + )); } - Widget floatingAction() { - return Consumer(builder: (context, provider, child) { - if (provider.countList.isEmpty) { + Widget floatingAction() + { + return Consumer(builder: (context, provider, child) + { + if (provider.countList.isEmpty) + { return Center(); - } else { + } else + { return Padding( padding: const EdgeInsets.only(left: 30), child: Container( @@ -93,7 +100,7 @@ class _BestDealScreenState extends State { color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(10)), ), - const Positioned( + Positioned( left: 20, bottom: 0, top: 0, @@ -102,7 +109,7 @@ class _BestDealScreenState extends State { height: 70, width: 70, radius: 10, - imageUrl: + imageUrl: provider.lastImageurl ?? "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", backGroundColor: Colors.white, ), @@ -113,15 +120,12 @@ class _BestDealScreenState extends State { const SizedBox( width: 10, ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - provider.countList.length.toString(), - style: context.customRegular(Colors.white, 18), - ), - ], + Text( + provider.countList.length.toString(), + style: context.customRegular( + Colors.white, + 29, + ), ), const Spacer(), InkWell( @@ -306,8 +310,12 @@ class _BestDealScreenState extends State { onTap: () async { if (await SharedPrefUtils.getToken() != null) { - await provider.addToWithCart(context, - bestdealproduct.id!, bestdealproduct); + await provider.addToWithCart( + context, + bestdealproduct.id!, + bestdealproduct, + bestdealproduct + .productImages?.first.url); } else { context.push(MyRoutes.SIGNUP); } diff --git a/lib/src/ui/bottomnavigation/bottom_bar_widget.dart b/lib/src/ui/bottomnavigation/bottom_bar_widget.dart index 3debc83..d3b9b35 100644 --- a/lib/src/ui/bottomnavigation/bottom_bar_widget.dart +++ b/lib/src/ui/bottomnavigation/bottom_bar_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; +import 'package:grocery_app/src/logic/provider/home_provider.dart'; import 'package:grocery_app/src/ui/cart/cartview_screen.dart'; import 'package:grocery_app/src/ui/favourite/favourite_screen.dart'; import 'package:grocery_app/src/ui/header.dart'; @@ -38,6 +39,7 @@ class _BottomBarState extends State { @override void initState() { + Provider.of(context, listen: false).getProfile(context); _currentIndex = 0; bottomWidgetPageController = PageController( initialPage: 0, diff --git a/lib/src/ui/cart/cartview_screen.dart b/lib/src/ui/cart/cartview_screen.dart index 8566b20..51e7127 100644 --- a/lib/src/ui/cart/cartview_screen.dart +++ b/lib/src/ui/cart/cartview_screen.dart @@ -3,10 +3,14 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; import 'package:grocery_app/src/common_widget/network_image.dart'; import 'package:grocery_app/src/common_widget/textfield_widget.dart'; +import 'package:grocery_app/src/core/routes/routes.dart'; import 'package:grocery_app/src/logic/provider/addTocart_provider.dart'; +import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; import 'package:grocery_app/src/logic/provider/home_provider.dart'; import 'package:grocery_app/src/ui/bestdeal/bestdeal_screen.dart'; @@ -14,11 +18,13 @@ import 'package:grocery_app/src/ui/widgets/custom_icon_button.dart'; import 'package:grocery_app/src/ui/widgets/elevated_button.dart'; import 'package:grocery_app/utils/constants/assets_constant.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; +import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; import 'package:grocery_app/utils/constants/string_constant.dart'; import 'package:grocery_app/utils/extensions/extensions.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class Mycart extends StatefulWidget { const Mycart({super.key}); @@ -35,6 +41,7 @@ class _MycartState extends State { Provider.of(context, listen: false) .getCurrentLocation(context); + Provider.of(context, listen: false).getAddress(context); super.initState(); } @@ -84,151 +91,346 @@ class _MycartState extends State { } Widget relatedProduct() { - return SizedBox( - height: 222, - child: ListView.builder( - itemCount: 5, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), - child: Container( - height: 215, - width: 150, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.1), - blurRadius: 1, - offset: const Offset(5, 5), + return Consumer(builder: (context, provider, child) { + if (provider.isBestdealingloading) { + return Center(child: CircularProgressIndicator()); + } else if (provider.bestdeal.isEmpty) { + return Center(child: Text('No products available')); + } else { + return SizedBox( + height: MediaQuery.of(context).size.height * 0.28, + child: ListView.builder( + itemCount: provider.bestdeal.length, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + var bestdealproduct = provider.bestdeal[index]; + double cardWidth = + MediaQuery.of(context).size.width * 0.4; // Dynamic width + + return InkWell( + onTap: () { + context.push(MyRoutes.PRODUCTDETAILS, + extra: bestdealproduct.id); + }, + child: Padding( + padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), + child: Container( + width: cardWidth, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + blurRadius: 1, + offset: const Offset(5, 5), + ), + ], ), - ]), - child: Padding( - padding: const EdgeInsets.all(5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 100, - width: 150, - decoration: BoxDecoration( - color: APPCOLOR.bgGrey, - borderRadius: BorderRadius.circular(15)), - child: const Stack( - alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - AppNetworkImage( - height: 70, - width: 70, - imageUrl: - "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", - backGroundColor: Colors.transparent), - Positioned( - right: 5, - top: 5, - child: Icon(Icons.favorite_border)) + Center( + child: Container( + height: MediaQuery.of(context).size.height * 0.12, + width: cardWidth * 0.9, + decoration: BoxDecoration( + color: APPCOLOR.bgGrey, + borderRadius: BorderRadius.circular(15), + ), + child: Stack( + alignment: Alignment.center, + children: [ + AppNetworkImage( + height: MediaQuery.of(context).size.height * + 0.08, + width: cardWidth * 0.7, + imageUrl: bestdealproduct + .productImages?.first?.url ?? + "", + backGroundColor: Colors.transparent, + ), + // Positioned( + // right: 5, + // top: 5, + // child: InkWell( + // onTap: () async { + // if (await SharedPrefUtils.getToken() != + // null) { + // provider.toggleWishlist( + // context, bestdealproduct.id!); + // } else { + // context.push(MyRoutes.LOGIN); + // } + // }, + // child: Icon( + // provider.wishlist + // .contains(bestdealproduct.id) + // ? Icons.favorite + // : Icons.favorite_border, + // color: provider.wishlist + // .contains(bestdealproduct.id) + // ? Colors.red + // : Colors.grey, + // ), + // ), + // ), + ], + ), + ), + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.01, + ), + Text( + bestdealproduct.name ?? "", + textAlign: TextAlign.left, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: + context.customMedium(APPCOLOR.balck1A1A1A, 14), + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.005, + ), + Text( + bestdealproduct.unit ?? "", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context.customMedium( + Colors.grey.withOpacity(0.8), + 12, + ), + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.005, + ), + const Spacer(), + Row( + children: [ + Row( + children: [ + Text( + "\$${bestdealproduct.discountPrice ?? ""} ", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context.customSemiBold( + Colors.black, 12), + ), + Text( + "\$${bestdealproduct.basePrice ?? ""}", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context + .customMedium( + Colors.grey.withOpacity(0.8), + 12, + ) + .copyWith( + decoration: + TextDecoration.lineThrough, + ), + ), + ], + ), + const Spacer(), + Align( + alignment: Alignment.centerRight, + child: GestureDetector( + onTap: () async { + if (await SharedPrefUtils.getToken() != + null) { + await provider.addToCart( + context, bestdealproduct.id!, 1); + + context + .read() + .getItemCards(context); + } else { + context.push(MyRoutes.SIGNUP); + } + }, + child: Container( + height: MediaQuery.of(context).size.height * + 0.035, + width: + MediaQuery.of(context).size.width * 0.1, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + borderRadius: BorderRadius.circular(5), + ), + child: Center( + child: provider.isLoading[ + bestdealproduct.id] ?? + false + ? Padding( + padding: + const EdgeInsets.all(8.0), + child: Container( + height: 10, + width: 10, + child: + CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2), + ), + ) + : Text( + 'Add', + style: context.customRegular( + Colors.white, 12), + ), + ), + ), + ), + ), + ], + ), ], ), ), - Text( - "Fortune Arhar Dal (Toor Dal)", - textAlign: TextAlign.left, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: context.customMedium(APPCOLOR.balck1A1A1A, 14), - ), - const SizedBox( - height: 5, - ), - Text( - "500 ML", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context.customMedium( - Colors.grey.withOpacity(0.8), 12), - ), - const SizedBox( - height: 3, - ), - Row( - children: [ - Expanded( - child: Row( - children: [ - Text( - "\$12", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context.customSemiBold(Colors.black, 12), - ), - const SizedBox( - width: 5, - ), - Text( - "\$14", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context - .customMedium( - Colors.grey.withOpacity(0.8), 12) - .copyWith( - decoration: TextDecoration.lineThrough, - ), - ), - ], - )), - Expanded( - child: Align( - alignment: Alignment.centerRight, - child: Container( - height: 30, - width: 50, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(5), - ), - child: Center( - child: Text( - 'Add', - style: context.customRegular(Colors.white, 12), - )), - ), - ), - ) - ], - ), - ], + ), ), - ), - ), - ); - }, - ), - ); + ); + }, + ), + ); + } + }); + } + + double calculateDiscountPercentage(double basePrice, double discountPrice) { + print( + "Base Price (Before Discount): $basePrice, Discount Price (After Discount): $discountPrice"); + + if (basePrice <= 0 || discountPrice <= 0 || discountPrice > basePrice) { + print("Error: Invalid price values."); + return 0; + } + + double discountAmount = basePrice - discountPrice; + double discountPercentage = (discountAmount / basePrice) * 100; + + return discountPercentage; } Widget cartItems() { return Consumer(builder: (context, provider, child) { if (provider.isLoaddcartItem) { - return Center( - child: CircularProgressIndicator( - color: Colors.green, + return Skeletonizer( + enabled: provider.isLoaddcartItem, + child: ListView.separated( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + separatorBuilder: (_, index) => Padding( + padding: EdgeInsets.only(top: 12.h, bottom: 24.h), + child: const Divider(thickness: 1), + ), + itemCount: 3, // Display 3 skeleton items + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 60.w, + height: 70.h, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(10), + ), + ), + 16.horizontalSpace, + Container( + width: 150.w, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 120.w, + height: 14.h, + color: Colors.grey[300], + ), + 5.verticalSpace, + Container( + width: 80.w, + height: 14.h, + color: Colors.grey[300], + ), + 5.verticalSpace, + Row( + children: [ + Container( + width: 40.w, + height: 14.h, + color: Colors.grey[300], + ), + 10.horizontalSpace, + Container( + width: 40.w, + height: 14.h, + color: Colors.grey[300], + ), + ], + ), + ], + ), + ), + const Spacer(), + Column( + children: [ + Row( + children: [ + Container( + width: 14.w, + height: 14.h, + color: Colors.grey[300], + ), + 5.horizontalSpace, + Container( + width: 14.w, + height: 14.h, + color: Colors.grey[300], + ), + 5.horizontalSpace, + Container( + width: 14.w, + height: 14.h, + color: Colors.grey[300], + ), + ], + ), + Gap(20), + Container( + height: 25, + width: 70, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10)), + color: Colors.grey[300], + ), + ), + ], + ) + ], + ), + ); + }, ), ); - } else if (provider.allitem == null) { - return Center(child: Text('🛒 Your Front Shop Cart is empty')); - } else if (provider.allitem.items == null || + } else if (provider.allitem == null || + provider.allitem.items == null || provider.allitem.items!.isEmpty) { return Center(child: Text('🛒 Your Front Shop Cart is empty')); } else { return ListView.separated( - shrinkWrap: true, // Prevents internal scrolling - physics: NeverScrollableScrollPhysics(), // Disables inner scroll + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), separatorBuilder: (_, index) => Padding( padding: EdgeInsets.only(top: 12.h, bottom: 24.h), child: const Divider(thickness: 1), @@ -255,14 +457,11 @@ class _MycartState extends State { radius: 10, ), ), - // Image.asset(product.image, width: 50.w, height: 40.h), - 16.horizontalSpace, Container( width: 150.w, child: Column( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, children: [ Text( items.product!.name ?? "", @@ -298,13 +497,25 @@ class _MycartState extends State { decoration: TextDecoration.lineThrough, ), ), + SizedBox(width: 10), + Container( + // padding: EdgeInsets.symmetric( + // horizontal: 6, vertical: 2), + // decoration: BoxDecoration( + // color: Colors.green, + // borderRadius: BorderRadius.circular(5), + // ), + child: Text( + "${calculateDiscountPercentage(double.parse(items.product!.basePrice.toString()), double.parse(items.product!.discountPrice.toString()))}%off", + style: TextStyle( + color: Colors.lightGreen, fontSize: 12)), + ), ], ), ], ), ), const Spacer(), - Column( children: [ Row( @@ -312,8 +523,13 @@ class _MycartState extends State { CustomIconButton( width: 14.w, height: 14.h, - onPressed: () { - // provider.decreaseQuantity(items); + onPressed: () async { + if (items.quantity! > 1) { + await provider.decreaseCartQuantity( + context, + items.id!, + int.parse(items.quantity.toString()) - 1); + } }, icon: SvgPicture.asset( APPASSETS.removeIcon, @@ -331,8 +547,11 @@ class _MycartState extends State { CustomIconButton( width: 14.w, height: 14.h, - onPressed: () { - // provider..increaseQuantity(items); + onPressed: () async { + await provider.addToCart( + context, items.productId!, 1); + + // await provider.getItemCards(context); }, icon: SvgPicture.asset( APPASSETS.addIcon, @@ -344,7 +563,7 @@ class _MycartState extends State { ), Gap(20), InkWell( - onTap: () { + onTap: () async { provider.deleteItem(context, items.id); }, child: Container( @@ -354,9 +573,8 @@ class _MycartState extends State { borderRadius: BorderRadius.all(Radius.circular(10)), shape: BoxShape.rectangle, border: Border.all( - color: Colors - .blue, // Replace with your desired border color - width: 2, // Border width + color: Colors.blue, + width: 2, ), ), child: provider.isRemoveItem[items.id] ?? false @@ -378,17 +596,315 @@ class _MycartState extends State { ) ], ), - ).animate(delay: (100 * index).ms).fade().slideX( - duration: 300.ms, - begin: -1, - curve: Curves.easeInSine, - ); + ); }, ); } }); } + // Widget relatedProduct() { + // return SizedBox( + // height: 222, + // child: ListView.builder( + // itemCount: 5, + // scrollDirection: Axis.horizontal, + // itemBuilder: (context, index) { + // return Padding( + // padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), + // child: Container( + // height: 215, + // width: 150, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(15), + // boxShadow: [ + // BoxShadow( + // color: Colors.grey.withOpacity(0.1), + // blurRadius: 1, + // offset: const Offset(5, 5), + // ), + // ]), + // child: Padding( + // padding: const EdgeInsets.all(5), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Container( + // height: 100, + // width: 150, + // decoration: BoxDecoration( + // color: APPCOLOR.bgGrey, + // borderRadius: BorderRadius.circular(15)), + // child: const Stack( + // alignment: Alignment.center, + // children: [ + // AppNetworkImage( + // height: 70, + // width: 70, + // imageUrl: + // "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", + // backGroundColor: Colors.transparent), + // Positioned( + // right: 5, + // top: 5, + // child: Icon(Icons.favorite_border)) + // ], + // ), + // ), + // Text( + // "Fortune Arhar Dal (Toor Dal)", + // textAlign: TextAlign.left, + // maxLines: 2, + // overflow: TextOverflow.ellipsis, + // style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ), + // const SizedBox( + // height: 5, + // ), + // Text( + // "500 ML", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context.customMedium( + // Colors.grey.withOpacity(0.8), 12), + // ), + // const SizedBox( + // height: 3, + // ), + // Row( + // children: [ + // Expanded( + // child: Row( + // children: [ + // Text( + // "\$12", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context.customSemiBold(Colors.black, 12), + // ), + // const SizedBox( + // width: 5, + // ), + // Text( + // "\$14", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context + // .customMedium( + // Colors.grey.withOpacity(0.8), 12) + // .copyWith( + // decoration: TextDecoration.lineThrough, + // ), + // ), + // ], + // )), + // Expanded( + // child: Align( + // alignment: Alignment.centerRight, + // child: Container( + // height: 30, + // width: 50, + // decoration: BoxDecoration( + // color: APPCOLOR.lightGreen, + // borderRadius: BorderRadius.circular(5), + // ), + // child: Center( + // child: Text( + // 'Add', + // style: context.customRegular(Colors.white, 12), + // )), + // ), + // ), + // ) + // ], + // ), + // ], + // ), + // ), + // ), + // ); + // }, + // ), + // ); + // } + + // Widget cartItems() { + // return Consumer(builder: (context, provider, child) { + // if (provider.isLoaddcartItem) { + // return Center( + // child: CircularProgressIndicator( + // color: Colors.green, + // ), + // ); + // } else if (provider.allitem == null) { + // return Center(child: Text('🛒 Your Front Shop Cart is empty')); + // } else if (provider.allitem.items == null || + // provider.allitem.items!.isEmpty) { + // return Center(child: Text('🛒 Your Front Shop Cart is empty')); + // } else { + // return ListView.separated( + // shrinkWrap: true, // Prevents internal scrolling + // physics: NeverScrollableScrollPhysics(), // Disables inner scroll + // separatorBuilder: (_, index) => Padding( + // padding: EdgeInsets.only(top: 12.h, bottom: 24.h), + // child: const Divider(thickness: 1), + // ), + // itemCount: provider.allitem.items!.length, + // itemBuilder: (context, index) { + // var items = provider.allitem.items![index]; + + // return Padding( + // padding: EdgeInsets.symmetric(horizontal: 10.w), + // child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Container( + // decoration: BoxDecoration( + // color: Colors.greenAccent.withOpacity(0.1), + // borderRadius: BorderRadius.circular(5), + // ), + // child: AppNetworkImage( + // width: 60.w, + // height: 70.h, + // imageUrl: items.product!.productImages!.first.url ?? " ", + // backGroundColor: APPCOLOR.bgGrey, + // radius: 10, + // ), + // ), + // // Image.asset(product.image, width: 50.w, height: 40.h), + + // 16.horizontalSpace, + // Container( + // width: 150.w, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Text( + // items.product!.name ?? "", + // maxLines: 2, + // overflow: TextOverflow.ellipsis, + // style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ), + // 5.verticalSpace, + // Text( + // items.product!.unit ?? "", + // style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ), + // Row( + // children: [ + // Text( + // "\$${items.product!.discountPrice ?? ""} ", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context.customSemiBold(Colors.black, 12), + // ), + // Text( + // "\$${items.product!.basePrice ?? ""}", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context + // .customMedium( + // Colors.grey.withOpacity(0.8), + // 12, + // ) + // .copyWith( + // decoration: TextDecoration.lineThrough, + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // const Spacer(), + + // Column( + // children: [ + // Row( + // children: [ + // CustomIconButton( + // width: 14.w, + // height: 14.h, + // onPressed: () { + // // provider.decreaseQuantity(items); + // }, + // icon: SvgPicture.asset( + // APPASSETS.removeIcon, + // fit: BoxFit.none, + // ), + // backgroundColor: APPCOLOR.appGreen, + // ), + // 5.horizontalSpace, + // Text( + // items.quantity.toString(), + // style: + // context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ), + // 5.horizontalSpace, + // CustomIconButton( + // width: 14.w, + // height: 14.h, + // onPressed: () { + // // provider..increaseQuantity(items); + // }, + // icon: SvgPicture.asset( + // APPASSETS.addIcon, + // fit: BoxFit.none, + // ), + // backgroundColor: APPCOLOR.appGreen, + // ), + // ], + // ), + // Gap(20), + // InkWell( + // onTap: () { + // provider.deleteItem(context, items.id); + // }, + // child: Container( + // height: 25, + // width: 70, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.all(Radius.circular(10)), + // shape: BoxShape.rectangle, + // border: Border.all( + // color: Colors + // .blue, // Replace with your desired border color + // width: 2, // Border width + // ), + // ), + // child: provider.isRemoveItem[items.id] ?? false + // ? Center( + // child: Padding( + // padding: const EdgeInsets.all(8.0), + // child: Container( + // height: 5, + // width: 5, + // child: CircularProgressIndicator( + // color: Colors.green, strokeWidth: 1), + // ), + // ), + // ) + // : Center(child: Text("Delete")), + // ), + // ) + // ], + // ) + // ], + // ), + // ); + // }, + // ); + // } + // }); + // } + Widget cartPlace() { return Consumer(builder: (context, provider, child) { print("jdhfgkdfkjg ${provider.allitem.createdAt}"); @@ -405,7 +921,9 @@ class _MycartState extends State { return Center( child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.green), - onPressed: () {}, + onPressed: () { + context.read().setIndex(0); + }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -423,13 +941,20 @@ class _MycartState extends State { title: Text('APPLY COUPON', style: TextStyle(fontWeight: FontWeight.bold)), trailing: Icon(Icons.arrow_forward_ios), - onTap: () {}, + onTap: () { + context.push(MyRoutes.COUPONSSCREEN); + }, ), - SummaryRow(label: 'Item Total', value: '\$22'), - SummaryRow(label: 'Discount', value: '\$2'), + SummaryRow( + label: 'Item Total Price', + value: '\$${provider.allitem.subtotal}'), + SummaryRow(label: 'Discount', value: '0.0'), SummaryRow(label: 'Delivery Free', value: 'Free', isGreen: true), Divider(), - SummaryRow(label: 'Grand Total', value: '\$22', isBold: true), + SummaryRow( + label: 'Grand Total', + value: '\$${provider.allitem.subtotal}', + isBold: true), ListTile( leading: Icon(Icons.home, color: Colors.green), title: provider.isDeliverable @@ -445,12 +970,27 @@ class _MycartState extends State { ), SizedBox(height: 10), ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: Colors.green), - onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: APPCOLOR.lightGreen), + onPressed: () { + if (provider.isDeliverable) { + _showAddressBottomSheet(context); + } else { + Fluttertoast.showToast( + msg: + "Delivery is not available for this pincode. Please try another pincode!", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 14.0, + ); + } + }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('\$22 Place Order', style: TextStyle(fontSize: 16)) + Text('\$22 Place Order', style: TextStyle(fontSize: 16)) ], ), ), @@ -461,8 +1001,6 @@ class _MycartState extends State { } void _showBottomSheet(BuildContext context) { - TextEditingController checkPinCode = TextEditingController(); - showModalBottomSheet( context: context, builder: (BuildContext context) { @@ -492,10 +1030,13 @@ class _MycartState extends State { child: Container( height: 20.h, child: TextFormField( - controller: checkPinCode, + controller: pinProvider.checkPinCode, + maxLength: 6, keyboardType: TextInputType.phone, + onChanged: (value) {}, decoration: InputDecoration( hintText: 'Enter PIN', + counterText: "", border: InputBorder .none, // Remove the inner border ), @@ -513,30 +1054,41 @@ class _MycartState extends State { ), InkWell( onTap: () { - pinProvider.checkPin(context, checkPinCode.text); + pinProvider.checkPin( + context, pinProvider.checkPinCode.text); }, child: Expanded( flex: 1, - child: Text( - "Check PIN", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: Colors.black), - )), + child: pinProvider.ischeckpin + ? Center( + child: CircularProgressIndicator( + color: APPCOLOR.lightGreen, + ), + ) + : Text( + "Check PIN", + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: Colors.black), + )), ), ], ), ), ), ), - - Gap(10.h), - // if (!pinProvider.isMatch) - Text( - 'pin code invoild', - style: TextStyle(color: Colors.red), - ), + if (!pinProvider.isDeliverable) ...{ + Text( + 'Delivery is not available for this pincode. Please try another pincode.', + style: TextStyle(color: Colors.red, fontSize: 10), + ), + } else ...{ + Text( + 'Delivery available for this pincode. Submit now.', + style: TextStyle(color: Colors.lightGreen, fontSize: 10), + ), + }, Gap(10.h), Center( child: SizedBox( @@ -544,7 +1096,9 @@ class _MycartState extends State { width: double.infinity, child: ButtonElevated( text: 'Submit', - onPressed: () {}, + onPressed: () { + Navigator.pop(context); + }, backgroundColor: APPCOLOR.appGreen), ), ), @@ -556,6 +1110,139 @@ class _MycartState extends State { }, ); } + + void _showAddressBottomSheet(BuildContext context) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + isDismissible: false, // Allows tap outside to close + enableDrag: true, // Enables swipe-down to dismiss + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + ), + + builder: (context) { + return AddressBottomSheet(); + }, + ); + } +} + +class AddressBottomSheet extends StatefulWidget { + @override + _AddressBottomSheetState createState() => _AddressBottomSheetState(); +} + +class _AddressBottomSheetState extends State { + // String selectedAddress = "Home"; + + @override + Widget build(BuildContext context) { + return Padding( + padding: + EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + child: Container( + padding: EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Select an Address", + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + IconButton( + icon: Icon(Icons.close), + onPressed: () => Navigator.pop(context), + ), + ], + ), + SizedBox(height: 10), + _buildAddressTile(context), + SizedBox(height: 16), + ElevatedButton.icon( + onPressed: () { + context.push(MyRoutes.ADDRESSS); + }, + icon: Icon(Icons.add, color: Colors.white), + label: Text( + "Add New Address", + style: TextStyle(color: Colors.white, fontSize: 15), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + minimumSize: Size(double.infinity, 50), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + ), + ), + SizedBox(height: 16), + ElevatedButton.icon( + onPressed: () {}, + label: Text( + "Continue", + style: TextStyle(color: Colors.white, fontSize: 16), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + minimumSize: Size(double.infinity, 50), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + ), + ), + SizedBox(height: 10), + ], + ), + ), + ); + } + + Widget _buildAddressTile(BuildContext context) { + return Consumer( + builder: (context, addressProvider, child) { + return addressProvider.addresslist.isEmpty + ? SizedBox.shrink() + : ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: addressProvider.addresslist.length, + itemBuilder: (context, index) { + var address = addressProvider.addresslist[index]; + + return Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + child: ListTile( + leading: Radio( + value: address.id ?? "", + groupValue: addressProvider + .selectedAddress, // Use provider's value + activeColor: Colors.green, + onChanged: (value) { + addressProvider.selectAddress(value.toString()); + }, + ), + title: Text( + address.addressType ?? "", + style: TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text(address.addressLine + + " " + + address.landmark + + " " + + address.city ?? + ""), + ), + ); + }, + ); + }, + ); + } } class SummaryRow extends StatelessWidget { diff --git a/lib/src/ui/coupons/coupons_screen.dart b/lib/src/ui/coupons/coupons_screen.dart new file mode 100644 index 0000000..5dd39ce --- /dev/null +++ b/lib/src/ui/coupons/coupons_screen.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; + +class CouponsScreen extends StatelessWidget { + final List> coupons = [ + { + "title": "Flat 10% OFF on Standard Chartered Digismart Credit Cards", + "description": "No Minimum Order Value", + "code": "DIGISMART" + }, + { + "title": "Flat 10% OFF upto \$10 on HSBC Cashback Credit Card", + "description": "Total Value of Items Must be \$3 or More", + "code": "HSBC10" + }, + { + "title": "Get Upto 50 OFF on Your First Payment", + "description": "Total Value of Items Must be \$10 or More", + "code": "PAYMENT50" + } + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + title: Text("Coupons"), + leading: IconButton( + icon: Icon(Icons.arrow_back_ios), + onPressed: () => Navigator.pop(context), + ), + ), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + children: [ + TextField( + cursorHeight: 20, + decoration: InputDecoration( + hintText: "Enter Coupon Code", + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + suffixIcon: Padding( + padding: const EdgeInsets.all(8.0), + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Text("Apply"), + ), + ), + ), + ), + SizedBox(height: 16), + Expanded( + child: ListView.builder( + itemCount: coupons.length, + itemBuilder: (context, index) { + final coupon = coupons[index]; + return Card( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 2, + child: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + coupon["title"]!, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 5), + Text( + coupon["description"]!, + style: TextStyle(color: Colors.grey[600]), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + decoration: BoxDecoration( + border: Border.all(color: Colors.green), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + coupon["code"]!, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.green, + ), + ), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Text("Apply"), + ) + ], + ) + ], + ), + ), + ); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/src/ui/edit_profile/edit_profile_screen.dart b/lib/src/ui/edit_profile/edit_profile_screen.dart index 49dae6f..96b90c5 100644 --- a/lib/src/ui/edit_profile/edit_profile_screen.dart +++ b/lib/src/ui/edit_profile/edit_profile_screen.dart @@ -1,11 +1,19 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:grocery_app/src/common_widget/name_text_field.dart'; import 'package:grocery_app/src/common_widget/network_image.dart'; +import 'package:grocery_app/src/logic/provider/profile_provider.dart'; import 'package:grocery_app/utils/constants/assets_constant.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; +import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; +import 'package:grocery_app/utils/constants/string_constant.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class EditProfileScreen extends StatefulWidget { const EditProfileScreen({super.key}); @@ -15,6 +23,51 @@ class EditProfileScreen extends StatefulWidget { } class _EditProfileScreenState extends State { + String? name; + String? email; + String? profile; + File? _image; + final ImagePicker _picker = ImagePicker(); + + TextEditingController firstController = TextEditingController(); + TextEditingController lastController = TextEditingController(); + + @override + void initState() { + getUserDetails(); + // TODO: implement initState + super.initState(); + } + + getUserDetails() async { + firstController.text = APPSTRING.userName; + lastController.text = APPSTRING.userLastName; + profile = APPSTRING.userProfile; + } + + /// Pick image from gallery or camera + Future _pickImage() async { + final XFile? pickedFile = + await _picker.pickImage(source: ImageSource.gallery); + + if (pickedFile != null) { + setState(() { + profile = pickedFile.path; + _image = File(pickedFile.path); + }); + + Provider.of(context, listen: false) + .uploadImage(context, _image); + + await _saveProfileImage(pickedFile.path); + } + } + + Future _saveProfileImage(String imagePath) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('KEY_PROFILE', imagePath); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -43,40 +96,50 @@ class _EditProfileScreenState extends State { ), ), ), - bottomNavigationBar: Container( - color: Colors.transparent, - height: 60, - child: Padding( - padding: const EdgeInsets.only(bottom: 10), - child: Row( - children: [ - const SizedBox( - width: 15, - ), - Expanded( - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - height: 50, - decoration: BoxDecoration(color: APPCOLOR.lightGreen, borderRadius: BorderRadius.circular(10)), - child: Center( - child: Text( - "Update", - style: context.customRegular(Colors.white, 16), + bottomNavigationBar: + Consumer(builder: (context, imageProvider, child) { + return Container( + color: Colors.transparent, + height: 60, + child: Padding( + padding: const EdgeInsets.only(bottom: 10), + child: Row( + children: [ + const SizedBox( + width: 15, + ), + Expanded( + child: InkWell( + onTap: imageProvider.isImageLoading + ? () { + imageProvider.createStore(context, + firstController.text, lastController.text); + } + : null, + child: Container( + height: 50, + decoration: BoxDecoration( + color: imageProvider.isImageLoading + ? APPCOLOR.lightGreen + : APPCOLOR.grey666666, + borderRadius: BorderRadius.circular(10)), + child: Center( + child: Text( + "Update", + style: context.customRegular(Colors.white, 16), + ), ), ), ), ), - ), - const SizedBox( - width: 15, - ), - ], + const SizedBox( + width: 15, + ), + ], + ), ), - ), - ), + ); + }), body: Padding( padding: context.bodyAllPadding, child: SingleChildScrollView( @@ -90,26 +153,37 @@ class _EditProfileScreenState extends State { Stack( alignment: Alignment.center, children: [ - const AppNetworkImage( - height: 80, - width: 80, - imageUrl: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTdQLwDqDwd2JfzifvfBTFT8I7iKFFevcedYg&s", - radius: 90, - backGroundColor: Colors.white, - boxFit: BoxFit.fill, + // + CircleAvatar( + radius: 40, + backgroundColor: Colors.white, + backgroundImage: _image != null + ? FileImage(_image!) as ImageProvider + : (profile != null && profile!.isNotEmpty + ? NetworkImage(profile!) + : const AssetImage("assets/default_profile.png") + as ImageProvider), ), Positioned( bottom: 0, right: 0, - child: Container( - height: 20, - width: 20, - decoration: BoxDecoration(color: APPCOLOR.lightGreen, border: Border.all(color: Colors.white), borderRadius: BorderRadius.circular(5)), - child: Center( - child: Icon( - MdiIcons.pencil, - size: 10, - color: Colors.white, + child: GestureDetector( + onTap: () { + _pickImage(); + }, + child: Container( + height: 20, + width: 20, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + border: Border.all(color: Colors.white), + borderRadius: BorderRadius.circular(5)), + child: Center( + child: Icon( + MdiIcons.pencil, + size: 10, + color: Colors.white, + ), ), ), )), @@ -120,34 +194,103 @@ class _EditProfileScreenState extends State { const SizedBox( height: 15, ), - const NameTextField( - name: "Name", - initText: "Smith Mate", + Container( + height: 60, + width: MediaQuery.sizeOf(context).width, + decoration: BoxDecoration( + border: Border.all(color: APPCOLOR.lightGreen), + borderRadius: BorderRadius.circular(15)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "First Name", + style: context.customMedium(APPCOLOR.lightGreen, 14), + ), + Expanded( + child: TextFormField( + controller: firstController, + decoration: const InputDecoration( + border: InputBorder.none, + isCollapsed: true, + contentPadding: EdgeInsets.only( + left: 0, + right: 0, + bottom: 5, + top: 5, + )), + )) + ], + ), + ), ), const SizedBox( height: 10, ), - const NameTextField( - name: "Email Address", - initText: "SmithMate@example.com", - ), - const SizedBox( - height: 10, - ), - const NameTextField( - name: "Mobile Number", - initText: "(205) 555-0100", - ), - const SizedBox( - height: 10, - ), - const NameTextField( - name: "Enter Address", - initText: "8502 Preston Rd. inglewood, USA", - ), - const SizedBox( - height: 10, + Container( + height: 60, + width: MediaQuery.sizeOf(context).width, + decoration: BoxDecoration( + border: Border.all(color: APPCOLOR.lightGreen), + borderRadius: BorderRadius.circular(15)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Last Name ", + style: context.customMedium(APPCOLOR.lightGreen, 14), + ), + Expanded( + child: TextFormField( + controller: lastController, + decoration: const InputDecoration( + border: InputBorder.none, + isCollapsed: true, + contentPadding: EdgeInsets.only( + left: 0, + right: 0, + bottom: 5, + top: 5, + )), + )) + ], + ), + ), ), + // const NameTextField( + // name: "Last Name", + // initText: "Smith Mate", + // ), + // const SizedBox( + // height: 10, + // ), + // const NameTextField( + // name: "Email Address", + // initText: "SmithMate@example.com", + // ), + // const SizedBox( + // height: 10, + // ), + // const NameTextField( + // name: "Mobile Number", + // initText: "(205) 555-0100", + // ), + // const SizedBox( + // height: 10, + // ), + // const NameTextField( + // name: "Enter Address", + // initText: "8502 Preston Rd. inglewood, USA", + // ), + // const SizedBox( + // height: 10, + // ), ], )), ), diff --git a/lib/src/ui/favourite/favourite_screen.dart b/lib/src/ui/favourite/favourite_screen.dart index 7abcab0..5c4bf65 100644 --- a/lib/src/ui/favourite/favourite_screen.dart +++ b/lib/src/ui/favourite/favourite_screen.dart @@ -1,12 +1,331 @@ +// import 'package:flutter/material.dart'; +// import 'package:go_router/go_router.dart'; +// import 'package:grocery_app/src/common_widget/network_image.dart'; +// import 'package:grocery_app/src/core/routes/routes.dart'; +// import 'package:grocery_app/src/data/best_dealProduct.dart'; +// import 'package:grocery_app/src/data/product_model.dart'; +// import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; +// import 'package:grocery_app/src/logic/provider/home_provider.dart'; +// import 'package:grocery_app/src/ui/header.dart'; +// import 'package:grocery_app/src/ui/widgets/custom_title.dart'; +// import 'package:grocery_app/utils/constants/color_constant.dart'; +// import 'package:grocery_app/utils/extensions/uicontext.dart'; +// import 'package:provider/provider.dart'; + +// class FavouriteScreen extends StatefulWidget { +// @override +// _FavouriteScreenState createState() => _FavouriteScreenState(); +// } + +// class _FavouriteScreenState extends State +// with SingleTickerProviderStateMixin { +// late AnimationController _animationController; +// late Animation _animation; + +// @override +// void initState() { +// Provider.of(context, listen: false) +// .gettAllWishList(context); +// _animationController = AnimationController( +// duration: const Duration(milliseconds: 1000), +// vsync: this, +// ); + +// super.initState(); +// } + +// @override +// void dispose() { +// _animationController.dispose(); +// super.dispose(); +// } + +// @override +// Widget build(BuildContext context) { +// return SafeArea( +// child: Scaffold( +// body: Padding( +// padding: context.bodyAllPadding.copyWith( +// top: 0, +// ), +// child: Column( +// children: [ +// Header(), +// itemList(), +// Consumer( +// builder: (context, wishListProvider, _) { +// if (wishListProvider.productDatum.isEmpty) { +// return SizedBox.shrink(); +// } else { +// return Padding( +// padding: const EdgeInsets.only(), +// child: Container( +// height: 80, +// width: MediaQuery.sizeOf(context).width, +// decoration: BoxDecoration( +// color: APPCOLOR.lightGreen, +// borderRadius: BorderRadius.circular(15)), +// child: Padding( +// padding: const EdgeInsets.all(10), +// child: Row( +// children: [ +// SizedBox( +// width: 80, +// child: Stack( +// children: [ +// Container( +// height: 70, +// width: 70, +// decoration: BoxDecoration( +// color: Colors.white.withOpacity(0.5), +// borderRadius: +// BorderRadius.circular(10)), +// ), +// Positioned( +// left: 20, +// bottom: 0, +// top: 0, +// right: 0, +// child: AppNetworkImage( +// height: 70, +// width: 70, +// radius: 10, +// imageUrl: wishListProvider +// .productDatumlastImageurl ?? +// "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", +// backGroundColor: Colors.white, +// ), +// ), +// ], +// ), +// ), +// const SizedBox( +// width: 10, +// ), +// Text( +// wishListProvider.productDatum.length.toString() ?? +// "", +// style: context.customRegular(Colors.white, 18), +// ), +// const Spacer(), +// InkWell( +// onTap: () { +// context.read().setIndex(2); +// }, +// child: Row( +// children: [ +// Text( +// 'View Cart', +// style: +// context.customMedium(Colors.white, 24), +// ), +// const SizedBox( +// width: 10, +// ), +// const Icon( +// Icons.arrow_forward, +// color: Colors.white, +// size: 35, +// ), +// ], +// ), +// ) +// ], +// ), +// ), +// ), +// ); +// } +// }), +// ], +// ), +// ), +// ), +// ); +// } + +// Widget itemList() { +// return Consumer(builder: (context, provider, child) { +// if (provider.isWishListItemLoadingg) { +// return Expanded(child: Center(child: CircularProgressIndicator())); +// } else if (provider.wishListItem.isEmpty) { +// return Expanded(child: Center(child: Text('No products available'))); +// } else { +// return Expanded( +// child: ListView.separated( +// itemCount: provider.wishListItem.length, +// shrinkWrap: true, +// padding: const EdgeInsets.all(16), +// itemBuilder: (_, index) { +// final item = provider.wishListItem[index]; +// final product = item.product!; +// final productId = product.id!; + +// final animation = Tween(begin: 0.0, end: 1.0).animate( +// CurvedAnimation( +// parent: _animationController, +// curve: Interval( +// (0.5 / provider.wishListItem.length) * index, +// 1, +// curve: Curves.easeOut, +// ), +// ), +// ); + +// _animationController.forward(from: 0); + +// return GestureDetector( +// onTap: () { +// context.push(MyRoutes.PRODUCTDETAILS, extra: productId); +// }, +// child: Container( +// padding: EdgeInsets.all(8), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(10), +// boxShadow: [ +// BoxShadow( +// color: Colors.grey.withOpacity(0.1), +// blurRadius: 5, +// offset: Offset(2, 2), +// ), +// ], +// ), +// child: Row( +// crossAxisAlignment: CrossAxisAlignment.center, +// children: [ +// Flexible( +// flex: 3, +// child: Container( +// height: 100, +// width: 100, +// decoration: BoxDecoration( +// borderRadius: BorderRadius.circular(10), +// color: APPCOLOR.bgGrey, +// ), +// child: ClipRRect( +// borderRadius: BorderRadius.circular(10), +// child: AppNetworkImage( +// imageUrl: item +// .product!.productImages!.first.url ?? +// "https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png", +// backGroundColor: APPCOLOR.bgGrey, +// height: 20, +// width: 20, +// ), +// ), +// ), +// ), +// Flexible( +// flex: 4, +// child: Padding( +// padding: const EdgeInsets.only(left: 10), +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// mainAxisAlignment: MainAxisAlignment.start, +// children: [ +// Text( +// product.name ?? "", + +// style: context.customMedium( +// APPCOLOR.balck1A1A1A, 14), +// //textAlign: TextAlign.center, +// maxLines: 2, +// overflow: TextOverflow.ellipsis, +// ), + +// Row( +// mainAxisAlignment: MainAxisAlignment.start, +// children: [ +// Text( +// "\$${product.discountPrice}", +// style: context.customSemiBold( +// Colors.black, 14), +// ), +// SizedBox(width: 5), +// Text( +// "\$${product.basePrice ?? ""}", +// style: context +// .customMedium( +// Colors.grey.withOpacity(0.8), 12) +// .copyWith( +// decoration: +// TextDecoration.lineThrough, +// ), +// ), +// ], +// ), +// SizedBox(height: 10), +// // Add to Cart Button +// ], +// ), +// ), +// ), +// Spacer(), +// Align( +// alignment: Alignment.centerRight, +// child: GestureDetector( +// onTap: () async { +// print("Add to Cart Pressed for ${product.id}"); + +// await provider.addToCartWithWishlist( +// context, +// product.id!, +// product, +// product.productImages![index].url); +// }, +// child: Container( +// height: MediaQuery.of(context).size.height * 0.035, +// width: MediaQuery.of(context).size.width * 0.1, +// decoration: BoxDecoration( +// color: APPCOLOR.lightGreen, +// borderRadius: BorderRadius.circular(5), +// ), +// child: Center( +// child: provider.isLoading[product.id] ?? false +// ? Padding( +// padding: const EdgeInsets.all(8.0), +// child: Container( +// height: 10, +// width: 10, +// child: CircularProgressIndicator( +// color: Colors.white, +// strokeWidth: 2), +// ), +// ) +// : Text( +// 'Add', +// style: context.customRegular( +// Colors.white, 12), +// ), +// ), +// ), +// ), +// ), +// ], +// ), +// ), +// ); +// }, +// separatorBuilder: (_, __) => Divider(), +// ), +// ); +// } +// }); +// } +// } import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:grocery_app/src/common_widget/network_image.dart'; -import 'package:grocery_app/src/data/product_model.dart'; +import 'package:grocery_app/src/core/routes/routes.dart'; +import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; import 'package:grocery_app/src/logic/provider/home_provider.dart'; import 'package:grocery_app/src/ui/header.dart'; -import 'package:grocery_app/src/ui/widgets/custom_title.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; import 'package:provider/provider.dart'; +// import 'package:shimmer/shimmer.dart'; +// Import Shimmer class FavouriteScreen extends StatefulWidget { @override @@ -16,13 +335,6 @@ class FavouriteScreen extends StatefulWidget { class _FavouriteScreenState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; - late Animation _animation; - - // List _favProducts = [ - // ProductModel("", 'Bell pepper red', '7pcs', '\$4.99'), - // ProductModel("", 'Ginger', '1kg', '\$4.99'), - // ProductModel("", 'Egg pasta', '30gm', '\$15.9'), - // ]; @override void initState() { @@ -46,186 +358,12 @@ class _FavouriteScreenState extends State Widget build(BuildContext context) { return SafeArea( child: Scaffold( - // floatingActionButton: Padding( - // padding: const EdgeInsets.only(left: 30), - // child: Container( - // height: 80, - // width: MediaQuery.sizeOf(context).width, - // decoration: BoxDecoration( - // color: APPCOLOR.lightGreen, - // borderRadius: BorderRadius.circular(15)), - // child: Padding( - // padding: const EdgeInsets.all(10), - // child: Row( - // children: [ - // SizedBox( - // width: 80, - // child: Stack( - // children: [ - // Container( - // height: 70, - // width: 70, - // decoration: BoxDecoration( - // color: Colors.white.withOpacity(0.5), - // borderRadius: BorderRadius.circular(10)), - // ), - // const Positioned( - // left: 20, - // bottom: 0, - // top: 0, - // right: 0, - // child: AppNetworkImage( - // height: 70, - // width: 70, - // radius: 10, - // imageUrl: - // "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", - // backGroundColor: Colors.white, - // ), - // ), - // ], - // ), - // ), - // const SizedBox( - // width: 10, - // ), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Text( - // '2 Items', - // style: context.customRegular(Colors.white, 18), - // ), - // Text( - // '\$25', - // style: context.customExtraBold(Colors.white, 20), - // ) - // ], - // ), - // const Spacer(), - // Text( - // 'View Cart', - // style: context.customMedium(Colors.white, 24), - // ), - // const SizedBox( - // width: 10, - // ), - // const Icon( - // Icons.arrow_forward, - // color: Colors.white, - // size: 35, - // ), - // ], - // ), - // ), - // ), - // ), - body: Padding( - padding: context.bodyAllPadding.copyWith( - top: 0, - ), + padding: context.bodyAllPadding.copyWith(top: 0), child: Column( children: [ Header(), - itemList(), - - Consumer( - builder: (context, wishListProvider, _) { - return wishListProvider.totalItems > 0 - ? Padding( - padding: const EdgeInsets.only(), - child: Container( - height: 80, - width: MediaQuery.sizeOf(context).width, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(15)), - child: Padding( - padding: const EdgeInsets.all(10), - child: Row( - children: [ - SizedBox( - width: 80, - child: Stack( - children: [ - Container( - height: 70, - width: 70, - decoration: BoxDecoration( - color: - Colors.white.withOpacity(0.5), - borderRadius: - BorderRadius.circular(10)), - ), - const Positioned( - left: 20, - bottom: 0, - top: 0, - right: 0, - child: AppNetworkImage( - height: 70, - width: 70, - radius: 10, - imageUrl: - "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", - backGroundColor: Colors.white, - ), - ), - ], - ), - ), - const SizedBox( - width: 10, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - '2 Items', - style: context.customRegular( - Colors.white, 18), - ), - Text( - '\$25', - style: context.customExtraBold( - Colors.white, 20), - ) - ], - ), - const Spacer(), - Text( - 'View Cart', - style: context.customMedium(Colors.white, 24), - ), - const SizedBox( - width: 10, - ), - const Icon( - Icons.arrow_forward, - color: Colors.white, - size: 35, - ), - ], - ), - ), - ), - ) - : SizedBox.shrink(); - }), - - // Padding( - // padding: - // const EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 78), - // child: NectarButton( - // onPressed: () {}, - // text: 'Add All To Cart', - // ), - // ), ], ), ), @@ -235,10 +373,9 @@ class _FavouriteScreenState extends State Widget itemList() { return Consumer(builder: (context, provider, child) { - print( - "sdhfgkj ${provider.wishListItem.length} ${provider.isWishListItemLoadingg}"); if (provider.isWishListItemLoadingg) { - return Expanded(child: Center(child: CircularProgressIndicator())); + return Expanded( + child: _buildSkeletonLoader()); // Show Skeleton while loading } else if (provider.wishListItem.isEmpty) { return Expanded(child: Center(child: Text('No products available'))); } else { @@ -252,290 +389,195 @@ class _FavouriteScreenState extends State final product = item.product!; final productId = product.id!; - final animation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _animationController, - curve: Interval( - (0.5 / provider.wishListItem.length) * index, - 1, - curve: Curves.easeOut, - ), - ), - ); - _animationController.forward(from: 0); - return Container( - padding: EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.1), - blurRadius: 5, - offset: Offset(2, 2), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Flexible( - flex: 3, - child: Container( - height: 100, - width: 100, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: APPCOLOR.bgGrey, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: AppNetworkImage( - imageUrl: - "https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png", - backGroundColor: APPCOLOR.bgGrey, - height: 20, - width: 20, + return GestureDetector( + onTap: () { + context.push(MyRoutes.PRODUCTDETAILS, extra: productId); + }, + child: Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + blurRadius: 5, + offset: Offset(2, 2), + ), + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + flex: 3, + child: Container( + height: 100, + width: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: APPCOLOR.bgGrey, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: AppNetworkImage( + imageUrl: item + .product!.productImages!.first.url ?? + "https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png", + backGroundColor: APPCOLOR.bgGrey, + height: 20, + width: 20, + ), ), ), ), - ), - Flexible( - flex: 4, - child: Padding( - padding: const EdgeInsets.only(left: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - product.name ?? "", + Flexible( + flex: 4, + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + product.name ?? "", + style: context.customMedium( + APPCOLOR.balck1A1A1A, 14), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + Row( + children: [ + Text( + "\$${product.discountPrice}", + style: context.customSemiBold( + Colors.black, 14), + ), + SizedBox(width: 5), + Text( + "\$${product.basePrice ?? ""}", + style: context + .customMedium( + Colors.grey.withOpacity(0.8), 12) + .copyWith( + decoration: + TextDecoration.lineThrough, + ), + ), + ], + ), + SizedBox(height: 10), + ], + ), + ), + ), + Spacer(), + Align( + alignment: Alignment.centerRight, + child: GestureDetector( + onTap: () async { + print("Add to Cart Pressed for ${product.id}"); - style: context.customMedium( - APPCOLOR.balck1A1A1A, 14), - //textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, + await provider.addToCartWithWishlist( + context, + product.id!, + product, + product.productImages![index].url); + }, + child: Container( + height: MediaQuery.of(context).size.height * 0.035, + width: MediaQuery.of(context).size.width * 0.1, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + borderRadius: BorderRadius.circular(5), ), - - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "\$${product.discountPrice}", - style: - context.customSemiBold(Colors.black, 14), - ), - SizedBox(width: 5), - Text( - "\$${product.basePrice ?? ""}", - style: context - .customMedium( - Colors.grey.withOpacity(0.8), 12) - .copyWith( - decoration: TextDecoration.lineThrough, + child: Center( + child: provider.isLoading[product.id] ?? false + ? Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + height: 10, + width: 10, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2), ), - ), - ], + ) + : Text( + 'Add', + style: context.customRegular( + Colors.white, 12), + ), ), - SizedBox(height: 10), - // Add to Cart Button - ], + ), ), ), - ), - Spacer(), - GestureDetector( - onTap: provider.isLoading[productId] ?? false - ? null - : () => provider.addToCart(context, productId), - child: Container( - height: 35, - width: 50, - decoration: BoxDecoration( - color: provider.cartItems.contains(productId) - ? Colors.grey - : APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(5), - ), - child: Center( - child: provider.isLoading[productId] ?? false - ? CircularProgressIndicator( - color: Colors.white, strokeWidth: 2) - : Text( - provider.cartItems.contains(productId) - ? 'Added' - : 'Add', - style: - context.customRegular(Colors.white, 14), - ), - ), - ), - ), - ], + ], + ), ), ); }, separatorBuilder: (_, __) => Divider(), ), ); - // Expanded( - // child: ListView.separated( - // itemCount: provider.wishListItem.length, - // shrinkWrap: true, - // padding: const EdgeInsets.all(16), - // itemBuilder: (_, index) { - // _animation = Tween(begin: 0.0, end: 1.0).animate( - // CurvedAnimation( - // parent: _animationController, - // curve: Interval( - // (0.5 / provider.wishListItem.length) * index, - // 1, - // curve: Curves.easeOut, - // ), - // ), - // ); - // _animationController.forward(from: 0); - // var item = provider.wishListItem[index]; - // return AnimatedBuilder( - // animation: _animationController, - // builder: (_, child) { - // return FadeTransition( - // opacity: _animation, - // child: Transform( - // transform: Matrix4.translationValues( - // 0.0, - // 50 * (1.0 - _animation.value), - // 0.0, - // ), - // child: child, - // ), - // ); - // }, - // child: ListTile( - // onTap: () {}, - // leading: Container( - // decoration: BoxDecoration( - // color: Colors.greenAccent.withOpacity(0.1), - // borderRadius: BorderRadius.circular(5), - // ), - // child: AppNetworkImage( - // height: 80, - // width: 80, - // imageUrl: - // 'https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png', - // backGroundColor: APPCOLOR.bgGrey, - // radius: 10, - // ), - // ), - // // Image.asset(_favProducts[index].productImage), - // title: Text(item.product!.name ?? ""), - // subtitle: Text(item.product!.unit ?? ""), - // trailing: Row( - // children: [ - // Column( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text("\$" + item.product!.discountPrice), - // Text( - // "\$${item.product!.basePrice ?? ""}", - // textAlign: TextAlign.left, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: context - // .customMedium( - // Colors.grey.withOpacity(0.8), - // 12, - // ) - // .copyWith( - // decoration: TextDecoration.lineThrough, - // ), - // ), - // ], - // ), - // Align( - // alignment: Alignment.centerRight, - // child: GestureDetector( - // // onTap: provider.isLoading[bestdealproduct.id] ?? - // // false - // // ? null - // // : () => provider.addToCart( - // // context, bestdealproduct.id!), - // child: Container( - // height: MediaQuery.of(context).size.height * 0.035, - // width: MediaQuery.of(context).size.width * 0.1, - // decoration: BoxDecoration( - // color: - // // provider.cartItems - // // .contains(bestdealproduct.id) - // // ? Colors.grey - // // : - // APPCOLOR.lightGreen, - // borderRadius: BorderRadius.circular(5), - // ), - // child: Center( - // child: - // // provider.isLoading[ - // // bestdealproduct.id] ?? - // // false - // // ? CircularProgressIndicator( - // // color: Colors.white, strokeWidth: 2) - // // : - - // Text( - // // provider.cartItems.contains( - // // bestdealproduct.id) - // // ? 'Added' - // // : - - // 'Add', - // style: context.customRegular(Colors.white, 12), - // ), - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // ); - // }, - // separatorBuilder: (_, index) { - // _animation = Tween(begin: 0.0, end: 1.0).animate( - // CurvedAnimation( - // parent: _animationController, - // curve: Interval( - // (0.5 / provider.wishListItem.length) * index, - // 1, - // curve: Curves.easeOut, - // ), - // ), - // ); - // _animationController.forward(from: 0); - // return AnimatedBuilder( - // animation: _animationController, - // builder: (_, child) { - // return FadeTransition( - // opacity: _animation, - // child: Transform( - // transform: Matrix4.translationValues( - // 0.0, - // 50 * (1.0 - _animation.value), - // 0.0, - // ), - // child: child, - // ), - // ); - // }, - // child: Divider(), - // ); - // }, - // ), - // ); } }); } + + Widget _buildSkeletonLoader() { + return ListView.separated( + itemCount: 6, // Show 6 skeleton items + padding: const EdgeInsets.all(16), + itemBuilder: (_, index) { + return Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + height: 100, + width: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.grey[300], + ), + ), + SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 16, + width: double.infinity, + color: Colors.grey[300], + ), + SizedBox(height: 8), + Container( + height: 16, + width: 100, + color: Colors.grey[300], + ), + SizedBox(height: 8), + Container( + height: 16, + width: 60, + color: Colors.grey[300], + ), + ], + ), + ), + ], + ), + ); + }, + separatorBuilder: (_, __) => Divider(), + ); + } } diff --git a/lib/src/ui/fruitvegidetail/fruit_veggie_detail.dart b/lib/src/ui/fruitvegidetail/fruit_veggie_detail.dart index 8a1207e..41c81b7 100644 --- a/lib/src/ui/fruitvegidetail/fruit_veggie_detail.dart +++ b/lib/src/ui/fruitvegidetail/fruit_veggie_detail.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -79,10 +80,25 @@ class _FruitVeggieDetailState extends State { Widget productWidget() { return Consumer(builder: (context, provider, child) { - if (provider.isLoadingg) { + if (provider.isLoadingg) + { return Padding( padding: const EdgeInsets.only(left: 120), - child: CircularProgressIndicator(), + child: Center( + child: Container( + width: 30, + height: 30, + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: APPCOLOR.bgGrey, + width: 1, + )), + child: const Center( + child: CupertinoActivityIndicator(), + ), + )), ); } else if (provider.products.isEmpty) { return Padding( @@ -106,8 +122,7 @@ class _FruitVeggieDetailState extends State { crossAxisSpacing: 10, mainAxisSpacing: 10, ), - itemBuilder: (context, index) - { + itemBuilder: (context, index) { var product = provider.products[index]; return InkWell( @@ -189,31 +204,31 @@ class _FruitVeggieDetailState extends State { // ), // ), - Positioned( - right: 5, - top: 5, - child: InkWell( - onTap: () async { - if (await SharedPrefUtils - .getToken() != - null) { - provider.toggleWishlist( - context, product.id!); - } else { - context.push(MyRoutes.SIGNUP); - } - }, - child: Icon( - provider.wishlist.contains(product.id) - ? Icons.favorite - : Icons.favorite_border, - color: provider.wishlist - .contains(product.id) - ? Colors.red - : Colors.grey, - ), - ), - ), + // Positioned( + // right: 5, + // top: 5, + // child: InkWell( + // onTap: () async { + // if (await SharedPrefUtils + // .getToken() != + // null) { + // provider.toggleWishlist( + // context, product.id!); + // } else { + // context.push(MyRoutes.SIGNUP); + // } + // }, + // child: Icon( + // provider.wishlist.contains(product.id) + // ? Icons.favorite + // : Icons.favorite_border, + // color: provider.wishlist + // .contains(product.id) + // ? Colors.red + // : Colors.grey, + // ), + // ), + // ), ], ), ), @@ -221,7 +236,7 @@ class _FruitVeggieDetailState extends State { Text( product.name ?? " ", textAlign: TextAlign.left, - maxLines: 2, + maxLines: 3, overflow: TextOverflow.ellipsis, style: context.customMedium( APPCOLOR.balck1A1A1A, 14), @@ -238,6 +253,7 @@ class _FruitVeggieDetailState extends State { ), ), const SizedBox(height: 3), + Spacer(), Row( children: [ Column( @@ -281,7 +297,7 @@ class _FruitVeggieDetailState extends State { if (await SharedPrefUtils.getToken() != null) { await provider.addToCart( - context, product.id!); + context, product.id!, 1); } else { context.push(MyRoutes.SIGNUP); } @@ -327,6 +343,8 @@ class _FruitVeggieDetailState extends State { ), ), ), + + ], ), ], @@ -348,7 +366,21 @@ class _FruitVeggieDetailState extends State { final activeIndexProvider = Provider.of(context); return Consumer(builder: (context, provider, child) { if (provider.iscategroyloading) { - return Center(child: CircularProgressIndicator()); + return Center( + child: Container( + width: 20, + height: 20, + decoration: BoxDecoration( + color: APPCOLOR.bgGrey, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: APPCOLOR.bgGrey, + width: 1, + )), + child: const Center( + child: CupertinoActivityIndicator(), + ), + )); } else if (provider.categoryList.isEmpty) { return Center(child: Text('No products available')); } else { diff --git a/lib/src/ui/home/home_screen.dart b/lib/src/ui/home/home_screen.dart index 718cf35..c3beeae 100644 --- a/lib/src/ui/home/home_screen.dart +++ b/lib/src/ui/home/home_screen.dart @@ -10,10 +10,13 @@ import 'package:grocery_app/src/ui/fruitvegidetail/fruit_veggie_detail.dart'; import 'package:grocery_app/src/ui/header.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; +import 'package:grocery_app/utils/constants/string_constant.dart'; import 'package:grocery_app/utils/extensions/extensions.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:provider/provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:url_launcher/url_launcher.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -34,6 +37,14 @@ class _HomeScreenState extends State { .getBestDealProduct(context); Provider.of(context, listen: false) .getAllcategory(context); + getUserDetails(); + } + + getUserDetails() async { + APPSTRING.userName = (await SharedPrefUtils.getUserName())!; + APPSTRING.emailName = (await SharedPrefUtils.getUserEmail())!; + APPSTRING.userProfile = (await SharedPrefUtils.getUserProfile())!; + APPSTRING.userLastName = (await SharedPrefUtils.getLastName())!; } @override @@ -175,379 +186,762 @@ class _HomeScreenState extends State { Widget bestDeal() { return Consumer(builder: (context, provider, child) { - if (provider.isBestdealingloading) { - return Center(child: CircularProgressIndicator()); - } else if (provider.bestdeal.isEmpty) { - return Center(child: Text('No products available')); - } else { - return SizedBox( - height: MediaQuery.of(context).size.height * 0.28, - child: ListView.builder( - itemCount: provider.bestdeal.length, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - var bestdealproduct = provider.bestdeal[index]; - double cardWidth = - MediaQuery.of(context).size.width * 0.4; // Dynamic width - - return InkWell( - onTap: () { - context.push(MyRoutes.PRODUCTDETAILS, - extra: bestdealproduct.id); - }, - child: Padding( - padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), - child: Container( - width: cardWidth, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.1), - blurRadius: 1, - offset: const Offset(5, 5), + return provider.isBestdealingloading + ? SizedBox( + height: MediaQuery.of(context).size.height * 0.28, + child: ListView.builder( + itemCount: 5, // Show 5 skeleton items + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + double cardWidth = MediaQuery.of(context).size.width * 0.4; + return Padding( + padding: + const EdgeInsets.only(right: 10, bottom: 5, top: 5), + child: Skeletonizer( + enabled: provider.isBestdealingloading, + child: Container( + width: cardWidth, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Container( - height: MediaQuery.of(context).size.height * 0.12, - width: cardWidth * 0.9, - decoration: BoxDecoration( - color: APPCOLOR.bgGrey, - borderRadius: BorderRadius.circular(15), - ), - child: Stack( - alignment: Alignment.center, - children: [ - AppNetworkImage( - height: MediaQuery.of(context).size.height * - 0.08, - width: cardWidth * 0.7, - imageUrl: bestdealproduct - .productImages?.first?.url ?? - "", - backGroundColor: Colors.transparent, - ), - // Positioned( - // right: 5, - // top: 5, - // child: InkWell( - // onTap: () async { - // if (await SharedPrefUtils.getToken() != - // null) { - // provider.toggleWishlist( - // context, bestdealproduct.id!); - // } else { - // context.push(MyRoutes.LOGIN); - // } - // }, - // child: Icon( - // provider.wishlist - // .contains(bestdealproduct.id) - // ? Icons.favorite - // : Icons.favorite_border, - // color: provider.wishlist - // .contains(bestdealproduct.id) - // ? Colors.red - // : Colors.grey, - // ), - // ), - // ), - ], - ), - ), - ), - SizedBox( - height: MediaQuery.of(context).size.height * 0.01, - ), - Text( - bestdealproduct.name ?? "", - textAlign: TextAlign.left, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: - context.customMedium(APPCOLOR.balck1A1A1A, 14), - ), - SizedBox( - height: MediaQuery.of(context).size.height * 0.005, - ), - Text( - bestdealproduct.unit ?? "", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context.customMedium( - Colors.grey.withOpacity(0.8), - 12, - ), - ), - SizedBox( - height: MediaQuery.of(context).size.height * 0.005, - ), - const Spacer(), - Row( + child: Padding( + padding: const EdgeInsets.all(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Center( + child: Container( + height: + MediaQuery.of(context).size.height * 0.12, + width: cardWidth * 0.9, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(15), + ), + ), + ), + SizedBox(height: 10), + Container( + height: 15, + width: cardWidth * 0.8, + color: Colors.grey[300], + ), + SizedBox(height: 5), + Container( + height: 12, + width: cardWidth * 0.5, + color: Colors.grey[300], + ), + SizedBox(height: 5), + const Spacer(), Row( children: [ - Text( - "\$${bestdealproduct.discountPrice ?? ""} ", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context.customSemiBold( - Colors.black, 12), + Container( + height: 12, + width: 40, + color: Colors.grey[300], ), - Text( - "\$${bestdealproduct.basePrice ?? ""}", - textAlign: TextAlign.left, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: context - .customMedium( - Colors.grey.withOpacity(0.8), - 12, - ) - .copyWith( - decoration: - TextDecoration.lineThrough, - ), + const Spacer(), + Container( + height: 25, + width: 40, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(5), + ), ), ], ), - const Spacer(), - Align( - alignment: Alignment.centerRight, + ], + ), + ), + ), + ), + ); + }, + ), + ) + : provider.bestdeal.isEmpty + ? Center(child: Text('No products available')) + : SizedBox( + height: MediaQuery.of(context).size.height * 0.28, + child: ListView.builder( + itemCount: provider.bestdeal.length, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + var bestdealproduct = provider.bestdeal[index]; + double cardWidth = + MediaQuery.of(context).size.width * 0.4; + + return InkWell( + onTap: () { + context.push(MyRoutes.PRODUCTDETAILS, + extra: bestdealproduct.id); + }, + child: Padding( + padding: const EdgeInsets.only( + right: 10, bottom: 5, top: 5), + child: Container( + width: cardWidth, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + blurRadius: 1, + offset: const Offset(5, 5), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Container( + height: + MediaQuery.of(context).size.height * + 0.12, + width: cardWidth * 0.9, + decoration: BoxDecoration( + color: APPCOLOR.bgGrey, + borderRadius: BorderRadius.circular(15), + ), + child: Stack( + alignment: Alignment.center, + children: [ + AppNetworkImage( + height: MediaQuery.of(context) + .size + .height * + 0.08, + width: cardWidth * 0.7, + imageUrl: bestdealproduct + .productImages + ?.first + ?.url ?? + "", + backGroundColor: Colors.transparent, + ), + ], + ), + ), + ), + SizedBox( + height: + MediaQuery.of(context).size.height * + 0.01), + Text( + bestdealproduct.name ?? "", + textAlign: TextAlign.left, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: context.customMedium( + APPCOLOR.balck1A1A1A, 14), + ), + SizedBox( + height: + MediaQuery.of(context).size.height * + 0.005), + Text( + bestdealproduct.unit ?? "", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context.customMedium( + Colors.grey.withOpacity(0.8), 12), + ), + SizedBox( + height: + MediaQuery.of(context).size.height * + 0.005), + const Spacer(), + Row( + children: [ + Row( + children: [ + Text( + "\$${bestdealproduct.discountPrice ?? ""} ", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context.customSemiBold( + Colors.black, 12), + ), + Text( + "\$${bestdealproduct.basePrice ?? ""}", + textAlign: TextAlign.left, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: context + .customMedium( + Colors.grey + .withOpacity(0.8), + 12) + .copyWith( + decoration: TextDecoration + .lineThrough), + ), + ], + ), + const Spacer(), + Align( + alignment: Alignment.centerRight, + child: GestureDetector( + onTap: () async { + if (await SharedPrefUtils + .getToken() != + null) { + await provider.addToCart(context, + bestdealproduct.id!, 1); + } else { + context.push(MyRoutes.SIGNUP); + } + }, + child: Container( + height: MediaQuery.of(context) + .size + .height * + 0.035, + width: MediaQuery.of(context) + .size + .width * + 0.1, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + borderRadius: + BorderRadius.circular(5), + ), + child: Center( + child: provider.isLoading[ + bestdealproduct.id] ?? + false + ? Padding( + padding: + const EdgeInsets.all( + 8.0), + child: SizedBox( + height: 10, + width: 10, + child: + CircularProgressIndicator( + color: Colors + .white, + strokeWidth: 2), + ), + ) + : Text( + 'Add', + style: + context.customRegular( + Colors.white, 12), + ), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + }, + ), + ); + }); + } + + // Widget bestDeal() { + // return Consumer(builder: (context, provider, child) { + // if (provider.isBestdealingloading) { + // return Center(child: CircularProgressIndicator()); + // } else if (provider.bestdeal.isEmpty) { + // return Center(child: Text('No products available')); + // } else { + // return SizedBox( + // height: MediaQuery.of(context).size.height * 0.28, + // child: ListView.builder( + // itemCount: provider.bestdeal.length, + // scrollDirection: Axis.horizontal, + // itemBuilder: (context, index) { + // var bestdealproduct = provider.bestdeal[index]; + // double cardWidth = + // MediaQuery.of(context).size.width * 0.4; // Dynamic width + + // return InkWell( + // onTap: () { + // context.push(MyRoutes.PRODUCTDETAILS, + // extra: bestdealproduct.id); + // }, + // child: Padding( + // padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), + // child: Container( + // width: cardWidth, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(15), + // boxShadow: [ + // BoxShadow( + // color: Colors.grey.withOpacity(0.1), + // blurRadius: 1, + // offset: const Offset(5, 5), + // ), + // ], + // ), + // child: Padding( + // padding: const EdgeInsets.all(5), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Center( + // child: Container( + // height: MediaQuery.of(context).size.height * 0.12, + // width: cardWidth * 0.9, + // decoration: BoxDecoration( + // color: APPCOLOR.bgGrey, + // borderRadius: BorderRadius.circular(15), + // ), + // child: Stack( + // alignment: Alignment.center, + // children: [ + // AppNetworkImage( + // height: MediaQuery.of(context).size.height * + // 0.08, + // width: cardWidth * 0.7, + // imageUrl: bestdealproduct + // .productImages?.first?.url ?? + // "", + // backGroundColor: Colors.transparent, + // ), + // // Positioned( + // // right: 5, + // // top: 5, + // // child: InkWell( + // // onTap: () async { + // // if (await SharedPrefUtils.getToken() != + // // null) { + // // provider.toggleWishlist( + // // context, bestdealproduct.id!); + // // } else { + // // context.push(MyRoutes.LOGIN); + // // } + // // }, + // // child: Icon( + // // provider.wishlist + // // .contains(bestdealproduct.id) + // // ? Icons.favorite + // // : Icons.favorite_border, + // // color: provider.wishlist + // // .contains(bestdealproduct.id) + // // ? Colors.red + // // : Colors.grey, + // // ), + // // ), + // // ), + // ], + // ), + // ), + // ), + // SizedBox( + // height: MediaQuery.of(context).size.height * 0.01, + // ), + // Text( + // bestdealproduct.name ?? "", + // textAlign: TextAlign.left, + // maxLines: 2, + // overflow: TextOverflow.ellipsis, + // style: + // context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ), + // SizedBox( + // height: MediaQuery.of(context).size.height * 0.005, + // ), + // Text( + // bestdealproduct.unit ?? "", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context.customMedium( + // Colors.grey.withOpacity(0.8), + // 12, + // ), + // ), + // SizedBox( + // height: MediaQuery.of(context).size.height * 0.005, + // ), + // const Spacer(), + // Row( + // children: [ + // Row( + // children: [ + // Text( + // "\$${bestdealproduct.discountPrice ?? ""} ", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context.customSemiBold( + // Colors.black, 12), + // ), + // Text( + // "\$${bestdealproduct.basePrice ?? ""}", + // textAlign: TextAlign.left, + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // style: context + // .customMedium( + // Colors.grey.withOpacity(0.8), + // 12, + // ) + // .copyWith( + // decoration: + // TextDecoration.lineThrough, + // ), + // ), + // ], + // ), + // const Spacer(), + // Align( + // alignment: Alignment.centerRight, + // child: GestureDetector( + // onTap: () async { + // print( + // "Add to Cart Pressed for ${bestdealproduct.id}"); + + // if (await SharedPrefUtils.getToken() != + // null) { + // // if (!(provider + // // .isLoading[bestdealproduct.id] ?? + // // false)) + // // { + + // await provider.addToCart( + // context, bestdealproduct.id!,1); + + // // } + // } else { + // context.push(MyRoutes.SIGNUP); + // } + // }, + // child: Container( + // height: MediaQuery.of(context).size.height * + // 0.035, + // width: + // MediaQuery.of(context).size.width * 0.1, + // decoration: BoxDecoration( + // color: APPCOLOR.lightGreen, + // borderRadius: BorderRadius.circular(5), + // ), + // child: Center( + // child: provider.isLoading[ + // bestdealproduct.id] ?? + // false + // ? Padding( + // padding: + // const EdgeInsets.all(8.0), + // child: Container( + // height: 10, + // width: 10, + // child: + // CircularProgressIndicator( + // color: Colors.white, + // strokeWidth: 2), + // ), + // ) + // : Text( + // 'Add', + // style: context.customRegular( + // Colors.white, 12), + // ), + // ), + // ), + // ), + // ), + // ], + // ), + // ], + // ), + // ), + // ), + // ), + // ); + // }, + // ), + // ); + // } + // }); + // } + + Widget bannerview() { + return Consumer(builder: (context, provider, child) { + return provider.isBannerLoading + ? Skeletonizer( + enabled: provider.isBannerLoading, + child: Container( + height: 180, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(15), + ), + ), + ) + : provider.banner.isEmpty + ? Center(child: Text('No products available')) + : CarouselSlider( + options: CarouselOptions( + height: 180, + autoPlay: true, + enlargeCenterPage: true, + viewportFraction: 1, + aspectRatio: 16 / 9, + initialPage: 0, + enableInfiniteScroll: true, + reverse: false, + autoPlayInterval: Duration(seconds: 3), + autoPlayAnimationDuration: Duration(milliseconds: 800), + autoPlayCurve: Curves.fastOutSlowIn, + enlargeFactor: 0.3, + ), + items: provider.banner.map((banner) { + return Builder( + builder: (BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Colors.greenAccent.withOpacity(0.1), + borderRadius: BorderRadius.circular(15), + ), + child: Stack( + children: [ + Positioned( + top: 15, + left: 15, + child: SizedBox( + width: 200, + child: Text( + banner.altText ?? "Special Event", + style: context.customExtraBold( + Colors.black, 18), + ), + ), + ), + Positioned( + bottom: 15, + left: 15, child: GestureDetector( - onTap: () async { - print( - "Add to Cart Pressed for ${bestdealproduct.id}"); - - if (await SharedPrefUtils.getToken() != - null) { - // if (!(provider - // .isLoading[bestdealproduct.id] ?? - // false)) - // { - - await provider.addToCart( - context, bestdealproduct.id!); - - // } - } else { - context.push(MyRoutes.SIGNUP); - } + onTap: () { + _launchUrl(banner.redirectUrl); }, child: Container( - height: MediaQuery.of(context).size.height * - 0.035, - width: - MediaQuery.of(context).size.width * 0.1, + height: 40, + width: 100, decoration: BoxDecoration( color: APPCOLOR.lightGreen, borderRadius: BorderRadius.circular(5), ), child: Center( - child: provider.isLoading[ - bestdealproduct.id] ?? - false - ? Padding( - padding: - const EdgeInsets.all(8.0), - child: Container( - height: 10, - width: 10, - child: - CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2), - ), - ) - : Text( - 'Add', - style: context.customRegular( - Colors.white, 12), - ), + child: Text( + 'Shop now', + style: context.customRegular( + Colors.white, 14), + ), ), ), ), ), + Positioned( + right: 15, + bottom: 15, + child: AppNetworkImage( + height: 130, + width: 150, + imageUrl: banner.imageUrl ?? + 'https://e7.pngegg.com/pngimages/742/816/png-clipart-coca-cola-can-illustration-coca-cola-soft-drink-surge-pepsi-coke-sweetness-cola-thumbnail.png', + backGroundColor: Colors.transparent, + ), + ), ], ), - ], - ), - ), - ), - ), - ); - }, - ), - ); - } + ); + }, + ); + }).toList(), + ); }); } - Widget bannerview() { + // Future _launchUrl(url) async { + // if (!await launchUrl(url)) { + // throw Exception('Could not launch $url'); + // } + // } + Future _launchUrl(url) async { + print("jdhfjkgh ${url}"); + final Uri uri = Uri.parse(url); + if (!await launchUrl(uri, mode: LaunchMode.externalApplication)) { + throw 'Could not launch $url'; + } + } + + // Widget categoriesProduct() { + // return Consumer(builder: (context, provider, child) { + // if (provider.isLoadingg) { + // return Center(child: CircularProgressIndicator()); + // } else if (provider.products.isEmpty) { + // return Center(child: Text('No products available')); + // } else { + // return GridView.builder( + // shrinkWrap: true, + // itemCount: provider.products.length, + // physics: const NeverScrollableScrollPhysics(), + // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + // crossAxisCount: 4, + // crossAxisSpacing: 5, + // mainAxisSpacing: 5, + // childAspectRatio: MediaQuery.of(context).size.width / + // (MediaQuery.of(context).size.height / 1.2), + // ), + // itemBuilder: (context, index) { + // var product = provider.products[index]; + // return InkWell( + // onTap: () { + // context.push(MyRoutes.PRODUCTDETAILS, extra: product.id); + // }, + // child: SizedBox( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Container( + // decoration: BoxDecoration( + // color: APPCOLOR.bgGrey, + // borderRadius: BorderRadius.circular(5), + // ), + // child: AppNetworkImage( + // height: 80, + // width: 80, + // imageUrl: product.productImages!.first.url, + // //'https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png', + // backGroundColor: APPCOLOR.bgGrey, + // radius: 10, + // ), + // ), + // const SizedBox( + // height: 10, + // ), + // Text( + // product.name ?? "", + // textAlign: TextAlign.center, + // maxLines: 2, + // overflow: TextOverflow.ellipsis, + // style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + // ) + // ], + // ), + // ), + // ); + // }, + // ); + // } + // }); + // } + + Widget categoriesProduct() { return Consumer(builder: (context, provider, child) { - if (provider.isBannerLoading) { - return Center(child: CircularProgressIndicator()); - } else if (provider.banner.isEmpty) { - return Center(child: Text('No products available')); - } else { - return CarouselSlider( - options: CarouselOptions( - height: 180, - - autoPlay: true, - enlargeCenterPage: true, - - viewportFraction: 1, - aspectRatio: 16 / 9, - initialPage: 0, - enableInfiniteScroll: true, - reverse: false, - - autoPlayInterval: Duration(seconds: 3), - autoPlayAnimationDuration: Duration(milliseconds: 800), - autoPlayCurve: Curves.fastOutSlowIn, - - enlargeFactor: 0.3, - //aspectRatio: 16 / 9, - //viewportFraction: 0.9, - ), - items: provider.banner.map((banner) { - return Builder( - builder: (BuildContext context) { - return Container( - width: MediaQuery.of(context).size.width, - // margin: const EdgeInsets.symmetric(horizontal: 8.0), - decoration: BoxDecoration( - color: Colors.greenAccent.withOpacity(0.1), - borderRadius: BorderRadius.circular(15), - ), - child: Stack( + return provider.isLoadingg + ? GridView.builder( + shrinkWrap: true, + itemCount: 8, // Show 8 skeleton items + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 5, + mainAxisSpacing: 5, + childAspectRatio: MediaQuery.of(context).size.width / + (MediaQuery.of(context).size.height / 1.2), + ), + itemBuilder: (context, index) { + return Skeletonizer( + enabled: provider.isLoadingg, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Positioned( - top: 15, - left: 15, - child: SizedBox( - width: 200, - child: Text( - banner.altText ?? "Special Event", - style: context.customExtraBold(Colors.black, 18), - ), + Container( + height: 80, + width: 80, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(5), ), ), - Positioned( - bottom: 15, - left: 15, - child: GestureDetector( - onTap: () { - // Add your navigation or shop action here - }, - child: Container( - height: 40, - width: 100, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(5), - ), - child: Center( - child: Text( - 'Shop now', - style: context.customRegular(Colors.white, 14), - ), - ), - ), - ), - ), - Positioned( - right: 15, - bottom: 15, - child: AppNetworkImage( - height: 130, - width: 150, - imageUrl: banner.imageUrl ?? - 'https://e7.pngegg.com/pngimages/742/816/png-clipart-coca-cola-can-illustration-coca-cola-soft-drink-surge-pepsi-coke-sweetness-cola-thumbnail.png', - backGroundColor: Colors.transparent, - ), + const SizedBox(height: 10), + Container( + height: 15, + width: 60, + color: Colors.grey[300], ), ], ), ); }, - ); - }).toList(), - ); - } - }); - } - - Widget categoriesProduct() { - return Consumer(builder: (context, provider, child) { - if (provider.isLoadingg) { - return Center(child: CircularProgressIndicator()); - } else if (provider.products.isEmpty) { - return Center(child: Text('No products available')); - } else { - return GridView.builder( - shrinkWrap: true, - itemCount: provider.products.length, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 5, - mainAxisSpacing: 5, - childAspectRatio: MediaQuery.of(context).size.width / - (MediaQuery.of(context).size.height / 1.2), - ), - itemBuilder: (context, index) { - var product = provider.products[index]; - return InkWell( - onTap: () { - context.push(MyRoutes.PRODUCTDETAILS, extra: product.id); - }, - child: SizedBox( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - color: APPCOLOR.bgGrey, - borderRadius: BorderRadius.circular(5), + ) + : provider.products.isEmpty + ? Center(child: Text('No products available')) + : GridView.builder( + shrinkWrap: true, + itemCount: provider.products.length, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 5, + mainAxisSpacing: 5, + childAspectRatio: MediaQuery.of(context).size.width / + (MediaQuery.of(context).size.height / 1.2), + ), + itemBuilder: (context, index) { + var product = provider.products[index]; + return InkWell( + onTap: () { + context.push(MyRoutes.PRODUCTDETAILS, + extra: product.id); + }, + child: SizedBox( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + color: APPCOLOR.bgGrey, + borderRadius: BorderRadius.circular(5), + ), + child: AppNetworkImage( + height: 80, + width: 80, + imageUrl: product.productImages!.first.url, + backGroundColor: APPCOLOR.bgGrey, + radius: 10, + ), + ), + const SizedBox(height: 10), + Text( + product.name ?? "", + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: context.customMedium( + APPCOLOR.balck1A1A1A, 14), + ), + ], + ), ), - child: AppNetworkImage( - height: 80, - width: 80, - imageUrl: product.productImages!.first.url, - //'https://i.pinimg.com/originals/a5/f3/5f/a5f35fb23e942809da3df91b23718e8d.png', - backGroundColor: APPCOLOR.bgGrey, - radius: 10, - ), - ), - const SizedBox( - height: 10, - ), - Text( - product.name ?? "", - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: context.customMedium(APPCOLOR.balck1A1A1A, 14), - ) - ], - ), - ), - ); - }, - ); - } + ); + }, + ); }); } } diff --git a/lib/src/ui/map/add_locations.dart b/lib/src/ui/map/add_locations.dart new file mode 100644 index 0000000..1213348 --- /dev/null +++ b/lib/src/ui/map/add_locations.dart @@ -0,0 +1,466 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:geocoding/geocoding.dart'; +import 'package:grocery_app/src/logic/provider/addTocart_provider.dart'; +import 'package:grocery_app/src/logic/provider/address_provider.dart'; +import 'package:grocery_app/utils/constants/color_constant.dart'; +import 'package:grocery_app/utils/extensions/uicontext.dart'; + +import 'package:http/http.dart' as http; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:provider/provider.dart'; + +const String googleApiKey = "AIzaSyAi3_Dls63iGs7Nccgdm-4FkS0rhT03-4U"; + +class AddLocationAddress extends StatefulWidget { + @override + _AddLocationAddressState createState() => _AddLocationAddressState(); +} + +class _AddLocationAddressState extends State { + final _formKey = GlobalKey(); + late GoogleMapController mapController; + LatLng _selectedLocation = LatLng(20.5937, 78.9629); + + TextEditingController _pincodeController = TextEditingController(); + TextEditingController _fullNameController = TextEditingController(); + TextEditingController _PhoneNumberController = TextEditingController(); + TextEditingController _addressTypeController = TextEditingController(); + TextEditingController _HouseNoController = TextEditingController(); + TextEditingController _RoadController = TextEditingController(); + TextEditingController _AlterNativeNumberController = TextEditingController(); + + @override + void initState() { + super.initState(); + _determinePosition(); + } + + Future _determinePosition() async { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + return; + } + + LocationPermission permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + return; + } + + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high, + ); + LatLng currentLatLng = LatLng(position.latitude, position.longitude); + + setState(() { + _selectedLocation = currentLatLng; + }); + + _getAddressFromLatLng(position.latitude, position.longitude); + } + + Future _getAddressFromLatLng(double lat, double lng) async { + final String url = + "https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=$googleApiKey"; + + try { + final response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + final data = json.decode(response.body); + if (data["status"] == "OK") { + var result = data["results"][0]; // First result is most accurate + + _RoadController.text = result["formatted_address"]; + List components = result["address_components"]; + + String roadName = ""; + String colony = ""; + String buildingName = ""; + String pincode = ""; + + for (var component in components) { + List types = component["types"]; + if (types.contains("route")) { + roadName = component["long_name"]; // Road Name + } else if (types.contains("sublocality_level_1") || + types.contains("locality")) { + colony = component["long_name"]; // Colony Name + } else if (types.contains("premise") || + types.contains("street_number")) { + buildingName = component["long_name"]; // Building Name + } else if (types.contains("postal_code")) { + pincode = component["long_name"]; // Extract Pin Code + } + } + + // setState(() { + // // _address = formattedAddress; + // _roadName = roadName; + // _colony = colony; + // _buildingName = buildingName; + // }); + + _pincodeController.text = pincode; + _RoadController.text = result["formatted_address"]; + + print( + "Full Address: ${result["formatted_address"]} ${response.body} sdfsgd ${pincode}"); + print("Road Name: $roadName"); + print("Colony: $colony"); + print("Building Name: $buildingName"); + } else {} + } else {} + } catch (e) { + print("Error fetching address: $e"); + } + } + + void _onMapTapped(LatLng tappedPoint) { + setState(() { + _selectedLocation = tappedPoint; + }); + _getAddressFromLatLng(tappedPoint.latitude, tappedPoint.longitude); + } + + Future _updateLocationFromPincode(String enteredPincode) async { + if (enteredPincode.isEmpty) return; + + try { + List locations = await locationFromAddress(enteredPincode); + if (locations.isNotEmpty) { + Location location = locations.first; + LatLng newLatLng = LatLng(location.latitude, location.longitude); + + setState(() { + _selectedLocation = newLatLng; + }); + + _getAddressFromLatLng(location.latitude, location.longitude); + mapController.animateCamera(CameraUpdate.newLatLng(newLatLng)); + } + } catch (e) { + print("Error fetching location from pincode: $e"); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("Add Delivery address")), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: SingleChildScrollView( + child: Column( + children: [ + Container( + height: 200.h, + child: GoogleMap( + initialCameraPosition: CameraPosition( + target: _selectedLocation, + zoom: 14, + ), + onMapCreated: (controller) { + mapController = controller; + }, + + myLocationEnabled: true, // Enable current location button + myLocationButtonEnabled: true, + markers: { + Marker( + markerId: MarkerId("selected Location"), + position: _selectedLocation, + ) + }, + onTap: _onMapTapped, + ), + ), + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10)], + ), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 10), + TextFormField( + controller: _fullNameController, + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: "Full Name (Required)*", + border: OutlineInputBorder(), + ), + + validator: (value) { + if (value == null || value.isEmpty) { + return "Full Name"; + } + return null; // ✅ Valid input + }, + + // Auto-update on enter + ), + SizedBox(height: 10), + TextFormField( + controller: _PhoneNumberController, + keyboardType: TextInputType.number, + maxLength: 10, + decoration: InputDecoration( + labelText: "Phone Number (Required)*", + border: OutlineInputBorder(), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return "Phone Number "; + } + return null; // ✅ Valid input + }, + ), + SizedBox(height: 10), + Row( + children: [ + Expanded( + child: TextFormField( + controller: _pincodeController, + keyboardType: TextInputType.number, + maxLength: 6, + decoration: InputDecoration( + labelText: "Enter Pincode", + border: OutlineInputBorder(), + counterText: ""), + validator: (value) { + if (value == null || value.isEmpty) { + return "Please enter a pincode"; + } else if (value.length != 6) { + return "Pincode must be exactly 6 digits"; + } else if (!RegExp(r'^[1-9][0-9]{5}$') + .hasMatch(value)) { + return "Enter a valid Indian pincode"; + } + return null; // ✅ Valid input + }, + ), + ), + SizedBox( + width: 10, + ), + // Expanded( + // child: TextFormField( + // controller: _addressTypeController, + // keyboardType: TextInputType.text, + // decoration: InputDecoration( + // labelText: "Address Type", + // border: OutlineInputBorder(), + // ), + // validator: (value) { + // if (value == null || value.isEmpty) { + // return "Enter address Home or Work "; + // } + // return null; // ✅ Valid input + // }, + // ), + // ),\ + Expanded( + child: DropdownButtonFormField( + value: _addressTypeController.text.isNotEmpty + ? _addressTypeController.text + : null, + items: + ["HOME", "WORK", "OTHER"].map((String type) { + return DropdownMenuItem( + value: type, + child: Text(type), + ); + }).toList(), + decoration: InputDecoration( + labelText: "Address Type", + border: OutlineInputBorder(), + ), + onChanged: (value) { + if (value != null) { + _addressTypeController.text = value; + } + }, + validator: (value) { + if (value == null || value.isEmpty) { + return "Select Address Type (Home, Work, Other)"; + } + return null; + }, + ), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + controller: _HouseNoController, + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: "House No, Building Name (Required)*", + border: OutlineInputBorder(), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return "Enter House No, Building "; + } + return null; // ✅ Valid input + }, + ), + SizedBox(height: 10), + TextFormField( + controller: _RoadController, + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: "Road Name, Area , Colony(Required)*", + border: OutlineInputBorder(), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return "Enter Road Name, Area , Colony(Required)"; + } + return null; // ✅ Valid input + }, + ), + SizedBox(height: 10), + + Consumer( + builder: (context, addressProvider, child) + { + return InkWell( + onTap: () async { + if (_formKey.currentState!.validate()) { + var status = await addressProvider.checkPin( + context, _pincodeController.text); + + if (status) { + var state = await addressProvider.addAddress( + context, + _fullNameController.text, + _pincodeController.text, + _PhoneNumberController.text, + _PhoneNumberController.text, + _HouseNoController.text, + _RoadController.text, + _addressTypeController.text); + if (state) { + context .read() + .getAddress(context); + Fluttertoast.showToast( + msg: "Address Added!", + backgroundColor: Colors.lightGreen); + Navigator.pop(context); + } + } else { + Fluttertoast.showToast( + msg: + "Delivery is not available for this pincode. Please try another pincode!", + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 14.0, + ); + } + } + }, + child: Container( + margin: const EdgeInsets.only( + left: 15, right: 15, top: 10, bottom: 10), + height: 50, + width: MediaQuery.sizeOf(context).width, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + borderRadius: BorderRadius.circular(10), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (addressProvider.ischeckpin) + const CircularProgressIndicator( + color: Colors.white, + ) + else + Text( + "Save Address", + style: context.customMedium( + Colors.white, 20), + ), + ], + ), + ), + ); + }, + ), + + // InkWell( + // onTap: () async { + // if (_formKey.currentState!.validate()) { + // var status = await Provider.of( + // context, + // listen: false) + // .checkPin(context, _pincodeController.text); + // if (status) { + // // var status = await Provider.of( + // // context, + // // listen: false) + // // .addAddress(context, _pincodeController.text); + // } else { + // // Delivery is not available for this pincode. Please try another pincode. + + // Fluttertoast.showToast( + // msg: + // "Delivery is not available for this pincode. Please try another pincode!", + // toastLength: Toast.LENGTH_SHORT, + // gravity: ToastGravity.BOTTOM, + // backgroundColor: Colors.red, + // textColor: Colors.white, + // fontSize: 14.0, + // ); + // } + // } + // }, + // child: Container( + // margin: const EdgeInsets.only( + // left: 15, right: 15, top: 10, bottom: 10), + // height: 50, + // width: MediaQuery.sizeOf(context).width, + // decoration: BoxDecoration( + // color: APPCOLOR.lightGreen, + // borderRadius: BorderRadius.circular(10)), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // const SizedBox( + // width: 10, + // ), + // Text( + // "Save Address", + // style: context.customMedium(Colors.white, 20), + // ), + // ], + // ), + // ), + // ), + + SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/ui/map/google_map.dart b/lib/src/ui/map/google_map.dart deleted file mode 100644 index 20c1686..0000000 --- a/lib/src/ui/map/google_map.dart +++ /dev/null @@ -1,330 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:geocoding/geocoding.dart'; -import 'package:grocery_app/utils/constants/color_constant.dart'; -import 'package:grocery_app/utils/extensions/uicontext.dart'; - -import 'package:http/http.dart' as http; -import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; - -const String googleApiKey = "AIzaSyAi3_Dls63iGs7Nccgdm-4FkS0rhT03-4U"; - -class MapScreen extends StatefulWidget { - @override - _MapScreenState createState() => _MapScreenState(); -} - -class _MapScreenState extends State { - late GoogleMapController mapController; - LatLng _selectedLocation = LatLng(20.5937, 78.9629); - - TextEditingController _pincodeController = TextEditingController(); - TextEditingController _fullNameController = TextEditingController(); - TextEditingController _PhoneNumberController = TextEditingController(); - TextEditingController _addressTypeController = TextEditingController(); - TextEditingController _HouseNoController = TextEditingController(); - TextEditingController _RoadController = TextEditingController(); - TextEditingController _AlterNativeNumberController = TextEditingController(); - - @override - void initState() { - super.initState(); - _determinePosition(); - } - - Future _determinePosition() async { - bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - return; - } - - LocationPermission permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.denied) { - return; - } - - Position position = await Geolocator.getCurrentPosition( - desiredAccuracy: LocationAccuracy.high, - ); - LatLng currentLatLng = LatLng(position.latitude, position.longitude); - - setState(() { - _selectedLocation = currentLatLng; - }); - - _getAddressFromLatLng(position.latitude, position.longitude); - } - - Future _getAddressFromLatLng(double lat, double lng) async { - final String url = - "https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=$googleApiKey"; - - try { - final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - final data = json.decode(response.body); - if (data["status"] == "OK") { - var result = data["results"][0]; // First result is most accurate - - _RoadController.text = result["formatted_address"]; - List components = result["address_components"]; - - String roadName = ""; - String colony = ""; - String buildingName = ""; - String pincode = ""; - - for (var component in components) { - List types = component["types"]; - if (types.contains("route")) { - roadName = component["long_name"]; // Road Name - } else if (types.contains("sublocality_level_1") || - types.contains("locality")) { - colony = component["long_name"]; // Colony Name - } else if (types.contains("premise") || - types.contains("street_number")) { - buildingName = component["long_name"]; // Building Name - } else if (types.contains("postal_code")) { - pincode = component["long_name"]; // Extract Pin Code - } - } - - // setState(() { - // // _address = formattedAddress; - // _roadName = roadName; - // _colony = colony; - // _buildingName = buildingName; - // }); - - _pincodeController.text = pincode; - _RoadController.text = result["formatted_address"]; - - print( - "Full Address: ${result["formatted_address"]} ${response.body} sdfsgd ${pincode}"); - print("Road Name: $roadName"); - print("Colony: $colony"); - print("Building Name: $buildingName"); - } else {} - } else {} - } catch (e) { - print("Error fetching address: $e"); - } - } - - // On map tapped - void _onMapTapped(LatLng tappedPoint) { - setState(() { - _selectedLocation = tappedPoint; - }); - _getAddressFromLatLng(tappedPoint.latitude, tappedPoint.longitude); - } - - // Update location based on entered pincode - Future _updateLocationFromPincode(String enteredPincode) async { - if (enteredPincode.isEmpty) return; - - try { - List locations = await locationFromAddress(enteredPincode); - if (locations.isNotEmpty) { - Location location = locations.first; - LatLng newLatLng = LatLng(location.latitude, location.longitude); - - setState(() { - _selectedLocation = newLatLng; - }); - - _getAddressFromLatLng(location.latitude, location.longitude); - mapController.animateCamera(CameraUpdate.newLatLng(newLatLng)); - } - } catch (e) { - print("Error fetching location from pincode: $e"); - } - } - -// { -// "name": "Socket Mall", -// "pincode": "400001", -// "phoneNumber": "+919876543210", -// "alternatePhoneNumber": "+919876543211", -// "addressLine": "123, Main Street, Apartment 4B", -// "landmark": "Near Central Park", -// "addressType": "HOME", -// "isDefault": false, -// "additionalInstructions": "Please ring doorbell twice" -// } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: Text("Add Delivery address")), - body: Column( - children: [ - Container( - height: 200.h, - child: GoogleMap( - initialCameraPosition: CameraPosition( - target: _selectedLocation, - zoom: 14, - ), - onMapCreated: (controller) { - mapController = controller; - }, - markers: { - Marker( - markerId: MarkerId("selected Location"), - position: _selectedLocation, - ) - }, - onTap: _onMapTapped, - ), - ), - SingleChildScrollView( - child: Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 10)], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Text("Selected Address:", - // style: TextStyle(fontWeight: FontWeight.bold)), - - // SizedBox(height: 5), - // Text(_address, style: TextStyle(fontSize: 16)), - SizedBox(height: 10), - TextField( - controller: _fullNameController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "Full Name (Required)*", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - SizedBox(height: 10), - TextField( - controller: _PhoneNumberController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "Phone Number (Required)*", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - SizedBox(height: 10), - Row( - children: [ - Expanded( - child: TextField( - controller: _pincodeController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "Enter Pincode", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - ), - SizedBox( - width: 10, - ), - Expanded( - child: TextField( - controller: _addressTypeController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "Address Type", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - ), - ], - ), - SizedBox(height: 10), - TextField( - controller: _HouseNoController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "House No, Building Name (Required)*", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - SizedBox(height: 10), - TextField( - controller: _RoadController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - labelText: "Road Name, Area , Colony(Required)*", - border: OutlineInputBorder(), - ), - onChanged: (value) {}, - onSubmitted: - _updateLocationFromPincode, // Auto-update on enter - ), - SizedBox(height: 10), - InkWell( - onTap: () { - // print("fjnghkjfjghj"); - // Provider.of(context, listen: false) - // .customerLogOut(context); - }, - child: Container( - margin: const EdgeInsets.only( - left: 15, right: 15, top: 10, bottom: 10), - height: 50, - width: MediaQuery.sizeOf(context).width, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(10)), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - width: 10, - ), - Text( - "Save Address", - style: context.customMedium(Colors.white, 20), - ), - ], - ), - ), - ), - // ElevatedButton( - // onPressed: () { - // Navigator.pop(context, { - // "location": _selectedLocation, - // "address": _address, - // "pincode": _pincode - // }); - // }, - // child: Text("Confirm Location"), - // ), - ], - ), - ), - ), - ], - ), - ); - } -} diff --git a/lib/src/ui/productdetails/product_details.dart b/lib/src/ui/productdetails/product_details.dart index 266ad57..570fc86 100644 --- a/lib/src/ui/productdetails/product_details.dart +++ b/lib/src/ui/productdetails/product_details.dart @@ -10,6 +10,7 @@ import 'package:go_router/go_router.dart'; import 'package:grocery_app/src/common_widget/network_image.dart'; import 'package:grocery_app/src/core/routes/routes.dart'; import 'package:grocery_app/src/data/allProduct_model.dart'; +import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; import 'package:grocery_app/src/logic/provider/home_provider.dart'; import 'package:grocery_app/utils/constants/assets_constant.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; @@ -18,6 +19,7 @@ import 'package:grocery_app/utils/extensions/uicontext.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:provider/provider.dart'; import 'package:readmore/readmore.dart'; +import 'package:shimmer/shimmer.dart'; class ProductDetails extends StatefulWidget { String id; @@ -95,7 +97,6 @@ class _ProductDetailsState extends State { prodectDtails(), Divider(), reviews(), - Divider(), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text("Similar Products", @@ -110,20 +111,39 @@ class _ProductDetailsState extends State { ), ), ), - // bottomNavigationBar: bottomBar(), + bottomNavigationBar: bottomBar(), ); } + double calculateDiscountPercentage(double basePrice, double discountPrice) { + print( + "Base Price (Before Discount): $basePrice, Discount Price (After Discount): $discountPrice"); + + if (basePrice <= 0 || discountPrice <= 0 || discountPrice > basePrice) { + print("Error: Invalid price values."); + return 0; + } + + double discountAmount = basePrice - discountPrice; + double discountPercentage = (discountAmount / basePrice) * 100; + + return discountPercentage; + } + Widget prodectDtails() { return Consumer(builder: (context, provider, child) { if (provider.isProductLoading) { - return Center( - child: CircularProgressIndicator( - color: Colors.green, - )); + return _buildSkeletonLoader(); } else if (provider.productDetails.data == null) { return Center(child: Text('No products available')); } else { + provider.setProductPrice( + double.parse(provider.productDetails.data!.discountPrice)); + provider.productQuantity = provider.productDetails.data!.quantity; + + if (provider.productDetails.data!.isInWishlist!) { + provider.wishlist.contains(provider.productDetails.data!.id); + } return Column( children: [ SizedBox( @@ -206,43 +226,13 @@ class _ProductDetailsState extends State { color: Colors.green, borderRadius: BorderRadius.circular(5), ), - child: Text("10% OFF", + child: Text( + "${calculateDiscountPercentage(double.parse(provider.productDetails.data!.basePrice), double.parse(provider.productDetails.data!.discountPrice))}% OFF", style: TextStyle(color: Colors.white, fontSize: 14)), ), - Spacer(), - InkWell( - onTap: () async { - if (await SharedPrefUtils.getToken() != null) { - provider.toggleWishlist( - context, provider.productDetails.data!.id!); - } else { - context.push(MyRoutes.SIGNUP); - } - }, - child: Icon( - provider.wishlist - .contains(provider.productDetails.data!.id) - ? Icons.favorite - : Icons.favorite_border, - color: provider.wishlist - .contains(provider.productDetails.data!.id) - ? Colors.red - : Colors.grey, - ), - ), ], ), - SizedBox(height: 10), - ReadMoreText( - provider.productDetails.data!.description ?? "", - trimMode: TrimMode.Line, - trimLines: 2, - colorClickableText: APPCOLOR.appGreen, - trimCollapsedText: 'Read More', - trimExpandedText: 'Show less', - style: context.customMedium(APPCOLOR.balck1A1A1A, 14), - ), ], ), ), @@ -252,262 +242,320 @@ class _ProductDetailsState extends State { }); } - Widget reviews() { + Widget _buildSkeletonLoader() { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Reviews & Ratings", - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), - SizedBox(height: 10), - Row( - children: [ - Text("4.2", - style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold)), - SizedBox( - width: 10, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RatingStars( - value: value, - onValueChanged: (v) { - // - setState(() { - value = v; - }); - }, - starBuilder: (index, color) => Icon( - Icons.star, - color: color, - ), - starCount: 5, - starSize: 20, - valueLabelColor: const Color(0xff9b9b9b), - valueLabelTextStyle: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w400, - fontStyle: FontStyle.normal, - fontSize: 12.0), - valueLabelRadius: 10, - maxValue: 5, - starSpacing: 2, - maxValueVisibility: false, - valueLabelVisibility: false, - animationDuration: Duration(milliseconds: 1000), - valueLabelPadding: - const EdgeInsets.symmetric(vertical: 1, horizontal: 8), - valueLabelMargin: const EdgeInsets.only(right: 8), - starOffColor: const Color(0xffe7e8ea), - starColor: Colors.green, - ), - Text( - "April 10, 2023", - style: TextStyle(color: Colors.grey), - ), - ], - ), - ], + Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 300, + color: Colors.white, + ), ), SizedBox(height: 10), - Row( - crossAxisAlignment: - CrossAxisAlignment.start, // Align items at the top - children: [ - CircleAvatar( - backgroundImage: NetworkImage('https://via.placeholder.com/50'), - ), - SizedBox(width: 10), - - // Column for Text and RatingStars - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, // Proper spacing - children: [ - Text( - "Johnson Smith", - style: TextStyle(fontWeight: FontWeight.bold), - ), - RatingStars( - value: value, - starBuilder: (index, color) => Icon( - Icons.star, - color: color, - ), - starCount: 5, - starSize: 20, - maxValue: 5, - starSpacing: 2, - maxValueVisibility: false, - valueLabelVisibility: false, - animationDuration: Duration(milliseconds: 1000), - valueLabelPadding: const EdgeInsets.symmetric( - vertical: 1, horizontal: 8), - valueLabelMargin: const EdgeInsets.only(right: 8), - starOffColor: const Color(0xffe7e8ea), - starColor: Colors.green, - ), - ], - ), - SizedBox(height: 4), - Text( - "April 10, 2023", - style: TextStyle(color: Colors.grey), - ), - ], - ), - ), - ], + Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 20, + width: double.infinity, + color: Colors.white, + ), ), SizedBox(height: 10), - ReadMoreText( - 'Flutter is Google’s mobile UI open source framework to build high-quality native (super fast) interfaces for iOS and Android apps with the unified codebase.', - trimMode: TrimMode.Line, - trimLines: 2, - colorClickableText: APPCOLOR.appGreen, - trimCollapsedText: 'Read More', - trimExpandedText: 'Show less', - style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + height: 20, + width: 150, + color: Colors.white, + ), ), ], ), ); } - // Widget similarProducts() { - // return SizedBox( - // height: 222, - // child: ListView.builder( - // itemCount: 5, - // scrollDirection: Axis.horizontal, - // itemBuilder: (context, index) { - // return Padding( - // padding: const EdgeInsets.only(right: 10, bottom: 5, top: 5), - // child: Container( - // height: 215, - // width: 150, - // decoration: BoxDecoration( - // color: Colors.white, - // borderRadius: BorderRadius.circular(15), - // boxShadow: [ - // BoxShadow( - // color: Colors.grey.withOpacity(0.1), - // blurRadius: 1, - // offset: const Offset(5, 5), - // ), - // ]), - // child: Padding( - // padding: const EdgeInsets.all(5), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // height: 100, - // width: 150, - // decoration: BoxDecoration( - // color: APPCOLOR.bgGrey, - // borderRadius: BorderRadius.circular(15)), - // child: const Stack( - // alignment: Alignment.center, - // children: [ - // AppNetworkImage( - // height: 70, - // width: 70, - // imageUrl: - // "https://5.imimg.com/data5/SELLER/Default/2024/2/385126988/OL/DA/VW/8627346/1l-fortune-sunflower-oil.jpg", - // backGroundColor: Colors.transparent), - // Positioned( - // right: 5, - // top: 5, - // child: Icon(Icons.favorite_border)) - // ], - // ), - // ), - // Text( - // "Fortune Arhar Dal (Toor Dal)", - // textAlign: TextAlign.left, - // maxLines: 2, - // overflow: TextOverflow.ellipsis, - // style: context.customMedium(APPCOLOR.balck1A1A1A, 14), - // ), - // const SizedBox( - // height: 5, - // ), - // Text( - // "500 ML", - // textAlign: TextAlign.left, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: context.customMedium( - // Colors.grey.withOpacity(0.8), 12), - // ), - // const SizedBox( - // height: 3, - // ), - // Row( - // children: [ - // Expanded( - // child: Row( - // children: [ - // Text( - // "\$12", - // textAlign: TextAlign.left, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: context.customSemiBold(Colors.black, 12), - // ), - // const SizedBox( - // width: 5, - // ), - // Text( - // "\$14", - // textAlign: TextAlign.left, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - // style: context - // .customMedium( - // Colors.grey.withOpacity(0.8), 12) - // .copyWith( - // decoration: TextDecoration.lineThrough, - // ), - // ), - // ], - // )), - // Expanded( - // child: Align( - // alignment: Alignment.centerRight, - // child: Container( - // height: 30, - // width: 50, - // decoration: BoxDecoration( - // color: APPCOLOR.lightGreen, - // borderRadius: BorderRadius.circular(5), - // ), - // child: Center( - // child: Text( - // 'Add', - // style: context.customRegular(Colors.white, 12), - // )), - // ), - // ), - // ) - // ], - // ), - // ], - // ), - // ), - // ), - // ); - // }, - // ), - // ); - // } + Widget reviews() { + return Consumer(builder: (context, provider, child) { + if (provider.isProductLoading) { + return SizedBox.shrink(); + } else if (provider.productDetails.data == null) { + return Center(child: Text('No products available')); + } else { + return provider.productDetails.data!.productReview!.isNotEmpty + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Reviews & Ratings", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.bold)), + SizedBox(height: 10), + Row( + children: [ + Text("4.2", + style: TextStyle( + fontSize: 30, fontWeight: FontWeight.bold)), + SizedBox( + width: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RatingStars( + value: value, + onValueChanged: (v) { + // + setState(() { + value = v; + }); + }, + starBuilder: (index, color) => Icon( + Icons.star, + color: color, + ), + starCount: 5, + starSize: 20, + valueLabelColor: const Color(0xff9b9b9b), + valueLabelTextStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + fontSize: 12.0), + valueLabelRadius: 10, + maxValue: 5, + starSpacing: 2, + maxValueVisibility: false, + valueLabelVisibility: false, + animationDuration: Duration(milliseconds: 1000), + valueLabelPadding: const EdgeInsets.symmetric( + vertical: 1, horizontal: 8), + valueLabelMargin: const EdgeInsets.only(right: 8), + starOffColor: const Color(0xffe7e8ea), + starColor: Colors.green, + ), + Text( + "April 10, 2023", + style: TextStyle(color: Colors.grey), + ), + ], + ), + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: + CrossAxisAlignment.start, // Align items at the top + children: [ + CircleAvatar( + backgroundImage: + NetworkImage('https://via.placeholder.com/50'), + ), + SizedBox(width: 10), + + // Column for Text and RatingStars + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment + .spaceBetween, // Proper spacing + children: [ + Text( + "Johnson Smith", + style: + TextStyle(fontWeight: FontWeight.bold), + ), + RatingStars( + value: value, + starBuilder: (index, color) => Icon( + Icons.star, + color: color, + ), + starCount: 5, + starSize: 20, + maxValue: 5, + starSpacing: 2, + maxValueVisibility: false, + valueLabelVisibility: false, + animationDuration: + Duration(milliseconds: 1000), + valueLabelPadding: + const EdgeInsets.symmetric( + vertical: 1, horizontal: 8), + valueLabelMargin: + const EdgeInsets.only(right: 8), + starOffColor: const Color(0xffe7e8ea), + starColor: Colors.green, + ), + ], + ), + SizedBox(height: 4), + Text( + "April 10, 2023", + style: TextStyle(color: Colors.grey), + ), + ], + ), + ), + ], + ), + SizedBox(height: 10), + ReadMoreText( + 'Flutter is Google’s mobile UI open source framework to build high-quality native (super fast) interfaces for iOS and Android apps with the unified codebase.', + trimMode: TrimMode.Line, + trimLines: 2, + colorClickableText: APPCOLOR.appGreen, + trimCollapsedText: 'Read More', + trimExpandedText: 'Show less', + style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + ), + ], + ), + ) + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Reviews & Ratings", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.bold)), + SizedBox(height: 10), + Row( + children: [ + Text("4.2", + style: TextStyle( + fontSize: 30, fontWeight: FontWeight.bold)), + SizedBox( + width: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RatingStars( + value: value, + onValueChanged: (v) { + // + setState(() { + value = v; + }); + }, + starBuilder: (index, color) => Icon( + Icons.star, + color: color, + ), + starCount: 5, + starSize: 20, + valueLabelColor: const Color(0xff9b9b9b), + valueLabelTextStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + fontSize: 12.0), + valueLabelRadius: 10, + maxValue: 5, + starSpacing: 2, + maxValueVisibility: false, + valueLabelVisibility: false, + animationDuration: Duration(milliseconds: 1000), + valueLabelPadding: const EdgeInsets.symmetric( + vertical: 1, horizontal: 8), + valueLabelMargin: const EdgeInsets.only(right: 8), + starOffColor: const Color(0xffe7e8ea), + starColor: Colors.green, + ), + Text( + "April 10, 2023", + style: TextStyle(color: Colors.grey), + ), + ], + ), + ], + ), + SizedBox(height: 10), + Row( + crossAxisAlignment: + CrossAxisAlignment.start, // Align items at the top + children: [ + CircleAvatar( + backgroundImage: + NetworkImage('https://via.placeholder.com/50'), + ), + SizedBox(width: 10), + + // Column for Text and RatingStars + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment + .spaceBetween, // Proper spacing + children: [ + Text( + "Johnson Smith", + style: + TextStyle(fontWeight: FontWeight.bold), + ), + RatingStars( + value: value, + starBuilder: (index, color) => Icon( + Icons.star, + color: color, + ), + starCount: 5, + starSize: 20, + maxValue: 5, + starSpacing: 2, + maxValueVisibility: false, + valueLabelVisibility: false, + animationDuration: + Duration(milliseconds: 1000), + valueLabelPadding: + const EdgeInsets.symmetric( + vertical: 1, horizontal: 8), + valueLabelMargin: + const EdgeInsets.only(right: 8), + starOffColor: const Color(0xffe7e8ea), + starColor: Colors.green, + ), + ], + ), + SizedBox(height: 4), + Text( + "April 10, 2023", + style: TextStyle(color: Colors.grey), + ), + ], + ), + ), + ], + ), + SizedBox(height: 10), + ReadMoreText( + 'Flutter is Google’s mobile UI open source framework to build high-quality native (super fast) interfaces for iOS and Android apps with the unified codebase.', + trimMode: TrimMode.Line, + trimLines: 2, + colorClickableText: APPCOLOR.appGreen, + trimCollapsedText: 'Read More', + trimExpandedText: 'Show less', + style: context.customMedium(APPCOLOR.balck1A1A1A, 14), + ), + ], + ), + ); + } + }); + } Widget bestDeal() { return Consumer(builder: (context, provider, child) { @@ -678,7 +726,7 @@ class _ProductDetailsState extends State { false ? null : () => provider.addToCart( - context, bestdealproduct.id!); + context, bestdealproduct.id!, 1); } else { context.push(MyRoutes.SIGNUP); } @@ -730,71 +778,90 @@ class _ProductDetailsState extends State { } Widget bottomBar() { - return Consumer( - builder: (context, cartProvider, child) { - return Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - boxShadow: [BoxShadow(color: Colors.grey.shade300, blurRadius: 10)], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - IconButton( - icon: Icon(Icons.remove_circle_outline), - onPressed: cartProvider.decreaseQuantity, - ), - Text("${cartProvider.quantity}", - style: - TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), - IconButton( - icon: Icon(Icons.add_circle_outline), - onPressed: cartProvider.increaseQuantity, - ), - ], + return Consumer(builder: (context, cartProvider, child) { + return Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [BoxShadow(color: Colors.grey.shade300, blurRadius: 10)], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + IconButton( + icon: Icon(Icons.remove_circle_outline), + onPressed: cartProvider.decreaseQuantity, + ), + Text("${cartProvider.quantity}", + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + IconButton( + icon: Icon(Icons.add_circle_outline), + onPressed: cartProvider.increaseQuantity, + ), + ], + ), + Container( + height: 50, + decoration: BoxDecoration( + color: APPCOLOR.lightGreen, + borderRadius: BorderRadius.circular(5), ), - Container( - height: 50, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - borderRadius: BorderRadius.circular(5), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Row( - children: [ - Text( - 'Add to Cart', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white), - ), - SizedBox(width: 10), - Container( - width: 2, height: 50, color: APPCOLOR.whiteFBFEFB), - SizedBox(width: 10), - Text( - "\$${cartProvider.totalPrice}", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: Colors.white), - ), - ], - ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Row( + children: [ + InkWell( + onTap: () { + cartProvider.addToCart( + context, + cartProvider.productDetails.data!.id!, + cartProvider.quantity); + }, + child: cartProvider.isLoadingCart + ? Padding( + padding: + const EdgeInsets.only(left: 40, right: 40), + child: Container( + height: 15, + width: 15, + child: Center( + child: CircularProgressIndicator( + color: Colors.white, strokeWidth: 2), + ), + ), + ) + : Text( + 'Add to Cart', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ), + SizedBox(width: 10), + Container( + width: 2, height: 50, color: APPCOLOR.whiteFBFEFB), + SizedBox(width: 10), + Text( + "\$${cartProvider.totalPrice}", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ], ), ), - ) - ], - ), - ); - }, - ); + ), + ) + ], + ), + ); + }); } } diff --git a/lib/src/ui/profilepage/profile_screen.dart b/lib/src/ui/profilepage/profile_screen.dart index 3db788a..3b42317 100644 --- a/lib/src/ui/profilepage/profile_screen.dart +++ b/lib/src/ui/profilepage/profile_screen.dart @@ -3,16 +3,19 @@ import 'package:grocery_app/src/common_widget/network_image.dart'; import 'package:grocery_app/src/logic/provider/home_provider.dart'; import 'package:grocery_app/src/ui/card_checkout/card_checkout_screen.dart'; import 'package:grocery_app/src/ui/edit_profile/edit_profile_screen.dart'; -import 'package:grocery_app/src/ui/map/google_map.dart'; + import 'package:grocery_app/src/ui/mapscreen/map_screen.dart'; import 'package:grocery_app/src/ui/message/message_screen.dart'; import 'package:grocery_app/src/ui/notification/notification_screen.dart'; import 'package:grocery_app/src/ui/rating_review/rating_review_screen.dart'; import 'package:grocery_app/src/ui/static_page/static_page_screen.dart'; import 'package:grocery_app/utils/constants/color_constant.dart'; +import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; +import 'package:grocery_app/utils/constants/string_constant.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); @@ -25,7 +28,8 @@ class _ProfileScreenState extends State { var top = 0.0; @override - Widget build(BuildContext context) { + Widget build(BuildContext context) + { return Scaffold( body: NestedScrollView( headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { @@ -69,34 +73,34 @@ class _ProfileScreenState extends State { AppNetworkImage( height: top < 150 ? 30 : 50, width: top < 150 ? 30 : 50, - imageUrl: + imageUrl: "${APPSTRING.userProfile ?? ""}" ?? "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTdQLwDqDwd2JfzifvfBTFT8I7iKFFevcedYg&s", radius: 90, backGroundColor: Colors.white, boxFit: BoxFit.fill, ), - top > 100 - ? Positioned( - bottom: 0, - right: 0, - child: Container( - height: 18, - width: 18, - decoration: BoxDecoration( - color: APPCOLOR.lightGreen, - border: Border.all( - color: Colors.white), - borderRadius: - BorderRadius.circular(5)), - child: Center( - child: Icon( - MdiIcons.pencil, - size: 10, - color: Colors.white, - ), - ), - )) - : const SizedBox(), + // top > 100 + // ? Positioned( + // bottom: 0, + // right: 0, + // child: Container( + // height: 18, + // width: 18, + // decoration: BoxDecoration( + // color: APPCOLOR.lightGreen, + // border: Border.all( + // color: Colors.white), + // borderRadius: + // BorderRadius.circular(5)), + // child: Center( + // child: Icon( + // MdiIcons.pencil, + // size: 10, + // color: Colors.white, + // ), + // ), + // )) + // : const SizedBox(), ], ), const SizedBox( @@ -108,13 +112,13 @@ class _ProfileScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ Text( - "Smith Mate", + APPSTRING.userName ?? "", style: context.customExtraBold( top < 100 ? Colors.black : Colors.white, 14), ), Text( - 'smithmate@example.com', + APPSTRING.emailName, style: context.customRegular( top < 100 ? Colors.black : Colors.white, 10), @@ -196,30 +200,31 @@ class _ProfileScreenState extends State { title: const Text('Notifications'), trailing: Icon(MdiIcons.chevronRight), ), - ListTile( - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return const RatingReviewScreen(); - }, - )); - }, - leading: Icon(MdiIcons.starOutline), - title: const Text('Rating & Review'), - trailing: Icon(MdiIcons.chevronRight), - ), - ListTile( - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return const MessageScreen(); - }, - )); - }, - leading: Icon(MdiIcons.messageOutline), - title: const Text('Driver Message'), - trailing: Icon(MdiIcons.chevronRight), - ), + // ListTile( + // onTap: () { + // Navigator.of(context).push(MaterialPageRoute( + // builder: (context) { + // return const RatingReviewScreen(); + // }, + // )); + // }, + // leading: Icon(MdiIcons.starOutline), + // title: const Text('Rating & Review'), + // trailing: Icon(MdiIcons.chevronRight), + // ), + // ListTile( + // onTap: () { + // Navigator.of(context).push(MaterialPageRoute( + // builder: (context) { + // return const MessageScreen(); + // }, + // )); + // }, + // leading: Icon(MdiIcons.messageOutline), + // title: const Text('Driver Message'), + // trailing: Icon(MdiIcons.chevronRight), + // ), + ListTile( onTap: () { Navigator.of(context).push(MaterialPageRoute( @@ -248,24 +253,12 @@ class _ProfileScreenState extends State { title: const Text('Term & Conditions'), trailing: Icon(MdiIcons.chevronRight), ), - ListTile( - onTap: () {}, - leading: Icon(MdiIcons.basketOutline), - title: const Text('Grocery List'), - trailing: Icon(MdiIcons.chevronRight), - ), - ListTile( - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return MapScreen(); - }, - )); - }, - leading: Icon(MdiIcons.basketOutline), - title: const Text('Map List'), - trailing: Icon(MdiIcons.chevronRight), - ), + // ListTile( + // onTap: () {}, + // leading: Icon(MdiIcons.basketOutline), + // title: const Text('Grocery List'), + // trailing: Icon(MdiIcons.chevronRight), + // ), ], ), ), diff --git a/lib/src/ui/splash/splash_screen.dart b/lib/src/ui/splash/splash_screen.dart index ef89b44..a5b068f 100644 --- a/lib/src/ui/splash/splash_screen.dart +++ b/lib/src/ui/splash/splash_screen.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:grocery_app/src/core/routes/routes.dart'; +import 'package:grocery_app/src/logic/provider/bottom_navbar_provider.dart'; import 'package:grocery_app/src/ui/onboarding/on_boarding_screen.dart'; import 'package:grocery_app/utils/constants/assets_constant.dart'; import 'package:grocery_app/utils/constants/shared_pref_utils.dart'; import 'package:grocery_app/utils/extensions/extensions.dart'; import 'package:grocery_app/utils/extensions/uicontext.dart'; +import 'package:provider/provider.dart'; class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @@ -14,6 +16,7 @@ class SplashScreen extends StatefulWidget { } class _SplashScreenState extends State { + couting() async { Future.delayed(const Duration(seconds: 3)).then((c) { Navigator.of(context).pushReplacement(MaterialPageRoute( @@ -27,6 +30,9 @@ class _SplashScreenState extends State { @override void initState() { Future.delayed(const Duration(seconds: 2), () async { + + Provider.of(context, listen: false) + .refreshToken(context); if (await SharedPrefUtils.isFreshInstall()) { context.clearAndPush(routePath: MyRoutes.ONBOARDING); } else { diff --git a/lib/utils/constants/shared_pref_utils.dart b/lib/utils/constants/shared_pref_utils.dart index bb22a09..18caf6d 100644 --- a/lib/utils/constants/shared_pref_utils.dart +++ b/lib/utils/constants/shared_pref_utils.dart @@ -1,5 +1,6 @@ // ignore_for_file: constant_identifier_names +import 'package:grocery_app/src/data/user_profile.dart'; import 'package:shared_preferences/shared_preferences.dart'; // Shared preference for the app to store data locally @@ -35,7 +36,43 @@ class SharedPrefUtils { static const String STORE_ID = "STORE_ID"; static const String REFRESH_TOKEN = "REFRESH_TOKEN"; - /// Set bearer authorization token + static const String KEY_NAME = "user_name"; + static const String KEY_LAST_NAME = "user_name"; + static const String KEY_EMAIL = "user_email"; + static const String KEY_PROFILE = "user_profile"; + + static Future saveUser({ + required UserProfile user, + }) async { + print("jdhsfhjdjfhg ${user.img}"); + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString(KEY_NAME, user.firstName ?? ""); + await prefs.setString(KEY_LAST_NAME, user.lastName ?? ""); + await prefs.setString(KEY_EMAIL, user.email ?? " "); + await prefs.setString(KEY_PROFILE, user.img ?? " "); + } + + static Future getUserName() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(KEY_NAME); + } + static Future getLastName() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(KEY_LAST_NAME); + } + + /// Get user email + static Future getUserEmail() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(KEY_EMAIL); + } + + /// Get user profile URL + static Future getUserProfile() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(KEY_PROFILE); + } + static Future setToken({required String authToken}) { _token = authToken; return SharedPreferences.getInstance() @@ -232,10 +269,7 @@ class SharedPrefUtils { return firstName!; } - static Future getLastName() async { - final sp = await SharedPreferences.getInstance(); - return sp.getString(LAST_NAME) ?? ""; - } + static Future getEmail() async { final sp = await SharedPreferences.getInstance(); @@ -247,11 +281,6 @@ class SharedPrefUtils { return sp.getString(PASSWORD) ?? ""; } - static Future getUsername() async { - final sp = await SharedPreferences.getInstance(); - return sp.getString(USER_NAME) ?? ""; - } - static Future getRandomInstruction() async { final sp = await SharedPreferences.getInstance(); return sp.getBool(INS_RANDOM) ?? true; diff --git a/lib/utils/constants/string_constant.dart b/lib/utils/constants/string_constant.dart index 0ba9697..e9fc296 100644 --- a/lib/utils/constants/string_constant.dart +++ b/lib/utils/constants/string_constant.dart @@ -2,10 +2,12 @@ class APPSTRING { //title static const String enterYourMobileNumber = "Enter Your Mobile Number"; static const String whatYourPhoneNumber = "What's your phone number?"; - static const String codeSentText = "A code will be send to verify your phone number"; + static const String codeSentText = + "A code will be send to verify your phone number"; static const String enterVerificationCode = "Enter Verification Code"; - static const String enterCode = "Enter the 6-digit code sent to you at ********8902"; + static const String enterCode = + "Enter the 6-digit code sent to you at ********8902"; static const String pleaseEnterYourFullName = "Please Enter Your Full Name"; //hint @@ -13,11 +15,16 @@ class APPSTRING { static const String firstNameHint = "First Name"; static const String lastNameHint = "last Name"; - static const String emailHint = "Email-ID"; + static const String emailHint = "Email-ID"; static const String addressHint = "Address"; //button static const String verifyButton = "Verify"; static const String continueBtn = "Continue"; - static const String appName = "Customer App"; + static const String appName = "Customer App"; + + static String userName = "user_name"; + static String userLastName = "user_name"; + static String emailName = "user_email"; + static String userProfile = "user_profile"; } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..7299b5c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,14 @@ #include "generated_plugin_registrant.h" +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..786ff5c 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index bb41b6b..670b8b7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,17 +6,21 @@ import FlutterMacOS import Foundation import connectivity_plus +import file_selector_macos import geolocator_apple import package_info_plus import path_provider_foundation import shared_preferences_foundation import sqflite +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 12ad738..69cb842 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,6 +121,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: @@ -209,6 +217,38 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4" + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" fixnum: dependency: transitive description: @@ -528,6 +568,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: b62d34a506e12bb965e824b6db4fbf709ee4589cf5d3e99b45ab2287b008ee0c + url: "https://pub.dev" + source: hosted + version: "0.8.12+20" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: "direct main" description: @@ -548,18 +652,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -604,10 +708,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" material_design_icons_flutter: dependency: "direct main" description: @@ -620,10 +724,18 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" nested: dependency: transitive description: @@ -864,6 +976,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + skeletonizer: + dependency: "direct main" + description: + name: skeletonizer + sha256: "0dcacc51c144af4edaf37672072156f49e47036becbc394d7c51850c5c1e884b" + url: "https://pub.dev" + source: hosted + version: "1.4.3" sky_engine: dependency: transitive description: flutter @@ -953,10 +1081,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" typed_data: dependency: transitive description: @@ -965,6 +1093,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + url: "https://pub.dev" + source: hosted + version: "6.3.14" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" uuid: dependency: transitive description: @@ -1009,10 +1201,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" web: dependency: transitive description: @@ -1046,5 +1238,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.4.4 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index ccfac7a..318e361 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,8 @@ dependencies: google_api_headers: fluttertoast: flutter_rating_stars: ^1.1.0 + url_launcher: ^6.3.1 + skeletonizer: ^1.4.3 @@ -61,7 +63,8 @@ dependencies: animations: ^2.0.1 animation_list: ^3.1.0 - + image_picker: any + shimmer: ^3.0.0 dev_dependencies: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index f7ec5d8..35fa88c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,17 @@ #include "generated_plugin_registrant.h" #include +#include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 27254a6..860aedc 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,7 +4,9 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus + file_selector_windows geolocator_windows + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST