Compare commits

...

10 Commits

Author SHA1 Message Date
Vaibhav
c246d1cbeb First commmit of RD App 2024-09-20 15:50:11 +05:30
a4160498e1 1)Common widget added 2024-09-16 17:22:40 +05:30
61553fd7f1 1) Added checkbox single or multiselect 2024-09-16 17:14:45 +05:30
545637e035 1)product manual api integration
2)order management implementation
2024-09-16 16:48:52 +05:30
174d7afa99 1)get all Place Order api integration done
2) single Place order api integration done
3) Refresh inidicator added
4)Caps Functionality added
2024-09-11 12:24:48 +05:30
e1d96ee34e new changes 2024-09-06 17:55:52 +05:30
50b0828726 first commit 2024-09-06 16:02:26 +05:30
215877afc4 1)Order Place api Integration
2)Confirm Order api Integration
3)get Oder api Integration
2024-09-06 14:39:40 +05:30
43413ac168 1)getProduct api Integration
2)getCategory wise product api integration
3)Category wise product filter added
2024-08-30 11:26:38 +05:30
7aa59ca145 1)User Login api Integrate
2)Forgot Password api Integrate
3)Change Password api Integrate and ChangePassword UI Create
2024-08-27 15:57:28 +05:30
63 changed files with 5409 additions and 949 deletions

View File

@ -1,4 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:label="cheminova" android:label="cheminova"
android:name="${applicationName}" android:name="${applicationName}"

BIN
assets/images/cart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,178 @@
import 'package:get/get.dart';
import '../models/product_model.dart';
import '../models/product_model1.dart';
class CartController extends GetxController {
var cartList = <Product>[].obs;
var cartCount = 0.obs;
var subtotal = 0.0.obs;
var gstTotal = 0.0.obs;
var grandTotal = 0.0.obs;
// Track the selected products
var selectedProducts = <Product>[].obs;
@override
void onInit() {
super.onInit();
// Initialize the cart list or other initializations if needed
initializeSelections();
}
void addToCart(Product product) {
var existingProduct = cartList.firstWhereOrNull((p) => p.id == product.id);
if (existingProduct != null) {
existingProduct.quantity++;
} else {
cartList.add(product);
}
cartCount.value = cartList.length;
updateTotalPrice();
}
void updateTotalPrice() {
double subTotal = 0.0;
double gstTotalAmount = 0.0;
for (var product in selectedProducts) {
subTotal += product.price * product.quantity;
gstTotalAmount += (product.price * product.quantity * (product.gst / 100));
}
subtotal.value = subTotal;
gstTotal.value = gstTotalAmount;
grandTotal.value = subtotal.value + gstTotal.value;
}
void increaseQuantity(Product product) {
final index = cartList.indexWhere((item) => item.id == product.id);
if (index != -1) {
cartList[index].quantity++;
if (selectedProducts.contains(cartList[index])) {
updateTotalPrice();
}
}
}
void decreaseQuantity(Product product) {
final index = cartList.indexWhere((item) => item.id == product.id);
if (index != -1 && cartList[index].quantity > 1) {
cartList[index].quantity--;
if (selectedProducts.contains(cartList[index])) {
updateTotalPrice();
}
}
}
void removeFromCart(Product product) {
cartList.removeWhere((item) => item.id == product.id);
selectedProducts.remove(product);
cartCount.value = cartList.length;
updateTotalPrice();
}
void toggleProductSelection(Product product, bool isSelected) {
if (isSelected) {
if (!selectedProducts.contains(product)) {
selectedProducts.add(product);
}
} else {
selectedProducts.remove(product);
}
updateTotalPrice();
}
void selectAllProducts(bool selectAll) {
if (selectAll) {
selectedProducts.assignAll(cartList);
} else {
selectedProducts.clear();
}
updateTotalPrice();
}
void initializeSelections() {
selectAllProducts(true);
}
}
// import 'package:get/get.dart';
// import '../models/product_model.dart';
// import 'package:collection/collection.dart';
//
// import '../models/product_model1.dart';
//
// class CartController extends GetxController {
//
// var cartList = <Product>[].obs;
// var cartCount = 0.obs;
// var subtotal = 0.0.obs;
// var gstTotal = 0.0.obs;
// var grandTotal = 0.0.obs;
//
// // Add item to cart
// void addToCart(Product product) {
// var existingProduct = cartList.firstWhereOrNull((p) => p.id == product.id);
// if (existingProduct != null) {
// // Update quantity if already in cart
// existingProduct.quantity++;
// } else {
// // Add new product to cart
// cartList.add(product);
// }
// cartCount.value = cartList.length;
// updateTotalPrice();
// }
//
// void updateTotalPrice() {
// double subTotal = 0.0;
// double gstTotalAmount = 0.0;
//
// for (var product in cartList.where((p) => p.selected)) {
// subTotal += product.price * product.quantity;
// gstTotalAmount += (product.price * product.quantity * (product.gst / 100));
// }
//
// subtotal.value = subTotal;
// gstTotal.value = gstTotalAmount;
// grandTotal.value = subtotal.value + gstTotal.value;
// }
//
// // Increase the quantity of a product
// void increaseQuantity(Product product) {
// final index = cartList.indexWhere((item) => item.id == product.id);
// if (index != -1) {
// cartList[index].quantity++;
// updateTotalPrice();
// }
// }
//
// // Decrease the quantity of a product
// void decreaseQuantity(Product product) {
// final index = cartList.indexWhere((item) => item.id == product.id);
// if (index != -1 && cartList[index].quantity > 1) {
// cartList[index].quantity--;
// updateTotalPrice();
// }
// }
//
// // Remove item from cart
// void removeFromCart(Product product) {
// cartList.removeWhere((item) => item.id == product.id);
// cartCount.value = cartList.length;
// updateTotalPrice();
// }
//
// // Toggle product selection
// void toggleProductSelection(Product product, bool isSelected) {
// final index = cartList.indexWhere((item) => item.id == product.id);
// if (index != -1) {
// cartList[index].selected = isSelected;
// updateTotalPrice();
// }
// }
// }

View File

@ -0,0 +1,63 @@
import 'package:cheminova/controller/get_single_placed_order_service.dart';
import 'package:cheminova/controller/place_order_controller.dart';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:get/get.dart';
import '../models/oder_place_model.dart';
import '../models/product_model1.dart';
import '../utils/log_service.dart';
import 'get_place_order_service.dart';
class GetPlacedOrderController extends GetxController {
final GetOrderPlacedService _getOrderPlacedService = GetOrderPlacedService();
final OrderPlacedController _orderPlacedController = Get.put(OrderPlacedController());
final GetSingleOrderPlacedService _getSingleOrderPlacedService = GetSingleOrderPlacedService();
var placedOrders = <PlacedOrderList>[].obs;
var products = <Product>[].obs;
var isLoading = false.obs;
@override
void onInit() {
super.onInit();
getOrders(); // Fetch the orders immediately on initialization
}
Future<void> getOrders() async {
final fetchedOrders = await _getOrderPlacedService.getPlacedOrders();
if (fetchedOrders != null && fetchedOrders.isNotEmpty) {
placedOrders.addAll(fetchedOrders);
//logger.w("Fetched orders: $fetchedOrders");
} else {
//logger.w("No orders fetched");
}
}
Future<void> searchOrder() async {
try {
isLoading.value = true;
final order = await _getSingleOrderPlacedService.getSinglePlacedOrder(placedOrders[0].id);
if (order != null) {
placedOrders.clear(); // Clear existing orders if needed
placedOrders.add(order);
} else {
// Handle order not found case
}
} catch (e) {
// Handle exceptions
} finally {
isLoading.value = false;
}
}
// Optional: Reset the pagination if needed
void resetPagination() {
_getOrderPlacedService.resetPagination();
placedOrders.clear(); // Clear existing data
getOrders(); // Fetch fresh data
}
}

View File

@ -0,0 +1,122 @@
import 'package:cheminova/models/place_order_list_model.dart';
import '../models/oder_place_model.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class GetOrderPlacedService {
int _currentPage = 1; // Initialize with the first page
//int _limit = 100; // Start with a fixed limit, can be adjusted
final List<PlacedOrderList> _allOrders = []; // To store all fetched orders
bool _hasMoreOrders = true; // To check if there are more orders to fetch
Future<List<PlacedOrderList>?> getPlacedOrders() async {
try {
while (_hasMoreOrders) {
// Construct the API URL with pagination parameters
String url = "api/rd-place-order?page=$_currentPage";
final response = await commonApiService<List<PlacedOrderList>>(
method: "GET",
url: url,
fromJson: (json) {
if (json['plcaedOrders'] != null) {
final List<PlacedOrderList> orders = (json['plcaedOrders'] as List)
.map((orderJson) => PlacedOrderList.fromJson(orderJson as Map<String, dynamic>))
.toList();
if (orders.isNotEmpty) {
_allOrders.addAll(orders);
_currentPage++;
// _limit += orders.length; // Adjust limit based on the number of fetched orders
} else {
_hasMoreOrders = false; // Stop fetching if no more orders are returned
}
return orders;
} else {
_hasMoreOrders = false; // Stop if there are no orders at all
return [];
}
},
);
if (response == null || response.isEmpty) {
_hasMoreOrders = false; // Stop fetching if the response is empty
}
}
return _allOrders;
} catch (e) {
showSnackbar(e.toString());
return null;
}
}
// Optional: Reset the pagination and orders when needed
void resetPagination() {
_currentPage = 1;
//_limit = 100; // Reset the limit to the initial value
_allOrders.clear(); // Clear the list of orders
_hasMoreOrders = true; // Reset the flag to allow fetching again
}
}
//
// import 'package:cheminova/models/place_order_list_model.dart';
//
// import '../models/oder_place_model.dart';
// import '../utils/common_api_service.dart';
// import '../utils/show_snackbar.dart';
//
// class GetOrderPlacedService {
// int _currentPage = 1; // Initialize with the first page
// int _limit = 10; // Fixed limit, you can change this as needed
// final List<PlacedOrderList> _allOrders = [];
// int? totalOrders ;
// Future<List<PlacedOrderList>?> getPlacedOrders() async {
// try {
// // Construct the API URL with pagination parameters
// String url = "/api/get-placed-order-pd?page=$_currentPage&limit=$_limit";
//
// final response = await commonApiService<List<PlacedOrderList>>(
// method: "GET",
// url: url,
// fromJson: (json) {
// if (json['plcaedOrders'] != null) {
// final List<PlacedOrderList> orders = (json['plcaedOrders'] as List)
// .map((orderJson) => PlacedOrderList.fromJson(orderJson as Map<String, dynamic>))
// .toList();
// // Automatically increase the page number for the next request
// if (orders.isNotEmpty) {
// _currentPage++;
// _limit+= orders.length;
//
// }
// return orders;
// } else {
// return [];
// }
// },
// );
//
// return response;
// } catch (e) {
// showSnackbar(e.toString());
// return null;
// }
// }
//
// // Optional: Reset the pagination when needed
// void resetPagination() {
// _currentPage = 1;
// _limit = 100;
// }
// }

View File

@ -0,0 +1,30 @@
import 'package:cheminova/models/place_order_list_model.dart'; // Import your model
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class GetSingleOrderPlacedService {
Future<PlacedOrderList?> getSinglePlacedOrder(String orderId) async {
try {
// Construct the API URL for the single placed order
String url = "/api/get-single-placed-order-pd/$orderId";
final response = await commonApiService<PlacedOrderList>(
method: "GET",
url: url,
fromJson: (json) {
if (json['singleOrder'] != null) {
// Convert the JSON response to a PlacedOrderList model
return PlacedOrderList.fromJson(json['singleOrder'] as Map<String, dynamic>);
} else {
throw Exception("Order not found"); // Throw an exception if not found
}
},
);
return response;
} catch (e) {
showSnackbar(e.toString());
return null;
}
}
}

View File

@ -1,10 +1,24 @@
import 'package:cheminova/controller/home_service.dart'; import 'package:cheminova/controller/home_service.dart';
import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/models/user_model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HomeController extends GetxController { class HomeController extends GetxController {
final HomeService homeService = HomeService(); final HomeService homeService = HomeService();
var user = Rxn<UserModel>();
UserModel? user;
// var userModel = UserModel(
// id: '',
// uniqueId: '',
// name: '',
// email: '',
// phone: '',
// role: '',
// sbu: '',
// createdAt: '',
// updatedAt: '',
// ).obs; // Observable for UserModel
@override @override
void onInit() { void onInit() {
@ -13,7 +27,84 @@ class HomeController extends GetxController {
} }
Future<void> getUser() async { Future<void> getUser() async {
user.value = await homeService.getUser(); try {
update(); print("Starting getUser function in controller");
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
print("Token from SharedPreferences: $token");
HomeService homeService = HomeService();
print("Calling homeService.getUser");
user = await homeService.getUser(token: token);
print("homeService.getUser completed. User: $user");
update();
if (user != null) {
print("User fetched successfully: $user");
} else {
print('Failed to fetch user data');
}
} catch (e) {
print("Error in getUser controller function: ${e.toString()}");
}
} }
} }
// import 'package:cheminova/controller/home_service.dart';
// import 'package:cheminova/models/user_model.dart';
// import 'package:get/get.dart';
// import 'package:shared_preferences/shared_preferences.dart';
//
// import '../notification_service.dart';
//
// class HomeController extends GetxController {
// final HomeService homeService = HomeService();
// NotificationServices notificationServices = NotificationServices();
//
//
//
// var userModel = UserModel(id: '', uniqueId: '', name: '', email: '', phone: '', role: '', sbu: '', createdAt: '', updatedAt: ''
//
// ).obs; // Observable for UserModel
//
// @override
// void onInit() {
// getUser();
// super.onInit();
// notificationServices.requestNotificationPermission();
// notificationServices.getDeviceToken().then((value) {
// print('Device Token: $value');
// fcmToken();
// });
// }
//
// Future<void> fcmToken() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
// String? token = prefs.getString('token');
// final fcmToken = await NotificationServices().getDeviceToken();
// print('fcmToken: $fcmToken');
// homeService.fcmToken({"fcmToken": fcmToken}, token!);
// }
//
// Future<void> getUser() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
//
// String? token = prefs.getString('token');
//
// userModel = (await homeService.getUser(token: token)) as dynamic;
//
//
// // if (userModel != null) {
// // if (userModel != null) {ddddd
// // userModel.value = userResponse as UserModel; // Update the userModel with API response
// // update(); // Notify GetX to rebuild widgets using GetBuilder/Obx
// // }
// }
// }
//

View File

@ -1,20 +1,54 @@
import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/models/user_model.dart';
import 'package:cheminova/utils/common_api_service.dart'; import 'package:cheminova/utils/common_api_service.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import '../utils/api_urls.dart';
class HomeService { class HomeService {
Future<UserModel?> getUser() async { Future<UserModel?> getUser({String? token}) async {
try { try {
final response = await commonApiService<UserModel>( print("Starting getUser method in HomeService");
print("Token: $token");
print("URL: ${ApiUrls.profileUrl}");
final response = await commonApiService<Map<String, dynamic>>(
method: "GET", method: "GET",
url: "/api/territorymanager/my-profile", url: ApiUrls.profileUrl,
fromJson: (json) => UserModel.fromJson(json), additionalHeaders: {
'Authorization': 'Bearer $token',
},
fromJson: (json) => json as Map<String, dynamic>,
); );
return response; print("Raw API response: $response");
if (response == null) {
print("API response is null");
showSnackbar("Failed to get a response from the server");
return null;
}
if (response['success'] != true) {
print("API call was not successful");
showSnackbar(response['message'] ?? "API call was not successful");
return null;
}
if (response['myData'] == null) {
print("myData is null in the response");
showSnackbar("User data not found in the response");
return null;
}
print("Attempting to create UserModel from myData");
final userModel = UserModel.fromJson(response['myData']);
print("UserModel created successfully: $userModel");
return userModel;
} catch (e) { } catch (e) {
showSnackbar(e.toString()); print("Error in getUser: ${e.toString()}");
showSnackbar("Error fetching user data: ${e.toString()}");
return null;
} }
return null;
} }
}
// ... keep the fcmToken method as it was
}

View File

@ -0,0 +1,45 @@
import 'dart:convert';
import 'package:cheminova/controller/place_order_service.dart';
import 'package:cheminova/models/product_model.dart';
import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/oder_place_model.dart';
class OrderPlacedController extends GetxController {
var placedOrder1 = PlacedOrderModel(
paymentMode: 'cheque',
shipTo: '456, Park Street, Kolkata, West Bengal - 700016',
billTo: '456, Park Street, Kolkata, West Bengal - 700016',
subtotal: 300,
gstTotal: 100,
grandTotal: 400,
orderItems: [
],
).obs;
var isLoading = false.obs;
final OrderPlacedService _orderPlacedService = OrderPlacedService();
Future<void> placeOrder() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
isLoading.value = true;
//try {
// Construct order details
PlacedOrderModel orderDetails = placedOrder1.value;
print("Order Details: $orderDetails");
// Call the service to place the order
await _orderPlacedService.placeOrder(orderDetails, token!);
}
// catch (e) {
//
// } finally {
// isLoading.value = false;
// }
}

View File

@ -0,0 +1,33 @@
import 'dart:convert';
import 'dart:developer';
import 'package:cheminova/models/product_model.dart';
import 'package:dio/dio.dart';
import '../models/oder_place_model.dart';
import '../utils/log_service.dart';
class OrderPlacedService {
final Dio dio = Dio();
Future<void> placeOrder(PlacedOrderModel orderDetails, String token) async {
//try {
// logger.w("orderjson ${jsonEncode(orderDetails.toJson())}");
final response = await dio.post(
'https://api.cnapp.co.in/api/rd-place-order',
// Ensure this is your correct endpoint
data: jsonEncode(orderDetails.toJson()),
options: Options(
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode != 201) {
throw Exception('Failed to place order');
}
}
}

View File

@ -0,0 +1,67 @@
import 'package:cheminova/controller/product_service.dart';
import 'package:cheminova/models/product_model1.dart';
import 'package:get/get.dart';
class ProductController extends GetxController {
final ProductService productService = ProductService();
var products = <Product>[].obs;
var categories = <String>[].obs; // Holds the list of categories
var selectedCategory = Rxn<String>(); // Holds the selected category
int _currentPage = 1;
bool isLoading = false;
@override
void onInit() {
super.onInit();
getCategory();
getUser();
}
Future<void> getUser() async {
if (isLoading) return;
isLoading = true;
try {
final category = selectedCategory.value; // Get the selected category
final fetchedProducts = await productService.getProduct(
_currentPage,
category: category,
);
if (fetchedProducts != null) {
// Directly add the fetched products (which are of type List<Product>) to the list
products.addAll(fetchedProducts);
print("fetchedProducts ,$fetchedProducts");
}
} catch (e) {
print("Error fetching products: $e");
} finally {
isLoading = false;
update();
}
}
Future<void> getCategory() async {
try {
final fetchedCategories = await productService.getCategory();
if (fetchedCategories != null) {
categories.assignAll(fetchedCategories.map((category) => category['categoryName'] as String));
categories.insert(0, 'All'); // Add "All" option
}
} catch (e) {
print("Error fetching categories: $e");
}
}
void setCategory(String category) {
selectedCategory.value = category == 'All' ? null : category;
_currentPage = 1;
products.clear();
getUser();
}
void loadMoreProducts() {
_currentPage++;
getUser();
}
}

View File

@ -0,0 +1,47 @@
import 'package:cheminova/controller/product_mannual_service.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/product_mannual_model.dart'; // Your model import
// Your service import
class ProductManualController extends GetxController {
var productManualList = <ProductManualModel>[].obs;
// Service to fetch data
final ProductMannualService productMannualService = ProductMannualService();
// Loading state
var isLoading = false.obs;
// Method to fetch product manuals from the service
void fetchProductManuals() async {
try {
// Set loading to true
isLoading.value = true;
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
var manuals = await productMannualService.getProductManuals(token!);
// If data is returned, update the list
if (manuals != null) {
productManualList.value = manuals;
} else {
productManualList.value = []; // If no data, set an empty list
}
} catch (e) {
// Handle error here, for example logging or showing an error message
print("Error fetching product manuals: $e");
} finally {
// Set loading to false
isLoading.value = false;
}
}
@override
void onInit() {
// Fetch product manuals when the controller is initialized
fetchProductManuals();
super.onInit();
}
}

View File

@ -0,0 +1,36 @@
import '../models/product_mannual_model.dart';
import '../utils/common_api_service.dart'; // Replace with your actual common API service import
class ProductMannualService {
Future<List<ProductManualModel>?> getProductManuals(String token) async {
try {
String url = "/api/productmanual/getall"; // Base URL to fetch product manuals
final response = await commonApiService<List<ProductManualModel>>(
method: "GET",
url: url,
additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token',
},
fromJson: (json) {
if (json['productManuals'] != null) {
// Map the list of product manuals from the response
final List<ProductManualModel> productManuals = (json['productManuals'] as List)
.map((manualJson) => ProductManualModel.fromJson(manualJson as Map<String, dynamic>))
.toList();
return productManuals;
} else {
return [];
}
},
);
return response;
} catch (e) {
print(e.toString());
return null;
}
}
}

View File

@ -0,0 +1,61 @@
import '../models/product_model1.dart';
import '../utils/common_api_service.dart';
import '../utils/show_snackbar.dart';
class ProductService {
Future<List<Product>?> getProduct(int page, {String? category}) async {
try {
String url;
if (category != null && category.isNotEmpty) {
url = "/api/product/getAll/user/?page=$page&category=$category";
} else {
url = "/api/product/getAll/user/?page=$page"; // URL without category filter
}
final response = await commonApiService<List<Product>>(
method: "GET",
url: url,
fromJson: (json) {
if (json['products'] != null) {
final List<Product> products = (json['products'] as List)
.map((productJson) => Product.fromJson(productJson as Map<String, dynamic>))
.toList();
return products;
} else {
return [];
}
},
);
return response;
} catch (e) {
// showSnackbar(e.toString());
return null;
}
}
Future<List<Map<String, dynamic>>?> getCategory() async {
try {
final response = await commonApiService<List<Map<String, dynamic>>>(
method: "GET",
url: "/api/category/getCategories",
fromJson: (json) {
if (json['categories'] != null) {
final List<Map<String, dynamic>> category = (json['categories'] as List)
.map((productJson) => productJson as Map<String, dynamic>)
.toList();
return category;
} else {
return [];
}
},
);
return response;
} catch (e) {
showSnackbar(e.toString());
print("Error: $e");
}
return null;
}
}

View File

@ -2,7 +2,7 @@ import 'package:cheminova/screens/splash_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
void main() { void main()async{
runApp(const MyApp()); runApp(const MyApp());
} }
@ -12,6 +12,7 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const GetMaterialApp( return const GetMaterialApp(
debugShowCheckedModeBanner: false,
home: SplashScreen(), home: SplashScreen(),
); );
} }

View File

@ -0,0 +1,23 @@
class AddedBy {
String id;
String name;
AddedBy({
required this.id,
required this.name,
});
factory AddedBy.fromJson(Map<String, dynamic> json) => AddedBy(
id: json["_id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"_id": id,
"name": name,
};
@override
String toString() {
return 'AddedBy(id: $id, brandName: $AddedBy,)';
}
}

View File

@ -0,0 +1,27 @@
class Brand {
final String id;
final String brandName;
Brand({
required this.id,
required this.brandName,
});
factory Brand.fromJson(Map<String, dynamic> json) {
return Brand(
id: json['_id'],
brandName: json['brandName'],
);
}
Map<String, dynamic> toJson() {
return {
'_id': id,
'brandName': brandName,
};
}
@override
String toString() {
return 'Brand(id: $id, brandName: $brandName,)';
}
}

View File

@ -0,0 +1,27 @@
// lib/models/cart_item.dart
import 'package:cheminova/models/product_model1.dart';
class CartItem {
final Product product;
int quantity;
CartItem({
required this.product,
this.quantity = 1,
});
// Method to increase quantity
void increaseQuantity() {
quantity++;
}
// Method to decrease quantity
void decreaseQuantity() {
if (quantity > 1) {
quantity--;
}
}
// Method to get total price of this item
int get totalPrice => product.price * quantity;
}

View File

@ -0,0 +1,27 @@
class Category {
final String id;
final String categoryName;
Category({
required this.id,
required this.categoryName,
});
factory Category.fromJson(Map<String, dynamic> json) {
return Category(
id: json['_id'],
categoryName: json['categoryName'],
);
}
Map<String, dynamic> toJson() {
return {
'_id': id,
'categoryName': categoryName,
};
}
@override
String toString() {
return 'Category(id: $id, categoryName: $categoryName,)';
}
}

View File

@ -0,0 +1,141 @@
import 'added_by_model.dart';
import 'brand_model.dart';
import 'category_model.dart';
class PlacedOrderModel {
String paymentMode;
String shipTo;
String billTo;
double subtotal;
double gstTotal;
double grandTotal;
List<OrderItem> orderItems;
PlacedOrderModel({
required this.paymentMode,
required this.shipTo,
required this.billTo,
required this.subtotal,
required this.gstTotal,
required this.grandTotal,
required this.orderItems,
});
Map<String, dynamic> toJson() => {
'paymentMode': paymentMode,
'shipTo': shipTo,
'billTo': billTo,
'subtotal': subtotal,
'gstTotal': gstTotal,
'grandTotal': grandTotal,
'orderItems': orderItems.map((item) => item.toJson()).toList(),
};
factory PlacedOrderModel.fromJson(Map<String, dynamic> json) => PlacedOrderModel(
paymentMode: json['paymentMode'],
shipTo: json['shipTo'],
billTo: json['billTo'],
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
grandTotal: json['grandTotal'].toDouble(),
orderItems: (json['orderItems'] as List).map((item) => OrderItem.fromJson(item)).toList(),
);
@override
String toString() {
return 'PlacedOrderModel{paymentMode: $paymentMode, '
'shipTo: $shipTo, '
'billTo: $billTo, '
'subtotal: $subtotal, '
'gstTotal: $gstTotal, '
'grandTotal: $grandTotal, '
'orderItems: ${orderItems.map((item) => item.toString()).join(', ')})';
}
}
class OrderItem {
String id;
String sku;
String name;
double price;
double gst;
int hsnCode;
String description;
String productStatus;
final String addedBy;
List<String> image;
DateTime createdAt;
DateTime updatedAt;
int count;
Category category;
Brand brand;
int v;
OrderItem({
required this.id,
required this.sku,
required this.name,
required this.price,
required this.gst,
required this.hsnCode,
required this.description,
required this.productStatus,
required this.addedBy,
required this.image,
required this.createdAt,
required this.updatedAt,
required this.count,
required this.category,
required this.brand,
required this.v,
});
// Adjusted toJson method to match the desired format
Map<String, dynamic> toJson() => {
'_id': id,
'SKU': sku,
'name': name,
'category': category.toJson(), // Ensure Category has a proper toJson method
'brand': brand.toJson(), // Ensure Brand has a proper toJson method
'price': price,
'GST': gst,
'HSN_Code': hsnCode,
'description': description,
'product_Status': productStatus,
'addedBy': {
'_id': id, // Assuming the addedBy is represented by the id
'name': addedBy // If addedBy is just a name, use it directly here
},
'image': image,
'createdAt': createdAt.toIso8601String(),
'updatedAt': updatedAt.toIso8601String(),
'__v': v,
'count': count,
};
factory OrderItem.fromJson(Map<String, dynamic> json) => OrderItem(
id: json['_id'],
sku: json['SKU'],
name: json['name'],
price: json['price'].toDouble(),
gst: json['GST'].toDouble(),
hsnCode: json['HSN_Code'],
description: json['description'],
productStatus: json['product_Status'],
addedBy: json['addedBy']['name'], // Assuming addedBy has a 'name' key
image: List<String>.from(json['image']),
createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']),
count: json['count'],
category: Category.fromJson(json['category']),
brand: Brand.fromJson(json['brand']),
v: json['__v'],
);
@override
String toString() {
return 'OrderItem(id: $id, sku: $sku, name: $name, price: $price, gst: $gst, hsnCode: $hsnCode, description: $description, productStatus: $productStatus, addedBy: $addedBy, image: $image, createdAt: $createdAt, updatedAt: $updatedAt, count: $count, category: $category, brand: $brand, v: $v)';
}
}

View File

@ -0,0 +1,51 @@
class PlaceOrderItem1 {
final String sku;
String? id;
List<String>? image;
final String name;
final String categoryName;
final String brandName;
final double price;
final int quantity;
PlaceOrderItem1({
required this.sku,
this.id,
this.image,
required this.name,
required this.categoryName,
required this.brandName,
required this.price,
required this.quantity,
});
factory PlaceOrderItem1.fromJson(Map<String, dynamic> json) {
return PlaceOrderItem1(
id: json['id'],
sku: json['SKU'],
name: json['name'],
categoryName: json['categoryName'],
brandName: json['brandName'],
price: json['price'].toDouble(),
quantity: json['quantity'], image: null,
);
}
Map<String, dynamic> toJson() {
return {
'SKU': sku,
'name': name,
'categoryName': categoryName,
'brandName': brandName,
'price': price,
'quantity': quantity,
};
}
@override
String toString() {
return 'OrderItem(sku: $sku, name: $name, categoryName: $categoryName, '
'brandName: $brandName, price: $price, quantity: $quantity)';
}
}

View File

@ -0,0 +1,136 @@
class PlacedOrderList {
final String id;
final String paymentMode;
final String shipTo;
final String billTo;
final List<OrderItem1> orderItem;
final double subtotal;
final double gstTotal;
final double grandTotal;
final String status;
final String addedBy;
final bool isCancelled;
final bool isDelivered;
final String deliveredDate;
final String uniqueId;
final DateTime createdAt;
final DateTime updatedAt;
PlacedOrderList({
required this.id,
required this.paymentMode,
required this.shipTo,
required this.billTo,
required this.orderItem,
required this.subtotal,
required this.gstTotal,
required this.grandTotal,
required this.status,
required this.addedBy,
required this.isCancelled,
required this.isDelivered,
required this.deliveredDate,
required this.uniqueId,
required this.createdAt,
required this.updatedAt,
});
factory PlacedOrderList.fromJson(Map<String, dynamic> json) {
return PlacedOrderList(
id: json['_id'],
paymentMode: json['paymentMode'],
shipTo: json['shipTo'],
billTo: json['billTo'],
orderItem: (json['orderItem'] as List)
.map((item) => OrderItem1.fromJson(item))
.toList(),
subtotal: json['subtotal'].toDouble(),
gstTotal: json['gstTotal'].toDouble(),
grandTotal: json['grandTotal'].toDouble(),
status: json['status'],
addedBy: json['addedBy'],
isCancelled: json['iscancelled'],
isDelivered: json['isDelivered'],
deliveredDate: json['DeliveredDate'],
uniqueId: json['uniqueId'],
createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']),
);
}
Map<String, dynamic> toJson() {
return {
'_id': id,
'paymentMode': paymentMode,
'shipTo': shipTo,
'billTo': billTo,
'orderItem': orderItem.map((item) => item.toJson()).toList(),
'subtotal': subtotal,
'gstTotal': gstTotal,
'grandTotal': grandTotal,
'status': status,
'addedBy': addedBy,
'iscancelled': isCancelled,
'isDelivered': isDelivered,
'DeliveredDate': deliveredDate,
'uniqueId': uniqueId,
'createdAt': createdAt.toIso8601String(),
'updatedAt': updatedAt.toIso8601String(),
};
}
@override
String toString() {
return 'PlacedOrderList(id: $id, paymentMode: $paymentMode, shipTo: $shipTo, billTo: $billTo, '
'orderItem: $orderItem, subtotal: $subtotal, gstTotal: $gstTotal, grandTotal: $grandTotal, '
'status: $status, addedBy: $addedBy, isCancelled: $isCancelled, isDelivered: $isDelivered, '
'deliveredDate: $deliveredDate, uniqueId: $uniqueId, createdAt: $createdAt, updatedAt: $updatedAt)';
}
}
class OrderItem1 {
final String sku;
final String name;
final String categoryName;
final String brandName;
final double price;
final int quantity;
OrderItem1({
required this.sku,
required this.name,
required this.categoryName,
required this.brandName,
required this.price,
required this.quantity,
});
factory OrderItem1.fromJson(Map<String, dynamic> json) {
return OrderItem1(
sku: json['SKU'],
name: json['name'],
categoryName: json['categoryName'],
brandName: json['brandName'],
price: json['price'].toDouble(),
quantity: json['quantity'],
);
}
Map<String, dynamic> toJson() {
return {
'SKU': sku,
'name': name,
'categoryName': categoryName,
'brandName': brandName,
'price': price,
'quantity': quantity,
};
}
@override
String toString() {
return 'OrderItem(sku: $sku, name: $name, categoryName: $categoryName, '
'brandName: $brandName, price: $price, quantity: $quantity)';
}
}

View File

@ -0,0 +1,120 @@
class ProductManualModel {
final String id;
final String title;
final ProductManualDetails productManual;
final String createdAt;
final String updatedAt;
ProductManualModel({
required this.id,
required this.title,
required this.productManual,
required this.createdAt,
required this.updatedAt,
});
// Factory method to create a ProductManualModel from JSON
factory ProductManualModel.fromJson(Map<String, dynamic> json) {
return ProductManualModel(
id: json['_id'] ?? '',
title: json['title'] ?? '',
productManual: ProductManualDetails.fromJson(json['product_manual']),
createdAt: json['createdAt'],
updatedAt: json['updatedAt'],
);
}
// Method to convert a ProductManualModel to JSON
Map<String, dynamic> toJson() {
return {
'_id': id,
'title': title,
'product_manual': productManual.toJson(),
'createdAt': createdAt,
'updatedAt': updatedAt,
};
}
// Override toString for better debugging
@override
String toString() {
return 'ProductManualModel(id: $id, title: $title, productManual: $productManual, createdAt: $createdAt, updatedAt: $updatedAt)';
}
}
class ProductManualDetails {
final String publicId;
final String url;
final String filename;
ProductManualDetails({
required this.publicId,
required this.url,
required this.filename,
});
// Factory method to create ProductManualDetails from JSON
factory ProductManualDetails.fromJson(Map<String, dynamic> json) {
return ProductManualDetails(
publicId: json['public_id'] ?? '',
url: json['url'] ?? '',
filename: json['filename'] ?? '',
);
}
// Method to convert ProductManualDetails to JSON
Map<String, dynamic> toJson() {
return {
'public_id': publicId,
'url': url,
'filename': filename,
};
}
// Override toString for better debugging
@override
String toString() {
return 'ProductManualDetails(publicId: $publicId, url: $url, filename: $filename)';
}
}
// Model for handling the entire response
class ProductManualResponse {
final bool success;
final List<ProductManualModel> productManuals;
final int total;
ProductManualResponse({
required this.success,
required this.productManuals,
required this.total,
});
// Factory method to create ProductManualResponse from JSON
factory ProductManualResponse.fromJson(Map<String, dynamic> json) {
var productList = (json['productManuals'] as List)
.map((manual) => ProductManualModel.fromJson(manual))
.toList();
return ProductManualResponse(
success: json['success'] ?? false,
productManuals: productList,
total: json['total'] ?? 0,
);
}
// Method to convert ProductManualResponse to JSON
Map<String, dynamic> toJson() {
return {
'success': success,
'productManuals': productManuals.map((manual) => manual.toJson()).toList(),
'total': total,
};
}
// Override toString for better debugging
@override
String toString() {
return 'ProductManualResponse(success: $success, total: $total, productManuals: $productManuals)';
}
}

View File

@ -5,6 +5,8 @@ class ProductModel {
final String image; final String image;
final String description; final String description;
final double price; final double price;
String? category1;
String? brandname;
final ProductCategory category; final ProductCategory category;
final String id; final String id;
int quantity; int quantity;
@ -15,7 +17,39 @@ class ProductModel {
required this.description, required this.description,
required this.price, required this.price,
required this.category, required this.category,
this.category1,
this.brandname,
required this.id, required this.id,
this.quantity = 1, this.quantity = 1,
}); });
// Factory constructor
factory ProductModel.fromJson(Map<String, dynamic> json) {
return ProductModel(
name: json['name']??"",
image: json['image']??"",
description: json['description']??"",
price: json['price']??"",
category: ProductCategory.values.firstWhere((e) => e.toString().split('.').last == json['category']),
category1: json['category1']??"",
brandname: json['brandname']??"",
id: json['id'],
quantity: json['quantity'] ?? 1,
);
}
// Optional: toJson method if you need to convert the model back to JSON
Map<String, dynamic> toJson() {
return {
'name': name,
'image': image,
'description': description,
'price': price,
'category': category.toString().split('.').last,
'category1': category1,
'brandname': brandname,
'id': id,
'quantity': quantity,
};
}
} }

View File

@ -0,0 +1,118 @@
import 'brand_model.dart';
import 'category_model.dart';
class Product {
final String id;
final String sku;
final String name;
final Category category;
final Brand brand;
final int price;
int quantity;
bool selected;
final int gst;
final int hsnCode;
final String description;
final String productStatus;
final String addedBy;
final DateTime createdAt;
Product({
required this.id,
required this.sku,
required this.name,
required this.category,
required this.brand,
required this.price,
this.quantity =1,
this.selected=false,
required this.gst,
required this.hsnCode,
required this.description,
required this.productStatus,
required this.addedBy,
required this.createdAt,
});
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['_id'] as String,
sku: json['SKU'] as String,
name: json['name'] as String,
category:Category.fromJson(json['category'] as Map<String, dynamic>),
brand: Brand.fromJson(json['brand'] as Map<String, dynamic>),
price: json['price'] as int,
gst: json['GST'] as int,
hsnCode: json['HSN_Code'] as int,
description: json['description'] ?? '',
productStatus: json['product_Status'] as String,
addedBy: json['addedBy']['name'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
// Method to convert a Product to JSON
Map<String, dynamic> toJson() {
return {
'_id': id,
'SKU': sku,
'name': name,
'category':toJson(),
'brand':toJson(),
'price': price,
'GST': gst,
'HSN_Code': hsnCode,
'description': description,
'product_Status': productStatus,
'addedBy': {
'name': addedBy,
},
'createdAt': createdAt.toIso8601String(),
};
}
// Override toString method for easy printing of Product details
@override
String toString() {
return 'Product(id: $id, sku: $sku, name: $name, category: $category, '
'brand: $brand, price: $price, quantity: $quantity, gst: $gst, '
'hsnCode: $hsnCode, description: $description, productStatus: $productStatus, '
'addedBy: $addedBy, createdAt: $createdAt)';
}
}
// class Category {
// final String id;
// final String categoryName;
//
// Category({
// required this.id,
// required this.categoryName,
// });
//
// factory Category.fromJson(Map<String, dynamic> json) {
// return Category(
// id: json['_id'],
// categoryName: json['categoryName'],
// );
// }
// }
//
// class Brand {
// final String id;
// final String brandName;
//
// Brand({
// required this.id,
// required this.brandName,
// });
//
// factory Brand.fromJson(Map<String, dynamic> json) {
// return Brand(
// id: json['_id'],
// brandName: json['brandName'],
// );
// }
// }

View File

@ -1,37 +1,76 @@
class UserModel { class UserModel {
String id; final String id;
String name; final String uniqueId;
String uniqueId; final String name;
String email; final String email;
bool isVerified; final String mobileNumber;
final String designation;
final String userType;
final String? principalDistributer;
final String? addedBy;
final String? kyc;
final String? fcmToken;
final String createdAt;
final String updatedAt;
final String? mappedSC;
UserModel({ UserModel({
required this.id, required this.id,
required this.name,
required this.uniqueId, required this.uniqueId,
required this.name,
required this.email, required this.email,
required this.isVerified, required this.mobileNumber,
required this.designation,
required this.userType,
this.principalDistributer,
this.addedBy,
this.kyc,
this.fcmToken,
required this.createdAt,
required this.updatedAt,
this.mappedSC,
}); });
// Factory constructor to create an instance of UserModel from a JSON map
factory UserModel.fromJson(Map<String, dynamic> json) { factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel( return UserModel(
id: json['_id'] as String, id: json['_id'],
name: json['name'] as String, uniqueId: json['uniqueId'],
uniqueId: json['uniqueId'] as String, name: json['name'],
email: json['email'] as String, email: json['email'],
isVerified: json['isVerified'] as bool, mobileNumber: json['mobile_number'],
designation: json['designation'],
userType: json['userType'],
principalDistributer: json['principal_distributer'],
addedBy: json['addedBy'],
kyc: json['kyc'],
fcmToken: json['fcm_token'],
createdAt: json['createdAt'],
updatedAt: json['updatedAt'],
mappedSC: json['mappedSC'],
); );
} }
// Method to convert an instance of UserModel to a JSON map
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'_id': id, '_id': id,
'name': name,
'uniqueId': uniqueId, 'uniqueId': uniqueId,
'name': name,
'email': email, 'email': email,
'isVerified': isVerified, 'mobile_number': mobileNumber,
'designation': designation,
'userType': userType,
'principal_distributer': principalDistributer,
'addedBy': addedBy,
'kyc': kyc,
'fcm_token': fcmToken,
'createdAt': createdAt,
'updatedAt': updatedAt,
'mappedSC': mappedSC,
}; };
} }
}
@override
String toString() {
return 'UserModel{id: $id, uniqueId: $uniqueId, name: $name, email: $email, mobileNumber: $mobileNumber, designation: $designation, userType: $userType, principalDistributer: $principalDistributer, addedBy: $addedBy, kyc: $kyc, fcmToken: $fcmToken, createdAt: $createdAt, updatedAt: $updatedAt, mappedSC: $mappedSC}';
}
}

View File

@ -0,0 +1,117 @@
import 'package:cheminova/controller/home_controller.dart';
import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import '../../widgets/comman_background.dart';
import '../../widgets/common_appbar.dart';
class ProfileScreen extends StatefulWidget {
// String? name;
// final String uniqueId;
// final String email;
// final String mobileNumber;
// final String designation;
const ProfileScreen({
Key? key,
}) : super(key: key);
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
final homecontroller = Get.put(HomeController());
@override
Widget build(BuildContext context) {
final user = homecontroller!.user;
return Stack(
children: [
CommonBackground(
isFullWidth: true,
child: Scaffold(
drawer: MyDrawer(),
backgroundColor: Colors.transparent,
appBar: CommonAppBar(
title: const Text('Profile'),
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: SvgPicture.asset(
'assets/svg/back_arrow.svg',
),
padding: const EdgeInsets.only(right: 20),
),
],
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
padding: const EdgeInsets.all(20.0)
.copyWith(top: 15, bottom: 30),
margin: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 20.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
color: const Color(0xffB4D1E5).withOpacity(0.9),
borderRadius: BorderRadius.circular(26.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
_buildProfileItem('Name', user!.name),
_buildProfileItem('ID', user.uniqueId),
_buildProfileItem('Email ID', user.email),
// _buildProfileItem('Mobile Number', user.phone),
// _buildProfileItem('Designation', user.role),
],
),
),
],
),
),
),
),
],
);
}
Widget _buildProfileItem(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xff004791),
),
),
const SizedBox(height: 5),
Text(
value,
style: const TextStyle(
fontSize: 18,
color: Colors.black,
),
),
const Divider(color: Colors.grey),
],
),
);
}
}

View File

@ -0,0 +1,181 @@
import 'package:cheminova/widgets/custom_button.dart';
import 'package:cheminova/widgets/input_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../utils/show_snackbar.dart';
import 'controller/auth_controller.dart';
class ChangePasswordScreen extends StatefulWidget {
const ChangePasswordScreen({super.key});
@override
State<ChangePasswordScreen> createState() => _ChangePasswordScreenState();
}
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final authController = Get.put(AuthController());
void dispose() {
authController.currentpassController.dispose();
authController.newpassController.dispose();
authController.confirmpassController.dispose();
super.dispose();
}
void validateAndChangePassword() async {
String oldPassword = authController.currentpassController.text.trim();
String newPassword = authController.newpassController.text.trim();
String confirmPassword = authController.confirmpassController.text.trim();
if (newPassword.isEmpty || confirmPassword.isEmpty || oldPassword.isEmpty) {
showSnackbar('All fields are required');
return;
}
if (newPassword.length < 8) {
showSnackbar('Password must be at least 8 characters long');
return;
}
if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(newPassword)) {
showSnackbar('Password must contain at least one special character');
return;
}
if (newPassword != confirmPassword) {
showSnackbar('New Password and Confirm Password do not match');
return;
}
authController.changePassword();
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: 20,
height: 20,
child: SvgPicture.asset('assets/svg/menu.svg')),
),
),
actions: [
GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset('assets/svg/back_arrow.svg'),
),
),
],
),
body: Stack(
alignment: Alignment.topCenter,
children: [
Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage(
'assets/images/image_1.png',
),
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(50.0),
bottomRight: Radius.circular(50.0),
),
),
child: SizedBox(
width: Get.width,
height: Get.height * 0.7,
),
),
Center(
child: SingleChildScrollView(
child: Card(
margin: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19),
side: const BorderSide(color: Color(0xFFFDFDFD)),
),
color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Container(
padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft,
child: Text(
'Change Password',
style: GoogleFonts.getFont(
'Roboto',
fontWeight: FontWeight.w500,
fontSize: 30,
height: 1.2,
),
),
),
InputField(
hintText: "Current Password",
labelText: "Current Password",
controller: authController.currentpassController,
obscureText: false,
keyboardType: TextInputType.text,
),
const SizedBox(height: 15),
InputField(
hintText: "New Password",
labelText: "New Password",
obscureText: false,
controller: authController.newpassController,
keyboardType: TextInputType.text,
),
const SizedBox(height: 15),
InputField(
hintText: "Confirm Password",
labelText: "Confirm Password",
obscureText: false,
controller: authController.confirmpassController,
keyboardType: TextInputType.text,
),
const SizedBox(height: 30),
CustomButton(
text: "RESET PASSWORD",
onPressed: () async {
validateAndChangePassword();
},
isLoading: authController.isLoading.value,
)
],
),
),
),
),
),
],
),
);
}
}

View File

@ -1,7 +1,9 @@
import 'package:cheminova/screens/authentication/controller/auth_service.dart'; import 'package:cheminova/screens/authentication/controller/auth_service.dart';
import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthController extends GetxController { class AuthController extends GetxController {
final authService = AuthService(); final authService = AuthService();
@ -9,6 +11,10 @@ class AuthController extends GetxController {
TextEditingController emailController = TextEditingController(); TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController(); TextEditingController passwordController = TextEditingController();
TextEditingController phoneController = TextEditingController(); TextEditingController phoneController = TextEditingController();
TextEditingController currentpassController = TextEditingController();
TextEditingController newpassController = TextEditingController();
TextEditingController confirmpassController = TextEditingController();
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
Future<void> login() async { Future<void> login() async {
@ -20,7 +26,60 @@ class AuthController extends GetxController {
isLoading.value = false; isLoading.value = false;
update(); update();
if (response != null) { if (response != null) {
showSnackbar("Your Successfully logged In!");
Get.offAll(() => const HomeScreen()); Get.offAll(() => const HomeScreen());
} }
else if(response == null){
showSnackbar("Please Enter Valid Email or Password");
}
} }
Future<void> forgotpass() async{
isLoading.value = true;
final response = await authService.forgotPassword(
{
'email': emailController.text,
}
);
isLoading.value = false;
update();
if(response != null){
showSnackbar("Email sent successfully");
}
}
Future<void> changePassword() async {
isLoading.value = true;
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
if (token != null) {
final response = await authService.changePassword(
{
'oldPassword': currentpassController.text,
'newPassword': newpassController.text,
'confirmPassword': confirmpassController.text,
},
token: token, // Pass the token here
);
print("tokemn ,$token");
isLoading.value = false;
update();
if (response != null) {
Get.snackbar('Success', 'Password changed successfully');
} else {
Get.snackbar('Error', 'Failed to change password');
}
} else {
isLoading.value = false;
update();
Get.snackbar('Error', 'Token not found. Please login again.');
}
}
} }

View File

@ -5,7 +5,7 @@ class AuthService {
Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async { Future<Map<String, dynamic>?> login(Map<String, dynamic> data) async {
try { try {
final response = await commonApiService<Map<String, dynamic>>( final response = await commonApiService<Map<String, dynamic>>(
url: '/api/territorymanager/login', url: '/api/rd-login',
method: 'POST', method: 'POST',
body: data, body: data,
fromJson: (json) => json, // Simply return the JSON map as is fromJson: (json) => json, // Simply return the JSON map as is
@ -16,4 +16,41 @@ class AuthService {
} }
return null; return null;
} }
Future<Map<String, dynamic>?> forgotPassword(Map<String, dynamic> data) async {
try {
final response = await commonApiService<Map<String, dynamic>>(
url: '/api/forgot-password',
method: 'POST',
body: data,
fromJson: (json) => json, // Simply return the JSON map as is
);
return response;
} catch (e) {
showSnackbar(e.toString());
}
return null;
}
Future<Map<String, dynamic>?> changePassword(Map<String, dynamic> data, {required String token}) async {
try {
final response = await commonApiService<Map<String, dynamic>>(
url: '/api/rd-password/update',
method: 'PUT',
body: data,
fromJson: (json) => json, // Simply return the JSON map as is
additionalHeaders: { // Pass the token here
'Authorization': 'Bearer $token',
},
);
return response;
} catch (e) {
showSnackbar(e.toString());
}
return null;
}
} }

View File

@ -5,6 +5,8 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'controller/auth_controller.dart';
class ForgetPasswordScreen extends StatefulWidget { class ForgetPasswordScreen extends StatefulWidget {
const ForgetPasswordScreen({super.key}); const ForgetPasswordScreen({super.key});
@ -15,6 +17,7 @@ class ForgetPasswordScreen extends StatefulWidget {
class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> { class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
final userNameController = TextEditingController(); final userNameController = TextEditingController();
final passwordController = TextEditingController(); final passwordController = TextEditingController();
final authController = Get.put(AuthController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -107,7 +110,7 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
InputField( InputField(
hintText: "Email", hintText: "Email",
labelText: "Email", labelText: "Email",
controller: userNameController, controller: authController.emailController,
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
@ -125,7 +128,12 @@ class _ForgetPasswordScreenState extends State<ForgetPasswordScreen> {
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
CustomButton(text: "Send", onPressed: () {}), CustomButton(text: "Send",
onPressed: () => authController.forgotpass(),
isLoading: authController.isLoading.value,
),
], ],
), ),
), ),

View File

@ -1,13 +1,12 @@
import 'dart:ui';
import 'package:cheminova/screens/authentication/controller/auth_controller.dart';
import 'package:cheminova/screens/authentication/forget_password_screen.dart';
import 'package:cheminova/screens/authentication/verify_phone_screen.dart';
import 'package:cheminova/widgets/custom_button.dart';
import 'package:cheminova/widgets/input_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../widgets/comman_text_from_filed.dart';
import '../../widgets/custom_button.dart';
import 'controller/auth_controller.dart';
import 'forget_password_screen.dart';
// Make sure you import HomeScreen
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@ -19,6 +18,8 @@ class LoginScreen extends StatefulWidget {
class _LoginScreenState extends State<LoginScreen> { class _LoginScreenState extends State<LoginScreen> {
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
final authController = Get.put(AuthController()); final authController = Get.put(AuthController());
final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
final String passwordPattern = r'^.{6,}$'; // At least 6 characters
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -30,9 +31,7 @@ class _LoginScreenState extends State<LoginScreen> {
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(
fit: BoxFit.cover, fit: BoxFit.cover,
image: AssetImage( image: AssetImage('assets/images/image_1.png'),
'assets/images/image_1.png',
),
), ),
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(50.0), bottomLeft: Radius.circular(50.0),
@ -45,131 +44,159 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
SingleChildScrollView( SingleChildScrollView(
child: Column( child: Form(
mainAxisAlignment: MainAxisAlignment.center, key: formKey,
crossAxisAlignment: CrossAxisAlignment.center, child: Column(
children: [ mainAxisAlignment: MainAxisAlignment.center,
SizedBox(height: Get.height * 0.1), crossAxisAlignment: CrossAxisAlignment.center,
Container( children: [
margin: const EdgeInsets.symmetric(vertical: 20), SizedBox(height: Get.height * 0.1),
child: Text( Container(
'Welcome', margin: const EdgeInsets.symmetric(vertical: 20),
style: GoogleFonts.getFont( child: Text(
'Roboto', 'Welcome',
fontWeight: FontWeight.w400, style: GoogleFonts.getFont(
fontSize: 24, 'Roboto',
height: 1.5, fontWeight: FontWeight.w400,
color: const Color(0xFFFFFFFF), fontSize: 24,
height: 1.5,
color: const Color(0xFFFFFFFF),
),
), ),
), ),
), Container(
Container( decoration: BoxDecoration(
decoration: BoxDecoration( color: const Color(0xFFFFFFFF),
color: const Color(0xFFFFFFFF), borderRadius: BorderRadius.circular(14),
borderRadius: BorderRadius.circular(14), ),
),
child: Container(
width: Get.width * 0.7,
height: Get.height * 0.07,
padding: const EdgeInsets.all(10),
child: Container( child: Container(
decoration: const BoxDecoration( width: Get.width * 0.7,
image: DecorationImage( height: Get.height * 0.07,
fit: BoxFit.fill, padding: const EdgeInsets.all(10),
image: AssetImage( child: Container(
'assets/images/px_cheminova_svg.png', decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage(
'assets/images/px_cheminova_svg.png',
),
), ),
), ),
), ),
), ),
), ),
), SizedBox(height: Get.height * 0.05),
SizedBox(height: Get.height * 0.05), Card(
Card( margin: const EdgeInsets.symmetric(horizontal: 24),
margin: const EdgeInsets.symmetric(horizontal: 24), shape: RoundedRectangleBorder(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(19),
borderRadius: BorderRadius.circular(19), side: const BorderSide(color: Color(0xFFFDFDFD)),
side: const BorderSide(color: Color(0xFFFDFDFD)), ),
), color: const Color(0xFFB4D1E5).withOpacity(0.9),
color: const Color(0xFFB4D1E5).withOpacity(0.9), child: Padding(
child: Padding( padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16.0), child: Column(
child: Column( children: [
children: [ Container(
Container( alignment: Alignment.centerLeft,
alignment: Alignment.centerLeft, padding: const EdgeInsets.only(bottom: 10),
padding: const EdgeInsets.only(bottom: 10), child: SvgPicture.asset(
child: SvgPicture.asset( 'assets/svg/login.svg',
'assets/svg/login.svg', height: Get.height * 0.05,
height: Get.height * 0.05,
),
),
Container(
padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft,
child: Text(
'Login',
style: GoogleFonts.getFont(
'Roboto',
fontWeight: FontWeight.w500,
fontSize: 30,
height: 1.2,
), ),
), ),
), Container(
Container( padding: const EdgeInsets.only(bottom: 10),
padding: const EdgeInsets.only(bottom: 10), alignment: Alignment.centerLeft,
alignment: Alignment.centerLeft, child: Text(
child: Text( 'Login',
'Sign in to Continue', style: GoogleFonts.getFont(
style: GoogleFonts.getFont( 'Roboto',
'Roboto', fontWeight: FontWeight.w500,
fontWeight: FontWeight.w300, fontSize: 30,
fontSize: 14, height: 1.2,
height: 1.8, ),
), ),
), ),
), Container(
InputField( padding: const EdgeInsets.only(bottom: 10),
hintText: "Email", alignment: Alignment.centerLeft,
labelText: "Email", child: Text(
controller: authController.emailController, 'Sign in to Continue',
keyboardType: TextInputType.emailAddress, style: GoogleFonts.getFont(
), 'Roboto',
InputField( fontWeight: FontWeight.w300,
hintText: "Password", fontSize: 14,
labelText: "Password", height: 1.8,
controller: authController.passwordController, ),
obscureText: true,
),
const SizedBox(height: 30),
GestureDetector(
onTap: () =>
Get.to(() => const ForgetPasswordScreen()),
child: Text(
'Forgot password?',
style: GoogleFonts.getFont(
'Roboto',
fontWeight: FontWeight.w400,
fontSize: 20,
height: 1,
letterSpacing: -0.2,
), ),
), ),
), CommonTextFormField(
const SizedBox(height: 30), controller: authController.emailController,
Obx( keyboardType: TextInputType.emailAddress,
() => CustomButton( validator: (value) {
text: "Login", if (value == null || value.isEmpty) {
onPressed: () => authController.login(), return 'Please enter your email id';
isLoading: authController.isLoading.value, }
if (!RegExp(emailPattern).hasMatch(value)) {
return 'Please Enter valid email';
}
return null;
},
title: 'Email',
label: "Email",
), ),
), const SizedBox(height: 15),
], CommonTextFormField(
controller: authController.passwordController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your password';
}
if (!RegExp(passwordPattern).hasMatch(value)) {
return 'Please Enter valid password';
}
return null;
},
obscureText: true,
title: 'Password',
maxLines: 1,
label: "Password",
),
const SizedBox(height: 30),
GestureDetector(
onTap: () =>
Get.to(() => const ForgetPasswordScreen()),
child: Text(
'Forgot password?',
style: GoogleFonts.getFont(
'Roboto',
fontWeight: FontWeight.w400,
fontSize: 20,
height: 1,
letterSpacing: -0.2,
),
),
),
const SizedBox(height: 30),
Obx(
() => CustomButton(
text: "Login",
onPressed: () {
if (formKey.currentState!.validate()) {
// Perform login action
authController.login();
}
},
isLoading: authController.isLoading.value,
),
),
],
),
), ),
), ),
), ],
], ),
), ),
), ),
], ],

View File

@ -85,7 +85,7 @@ class _HomeScreenState extends State<HomeScreen> {
HomeCard( HomeCard(
title: 'Order Management', title: 'Order Management',
onTap: () => Get.to( onTap: () => Get.to(
() => const OrderManagementScreen(), () => OrderManagementScreen(),
), ),
), ),
HomeCard( HomeCard(

View File

@ -1,36 +1,175 @@
import 'package:cheminova/models/product_model.dart'; import 'dart:ffi';
import 'package:cheminova/screens/order/order_confermation_screen.dart'; import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/widgets/input_field.dart'; import 'package:cheminova/models/added_by_model.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/models/category_model.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../controller/cart_controller.dart';
import '../../controller/place_order_controller.dart';
import '../../controller/place_order_service.dart';
import '../../controller/product_controller.dart';
import '../../controller/product_service.dart';
import '../../models/brand_model.dart';
import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
import '../../widgets/my_drawer.dart';
import '../../widgets/product_card.dart';
import 'order_confermation_screen.dart';
class CheckoutScreen extends StatefulWidget { class CheckoutScreen extends StatefulWidget {
const CheckoutScreen({super.key}); final Product? productModel;
PlacedOrderModel? placeOrder;
List<Product>? selectedProducts;
CheckoutScreen({super.key, this.productModel, this.placeOrder,this.selectedProducts});
@override @override
State<CheckoutScreen> createState() => _CheckoutScreenState(); State<CheckoutScreen> createState() => _CheckoutScreenState();
} }
class _CheckoutScreenState extends State<CheckoutScreen> { class _CheckoutScreenState extends State<CheckoutScreen> {
final TextEditingController _addressController = TextEditingController(); final CartController _cartController = Get.put(CartController());
final TextEditingController _contactController = TextEditingController(); final ProductService _productService = ProductService();
final ProductController _productController = Get.put(ProductController());
final OrderPlacedController _orderPlacedController =
Get.put(OrderPlacedController());
final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
final List<ProductModel> _checkoutList = [ int currentPage = 1;
ProductModel( String _groupValue = "cheque";
id: "1",
image: 'assets/images/product.png', final List<String> _addressList = [
name: "Product 1", 'Home - 123 Street, City',
category: ProductCategory.food, 'Office - 456 Avenue, City',
description: 'Product 1 description', 'Warehouse - 789 Blvd, City',
price: 100,
),
]; ];
String _groupValue = "Credit Card"; String? _selectedShippingAddress;
String? _selectedBillingAddress;
@override
void initState() {
super.initState();
// _getOrder();
_loadSelectedAddress();
_loadSelectedPaymentMode();
if (_addressList.isNotEmpty) {
_selectedShippingAddress = _addressList.first;
_selectedBillingAddress = _addressList.first;
}
}
void _saveSelectedAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('selectedShippingAddress', _selectedShippingAddress!);
await prefs.setString('selectedBillingAddress', _selectedBillingAddress!);
}
void _onShippingAddressChanged(String? value) {
setState(() {
_selectedShippingAddress = value;
});
_saveSelectedAddress();
}
void _onBillingAddressChanged(String? value) {
setState(() {
_selectedBillingAddress = value;
});
_saveSelectedAddress();
}
void _loadSelectedAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_selectedShippingAddress =
prefs.getString('selectedShippingAddress') ?? _addressList.first;
_selectedBillingAddress =
prefs.getString('selectedBillingAddress') ?? _addressList.first;
});
}
void _onPaymentModeChanged(String? value) {
setState(() {
_groupValue = value!;
});
_saveSelectedPaymentMode();
}
void _saveSelectedPaymentMode() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('selectedPaymentMode', _groupValue);
}
void _loadSelectedPaymentMode() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_groupValue = prefs.getString('selectedPaymentMode') ?? 'cheque';
});
}
// void _getOrder(){
// final details = _getPlacedOrderController.getOrder(widget.productModel!.id);
// print("dffgfg,$details");
// }
void _onPlaceOrder() async {
try {
// Map the cart items (Product) to OrderItem objects
List<OrderItem> orderItems = _cartController.selectedProducts.map<OrderItem>((product) {
return OrderItem(
id: product.id,
name: product.name,
price: product.price.toDouble(),
sku: product.sku,
gst: product.gst.toDouble(),
hsnCode: product.hsnCode,
description: product.description,
productStatus: product.productStatus,
image: [],
createdAt: product.createdAt,
updatedAt: product.createdAt,
count: product.quantity,
//category:product.category,
category:Category(id: product.category.id, categoryName: product.category.categoryName),
// brand:product.brand,
brand:Brand(id: product.brand.id, brandName: product.brand.brandName),
v: 0, addedBy: product.addedBy,
);
}).toList();
// Update the placedOrder1 value
_orderPlacedController.placedOrder1.value= PlacedOrderModel(
paymentMode: _groupValue,
shipTo: _selectedShippingAddress!,
billTo: _selectedBillingAddress!,
orderItems: orderItems,
gstTotal: _cartController.gstTotal.value,
grandTotal: _cartController.grandTotal.value,
subtotal: _cartController.subtotal.value,
);
await _orderPlacedController.placeOrder();
if (_orderPlacedController.isLoading.value) {
showSnackbar("Order Placed Successfully");
Get.to(() => OrderConfermationScreen(
placedOrder: _orderPlacedController.placedOrder1.value,
));
}
} catch (e) {
print("PlaceOrderScreen error: $e");
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -63,9 +202,7 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
), ),
), ),
], ],
title: const Text( title: const Text("Checkout"),
"Checkout",
),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(),
body: Stack( body: Stack(
@ -78,9 +215,7 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
SafeArea( SafeArea(
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(height: Get.height * 0.02),
height: Get.height * 0.02,
),
Card( Card(
margin: EdgeInsets.symmetric(horizontal: Get.width * 0.05), margin: EdgeInsets.symmetric(horizontal: Get.width * 0.05),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -106,15 +241,37 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
), ),
), ),
), ),
InputField( SizedBox(height: 5,),
hintText: 'Address:', DropdownButtonFormField<String>(
labelText: 'Address:', decoration: InputDecoration(
controller: _addressController, labelText: 'Shipping Address:',
hintText: 'Select Shipping Address',
border: OutlineInputBorder(),
),
value: _selectedShippingAddress,
items: _addressList.map((String address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
);
}).toList(),
onChanged: _onShippingAddressChanged,
), ),
InputField( SizedBox(height: Get.height * 0.02),
hintText: 'Contact:', DropdownButtonFormField<String>(
labelText: 'Contact:', decoration: InputDecoration(
controller: _contactController, labelText: 'Billing Address:',
hintText: 'Select Billing Address',
border: OutlineInputBorder(),
),
value: _selectedBillingAddress,
items: _addressList.map((String address) {
return DropdownMenuItem<String>(
value: address,
child: Text(address),
);
}).toList(),
onChanged: _onBillingAddressChanged,
), ),
Padding( Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
@ -136,42 +293,30 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
SizedBox( SizedBox(
height: Get.height * 0.035, height: Get.height * 0.035,
child: RadioListTile( child: RadioListTile(
title: const Text("Credit Card"), title: const Text("Cheque"),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
value: "Credit Card", value: "cheque",
groupValue: _groupValue, groupValue: _groupValue,
onChanged: (value) { onChanged: _onPaymentModeChanged,
setState(() {
_groupValue = value.toString();
});
},
), ),
), ),
SizedBox( SizedBox(
height: Get.height * 0.035, height: Get.height * 0.035,
child: RadioListTile( child: RadioListTile(
title: const Text("Net Banking"), title: const Text("Online transfer"),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
value: "Net Banking", value: "online-transfer",
groupValue: _groupValue, groupValue: _groupValue,
onChanged: (value) { onChanged: _onPaymentModeChanged,
setState(() {
_groupValue = value.toString();
});
},
), ),
), ),
SizedBox( SizedBox(
child: RadioListTile( child: RadioListTile(
title: const Text("Cash on Delivery"), title: const Text("Credit"),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
value: "Cash on Delivery", value: "credit",
groupValue: _groupValue, groupValue: _groupValue,
onChanged: (value) { onChanged: _onPaymentModeChanged,
setState(() {
_groupValue = value.toString();
});
},
), ),
), ),
], ],
@ -198,58 +343,83 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
child: Padding( child: Padding(
padding: EdgeInsets.all(Get.width * 0.02), padding: EdgeInsets.all(Get.width * 0.02),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, itemCount: _cartController.selectedProducts.length,
itemCount: 10, itemBuilder: (context, index) {
itemBuilder: (context, index) => final cartItem =
ProductCard( _cartController.cartList[index];
product: _checkoutList[0], return ProductCard(
isCheckout: true, productModel:_cartController.selectedProducts[index] ,
), isCheckout: true,
quantity: _cartController.cartList[0].quantity,
// ListTile(
// title: Text(cartItem.name ?? 'N/A'),
// subtitle: Text(
// 'Quantity: ${cartItem.quantity}'),
// trailing: Text(
// 'Price: \${cartItem.price.toStringAsFixed(2)}'),
// );
);},
), ),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.all(Get.width * 0.04), padding: EdgeInsets.all(Get.width * 0.02),
child: Text( child: Column(
'Total Price: ₹ 1000.00', crossAxisAlignment: CrossAxisAlignment.start,
style: GoogleFonts.roboto( children: [
fontSize: Get.width * 0.05, Row(
fontWeight: FontWeight.w700, mainAxisAlignment: MainAxisAlignment.spaceBetween,
color: Colors.black, children: [
), Text('Subtotal',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.subtotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('GST',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.gstTotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Amount',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.grandTotal.value.toStringAsFixed(2)}'),
],
),
],
), ),
), ),
], ],
), ),
), ),
], ],
), ),
), ),
), ),
SizedBox( SizedBox(height: 10.0,),
height: Get.height * 0.025, Row(
), mainAxisAlignment: MainAxisAlignment.center,
SizedBox( children: [
width: Get.width * 0.9, ElevatedButton(
height: Get.height * 0.06, onPressed: _onPlaceOrder,
child: ElevatedButton( style: ElevatedButton.styleFrom(
onPressed: () => foregroundColor: Colors.white,
Get.to(() => const OrderConfermationScreen()), backgroundColor: const Color(0xFF00784C),
style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(
foregroundColor: Colors.white, horizontal: Get.width * 0.20,
backgroundColor: const Color(0xFF00784C), vertical: Get.height * 0.02),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
),
), ),
child: const Text("Place Order"),
), ),
child: Text( ],
"Place Order",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w600,
),
),
),
), ),
], ],
), ),
@ -258,4 +428,4 @@ class _CheckoutScreenState extends State<CheckoutScreen> {
), ),
); );
} }
} }

View File

@ -1,4 +1,6 @@
import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/widgets/product_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -6,8 +8,16 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart';
import '../../controller/place_order_controller.dart';
import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
class OrderConfermationScreen extends StatefulWidget { class OrderConfermationScreen extends StatefulWidget {
const OrderConfermationScreen({super.key}); Product? productModel;
PlacedOrderModel? placedOrder;
List<Product>? selectedProducts;
OrderConfermationScreen({super.key,this.productModel,this.placedOrder,this.selectedProducts});
@override @override
State<OrderConfermationScreen> createState() => State<OrderConfermationScreen> createState() =>
@ -15,18 +25,28 @@ class OrderConfermationScreen extends StatefulWidget {
} }
class _OrderConfermationScreenState extends State<OrderConfermationScreen> { class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
final List<ProductModel> _checkoutList = [ final CartController _cartController = Get.put(CartController());
ProductModel( final OrderPlacedController _placedController = Get.put(OrderPlacedController());
id: "1", final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
image: 'assets/images/product.png', // final List<ProductModel> _checkoutList = [
name: "Product 1", // ProductModel(
category: ProductCategory.food, // id: "1",
description: 'Product 1 description', // image: 'assets/images/product.png',
price: 100.00, // name: "Product 1",
), // category: ProductCategory.food,
]; // description: 'Product 1 description',
// price: 100.00,
// ),
// ];
// void _getOrder(){
// final details = _getPlacedOrderController.getOrder();
// showSnackbar("Get Placed Order Sucessfully");
// print("dffgfg,$details");
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final orderItems = _placedController.placedOrder1;
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
@ -94,7 +114,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
"Order Number: 123456", "Order Number:1234",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -109,7 +129,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
'Order Summary', 'Order Summary',
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.w500, fontWeight: FontWeight.bold,
color: Colors.black, color: Colors.black,
), ),
), ),
@ -124,26 +144,45 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
padding: EdgeInsets.all(Get.width * 0.02), padding: EdgeInsets.all(Get.width * 0.02),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: 10, itemCount: _cartController.selectedProducts.length,
itemBuilder: (context, index) => itemBuilder: (context, index) =>
ProductCard( ProductCard(
product: _checkoutList[0], productModel:_cartController.selectedProducts[index],
isCheckout: true, isCheckout: true,
), ),
), ),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.all(Get.width * 0.04), padding: EdgeInsets.all(Get.width * 0.02),
child: Text( child: Column(
'Total Price: ₹ 1000.00', crossAxisAlignment: CrossAxisAlignment.start,
style: GoogleFonts.roboto( children: [
fontSize: Get.width * 0.05, Row(
fontWeight: FontWeight.w700, mainAxisAlignment: MainAxisAlignment.spaceBetween,
color: Colors.black, children: [
), Text('Subtotal',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.subtotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('GST',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.gstTotal.value.toStringAsFixed(2)}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Amount',style: TextStyle(fontWeight: FontWeight.bold)),
Text('${_cartController.grandTotal.value.toStringAsFixed(2)}'),
],
),
],
), ),
), ),
], ],
), ),
), ),
@ -161,32 +200,28 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
Card( Card(
child: SizedBox( child: SizedBox(
width: Get.width, width: Get.width,
height: Get.height * 0.2, height: Get.height * 0.1,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: TextField(
"Address: Lorem Ipsum is simply dummy text of the printing and typesetting industry", controller: TextEditingController(
style: GoogleFonts.roboto( text: widget.placedOrder!.shipTo,
fontSize: Get.width * 0.04, ),
fontWeight: FontWeight.w400, decoration: InputDecoration(
hintText: "Address : ${widget.placedOrder!.shipTo}",
hintStyle: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
),
border: OutlineInputBorder(),
), ),
), ),
), ),
Padding(
padding: const EdgeInsets.all(8.0), ]),
child: Text(
"Contact: +91 9123456789",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
),
),
),
],
),
), ),
), ),
Card( Card(
@ -196,7 +231,7 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
"Estimated Delivery Date: [Date]", "Estimated Delivery Date: ${widget.placedOrder!.orderItems[0].createdAt}",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -205,10 +240,12 @@ class _OrderConfermationScreenState extends State<OrderConfermationScreen> {
), ),
), ),
), ),
], ],
), ),
), ),
), ),
], ],
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/screens/order_management/order_status_update_screen.dart'; import 'package:cheminova/screens/order_management/order_status_update_screen.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/widgets/product_card.dart';
@ -6,24 +7,20 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart';
import '../../models/product_model1.dart';
class OrderFullfilmentScreen extends StatefulWidget { class OrderFullfilmentScreen extends StatefulWidget {
const OrderFullfilmentScreen({super.key}); //final Product? productModel;
PlacedOrderList? placedOrderList;
OrderFullfilmentScreen({super.key,this.placedOrderList});
@override @override
State<OrderFullfilmentScreen> createState() => _OrderFullfilmentScreenState(); State<OrderFullfilmentScreen> createState() => _OrderFullfilmentScreenState();
} }
class _OrderFullfilmentScreenState extends State<OrderFullfilmentScreen> { class _OrderFullfilmentScreenState extends State<OrderFullfilmentScreen> {
final List<ProductModel> _checkoutList = [ final CartController _cartController = Get.put(CartController());
ProductModel(
id: "1",
image: 'assets/images/image_1.png',
name: "Product 1",
category: ProductCategory.food,
description: 'Product 1 description',
price: 100,
),
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -153,7 +150,7 @@ class _OrderFullfilmentScreenState extends State<OrderFullfilmentScreen> {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: 10, itemCount: 10,
itemBuilder: (context, index) => ProductCard( itemBuilder: (context, index) => ProductCard(
product: _checkoutList[0], placedOrderList:widget.placedOrderList,
isCheckout: true, isCheckout: true,
), ),
), ),

View File

@ -1,32 +1,73 @@
import 'package:cheminova/models/product_model.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:cheminova/screens/order_management/order_fullfilment_screen.dart'; import 'package:cheminova/controller/get_order_placed_controller.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/models/oder_place_model.dart';
import 'package:cheminova/models/order_item_model.dart';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../../controller/cart_controller.dart';
import '../../models/product_model1.dart';
class OrderManagementDetailScreen extends StatefulWidget { class OrderManagementDetailScreen extends StatefulWidget {
const OrderManagementDetailScreen({super.key}); //final Product? productModel;
PlacedOrderList? placedOrderList;
PlacedOrderModel? placedOrderModel;
OrderManagementDetailScreen({super.key,this.placedOrderList,this.placedOrderModel});
@override @override
State<OrderManagementDetailScreen> createState() => State<OrderManagementDetailScreen> createState() =>
_OrderManagementDetailScreenState(); _OrderManagementDetailScreenState();
} }
class _OrderManagementDetailScreenState class _OrderManagementDetailScreenState
extends State<OrderManagementDetailScreen> { extends State<OrderManagementDetailScreen> {
final List<ProductModel> _checkoutList = [ final CartController _cartController = Get.put(CartController());
ProductModel( final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
id: "1", String formatDate(String apiDate) {
image: 'assets/images/image_1.png',
name: "Product 1", DateTime parsedDate = DateTime.parse(apiDate);
category: ProductCategory.food,
description: 'Product 1 description', String formattedDate = DateFormat('dd-MMM-yyyy').format(parsedDate);
price: 100,
), return formattedDate;
]; }
@override String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
Future<void> adduni()async {
final Set<String> uniqueOrderIds = {};
final List<PlacedOrderList> uniqueOrders = [];
for (var order in _getPlacedOrderController.placedOrders) {
if (uniqueOrderIds.add(order.uniqueId)) {
uniqueOrders.add(order);
}
}
final order = uniqueOrders[0];
// Combine product names into a single string
final productNames = order.orderItem
.map((item) => (item.name))
.join(', ');
final categotyName = order.orderItem
.map((item) => (item.categoryName))
.join(', ');
final quantity = order.orderItem
.map((item) => (item.quantity))
.join(', ');
}
@override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
@ -95,8 +136,8 @@ class _OrderManagementDetailScreenState
child: Text( child: Text(
"Order Summary", "Order Summary",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: Get.width * 0.04, fontSize: Get.width * 0.05,
fontWeight: FontWeight.w400, fontWeight: FontWeight.bold,
), ),
), ),
), ),
@ -106,12 +147,18 @@ class _OrderManagementDetailScreenState
child: Padding( child: Padding(
padding: padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0), const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text( child: Row(
"Order ID: 123456", mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: GoogleFonts.roboto( children: [
fontSize: Get.width * 0.04, Text(
fontWeight: FontWeight.w400, "Order ID:",
), style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text(widget.placedOrderList!.uniqueId),
],
), ),
), ),
), ),
@ -120,25 +167,37 @@ class _OrderManagementDetailScreenState
child: Padding( child: Padding(
padding: padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0), const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text( child: Row(
"Order Date: MM/DD/YYYY", mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: GoogleFonts.roboto( children: [
fontSize: Get.width * 0.04, Text(
fontWeight: FontWeight.w400, "Order Date: ",
), style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text(formatDate("${widget.placedOrderList!.createdAt}")),
],
), ),
), ),
), ),
SizedBox( SizedBox(
width: Get.width, width: Get.width,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: Text( child: Row(
"Total Price: ₹ Total", mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: GoogleFonts.roboto( children: [
fontSize: Get.width * 0.04, Text(
fontWeight: FontWeight.w400, "Total Amount: ",
), style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text("${widget.placedOrderList!.grandTotal}"),
],
), ),
), ),
), ),
@ -153,11 +212,52 @@ class _OrderManagementDetailScreenState
padding: EdgeInsets.all(Get.width * 0.02), padding: EdgeInsets.all(Get.width * 0.02),
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: 10, itemCount: widget.placedOrderList?.orderItem.length ?? 0,
itemBuilder: (context, index) => ProductCard( itemBuilder: (context, index) {
product: _checkoutList[0], final orderItem = widget.placedOrderList!.orderItem[index];
isCheckout: true, return orderItem != null
), ? Card(
margin: const EdgeInsets.symmetric(vertical: 5.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Image.asset(
"assets/images/product.png", // Add the image URL here
height: 50,
width: 50,
fit: BoxFit.cover,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
capitalizeFirstLetter(orderItem.name),
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.bold,
),
),
Text(
"Quantity: ${orderItem.quantity}",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.03,
),
),
],
),
),
],
),
),
)
: const SizedBox.shrink();
},
), ),
), ),
), ),
@ -182,31 +282,38 @@ class _OrderManagementDetailScreenState
), ),
SizedBox( SizedBox(
width: Get.width, width: Get.width,
height: Get.height*0.06,
child: Padding( child: Padding(
padding: padding:
const EdgeInsets.fromLTRB(8, 8, 8, 0), const EdgeInsets.fromLTRB(8, 8, 8, 0),
child: Text( child: Row(
"Address: Hyderabad", children: [
style: GoogleFonts.roboto( Text(
fontSize: Get.width * 0.04, "Address: ",
fontWeight: FontWeight.w400, style: GoogleFonts.roboto(
), fontSize: Get.width * 0.04,
), fontWeight: FontWeight.bold,
), ),
), ),
SizedBox( AutoSizeText("${widget.placedOrderList!.shipTo}",maxLines: 4,
width: Get.width, overflow:TextOverflow.ellipsis,)
child: Padding( ],
padding: const EdgeInsets.all(8.0),
child: Text(
"Contact: +91 9123456789",
style: GoogleFonts.roboto(
fontSize: Get.width * 0.04,
fontWeight: FontWeight.w400,
),
), ),
), ),
), ),
// SizedBox(
// width: Get.width,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: Text(
// "Contact: +91 9123456789",
// style: GoogleFonts.roboto(
// fontSize: Get.width * 0.04,
// fontWeight: FontWeight.w400,
// ),
// ),
// ),
// ),
], ],
), ),
), ),
@ -216,12 +323,17 @@ class _OrderManagementDetailScreenState
width: Get.width, width: Get.width,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Text( child: Row(
"Status: Processing/ Shipped/ Delivered", children: [
style: GoogleFonts.roboto( Text(
fontSize: Get.width * 0.04, "Status: ",
fontWeight: FontWeight.w600, style: GoogleFonts.roboto(
), fontSize: Get.width * 0.04,
fontWeight: FontWeight.w600,
),
),
Text(capitalizeFirstLetter("${widget.placedOrderList!.status}")),
],
), ),
), ),
), ),
@ -231,29 +343,31 @@ class _OrderManagementDetailScreenState
), ),
), ),
SizedBox(height: Get.height * 0.04), SizedBox(height: Get.height * 0.04),
SizedBox( // SizedBox(
width: Get.width * 0.9, // width: Get.width * 0.9,
height: Get.height * 0.06, // height: Get.height * 0.06,
child: ElevatedButton( // child: ElevatedButton(
onPressed: () => Get.to( // onPressed: () => Get.to(
() => const OrderFullfilmentScreen(), // () => OrderFullfilmentScreen(
), // placedOrderList:widget.placedOrderList ,
style: ElevatedButton.styleFrom( // ),
foregroundColor: Colors.white, // ),
backgroundColor: const Color(0xFF00784C), // style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( // foregroundColor: Colors.white,
borderRadius: BorderRadius.circular(10), // backgroundColor: const Color(0xFF00784C),
), // shape: RoundedRectangleBorder(
), // borderRadius: BorderRadius.circular(10),
child: Text( // ),
"Fulfill Order", // ),
style: GoogleFonts.roboto( // child: Text(
fontSize: Get.width * 0.04, // "Fulfill Order",
fontWeight: FontWeight.w600, // style: GoogleFonts.roboto(
), // fontSize: Get.width * 0.04,
), // fontWeight: FontWeight.w600,
), // ),
), // ),
// ),
// ),
], ],
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/screens/order_management/order_management_detail_screen.dart'; import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
import 'package:cheminova/widgets/input_field.dart'; import 'package:cheminova/widgets/input_field.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
@ -5,9 +6,16 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import '../../controller/cart_controller.dart';
import '../../controller/get_order_placed_controller.dart';
import '../../models/product_model1.dart';
class OrderManagementScreen extends StatefulWidget { class OrderManagementScreen extends StatefulWidget {
const OrderManagementScreen({super.key}); final Product? productModel;
PlacedOrderList? placeOrder;
OrderManagementScreen({super.key, this.productModel, this.placeOrder});
@override @override
State<OrderManagementScreen> createState() => _OrderManagementScreenState(); State<OrderManagementScreen> createState() => _OrderManagementScreenState();
@ -15,10 +23,39 @@ class OrderManagementScreen extends StatefulWidget {
class _OrderManagementScreenState extends State<OrderManagementScreen> { class _OrderManagementScreenState extends State<OrderManagementScreen> {
final _searchController = TextEditingController(); final _searchController = TextEditingController();
final List<String> _filterList = [ final List<String> _filterList = ["Order Status", "Date Range"];
"Order Status",
"Date Range", final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
]; final CartController _cartController = Get.put(CartController());
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
GlobalKey<RefreshIndicatorState>();
@override
void initState() {
super.initState();
getOrder1();
}
Future<void> _onRefresh() async {
await getOrder1();
await Future.delayed(Duration(seconds: 1));
}
Future<void> getOrder1() async {
await _getPlacedOrderController.getOrders();
print("Order fetched successfully");
}
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
String formatDate(String apiDate) {
DateTime parsedDate = DateTime.parse(apiDate);
String formattedDate = DateFormat('dd-MMM-yyyy').format(parsedDate);
return formattedDate;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -34,9 +71,7 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
onTap: () => Scaffold.of(context).openDrawer(), onTap: () => Scaffold.of(context).openDrawer(),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset( child: SvgPicture.asset('assets/svg/menu.svg'),
'assets/svg/menu.svg',
),
), ),
); );
}, },
@ -46,169 +81,190 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
onTap: () => Get.back(), onTap: () => Get.back(),
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset( child: SvgPicture.asset('assets/svg/back_arrow.svg'),
'assets/svg/back_arrow.svg',
),
), ),
), ),
], ],
title: const Text( title: const Text("Order Management"),
"Order Management",
),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(),
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
Image.asset( Image.asset('assets/images/image_1.png', fit: BoxFit.cover),
'assets/images/image_1.png',
fit: BoxFit.cover,
),
SafeArea( SafeArea(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
bottom: MediaQuery.of(context).viewInsets.bottom), child: RefreshIndicator(
child: Column( key: _refreshIndicatorKey,
mainAxisSize: MainAxisSize.min, onRefresh: _onRefresh,
mainAxisAlignment: MainAxisAlignment.start, color: Colors.black,
children: [ backgroundColor: Colors.white,
InputField( child: Column(
hintText: "Search Order", mainAxisSize: MainAxisSize.min,
labelText: "Search Order", mainAxisAlignment: MainAxisAlignment.start,
controller: _searchController, children: [
), InputField(
SizedBox(height: Get.height * 0.035), hintText: "Search Order",
Card( labelText: "Search Order",
margin: const EdgeInsets.symmetric(horizontal: 18), controller: _searchController,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19),
side: const BorderSide(color: Color(0xFFFDFDFD)),
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), SizedBox(height: Get.height * 0.035),
child: Padding( Card(
padding: const EdgeInsets.all(12.0), margin: const EdgeInsets.symmetric(horizontal: 18),
child: Column( shape: RoundedRectangleBorder(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(19),
children: [ side: const BorderSide(color: Color(0xFFFDFDFD)),
SizedBox( ),
height: Get.height * 0.05, color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: ListView.builder( child: Padding(
shrinkWrap: true, padding: const EdgeInsets.all(12.0),
scrollDirection: Axis.horizontal, child: Column(
itemCount: _filterList.length, mainAxisSize: MainAxisSize.min,
itemBuilder: (context, index) => Padding( children: [
padding: SizedBox(
const EdgeInsets.symmetric(horizontal: 4), height: Get.height * 0.05,
child: Chip( child: ListView.builder(
label: Text( shrinkWrap: true,
_filterList[index], scrollDirection: Axis.horizontal,
style: GoogleFonts.roboto( itemCount: _filterList.length,
fontSize: 14, itemBuilder: (context, index) => Padding(
fontWeight: FontWeight.w500, padding: const EdgeInsets.symmetric(horizontal: 4),
child: Chip(
label: Text(
_filterList[index],
style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w500),
), ),
), ),
), ),
), ),
), ),
), SizedBox(
SizedBox( height: Get.height * 0.6,
height: Get.height * 0.6, child: Obx(() {
child: ListView.builder( // Use a set to keep track of unique order IDs
padding: EdgeInsets.zero, final Set<String> uniqueOrderIds = {};
shrinkWrap: true, final List<PlacedOrderList> uniqueOrders = [];
itemCount: 2,
itemBuilder: (context, index) => Padding( for (var order in _getPlacedOrderController.placedOrders) {
padding: if (uniqueOrderIds.add(order.id)) {
const EdgeInsets.symmetric(vertical: 8), uniqueOrders.add(order);
child: Card( }
child: Column( }
crossAxisAlignment:
CrossAxisAlignment.start, return ListView.builder(
children: [ padding: EdgeInsets.zero,
Padding( shrinkWrap: true,
padding: const EdgeInsets.fromLTRB( itemCount: uniqueOrders.length,
16, 8, 8, 0), itemBuilder: (context, index) {
child: Text( final order = uniqueOrders[index];
"Order ID: 123456",
style: GoogleFonts.roboto( // Combine product names into a single string
fontSize: 14, final productNames = order.orderItem
fontWeight: FontWeight.w400, .map((item) => capitalizeFirstLetter(item.name))
), .join(', ');
),
), return Padding(
Padding( padding: const EdgeInsets.symmetric(vertical: 8),
padding: const EdgeInsets.fromLTRB( child: Card(
16, 8, 8, 0), child: Column(
child: Text( crossAxisAlignment: CrossAxisAlignment.start,
"Product Name: XYZ", children: [
style: GoogleFonts.roboto( Padding(
fontSize: 14, padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
fontWeight: FontWeight.w400, child: Row(
), mainAxisAlignment: MainAxisAlignment.start,
), children: [
), Text("Order ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Padding( Text("${order.uniqueId}")
padding: const EdgeInsets.fromLTRB( ],
16, 8, 8, 0),
child: Text(
"Order Date: MM/DD/YYYY",
style: GoogleFonts.roboto(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(
16, 8, 8, 8),
child: Text(
"Status: Processing/shipped/delivered",
style: GoogleFonts.roboto(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
SizedBox(
width: Get.width * 0.4,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () => Get.to(
() =>
const OrderManagementDetailScreen(),
),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor:
const Color(0xFF004791),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10),
), ),
), ),
child: Text( Padding(
"View Details", padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
style: GoogleFonts.roboto( child: Row(
fontSize: 14, crossAxisAlignment: CrossAxisAlignment.start, // Aligns the Column to the top of the Text
fontWeight: FontWeight.w400, children: [
Text(
"Product Names: ",
style: GoogleFonts.roboto(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // Aligns text to the right within the Column
children: [
const SizedBox(height: 4), // Adds a small space between the label and the product names
for (int i = 0; i < productNames.split(",").length; i++)
Text(
'${i + 1}. ${productNames.split(",")[i].trim()}', // Adds index and trims whitespace
textAlign: TextAlign.left, // Aligns text to the right
style: GoogleFonts.roboto(
fontSize: 14,
),
),
],
),
),
],
), ),
), ),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Order Date: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text(formatDate("${order.createdAt}"))
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Status: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
Text(capitalizeFirstLetter("${order.status}"))
],
),
),
SizedBox(
width: Get.width * 0.4,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () => Get.to(() => OrderManagementDetailScreen(
placedOrderList: uniqueOrders[index])),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF004791),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
child: Text("View Details", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
),
),
)
],
), ),
) ),
], );
), },
), );
), }),
), )
) ],
], ),
), ),
), ),
), ],
], ),
), ),
), ),
), ),
@ -218,3 +274,253 @@ class _OrderManagementScreenState extends State<OrderManagementScreen> {
); );
} }
} }
// import 'package:cheminova/controller/get_place_order_service.dart';
// import 'package:cheminova/controller/place_order_controller.dart';
// import 'package:cheminova/models/place_order_list_model.dart';
// import 'package:cheminova/screens/order_management/order_management_detail_screen.dart';
// import 'package:cheminova/widgets/input_field.dart';
// import 'package:cheminova/widgets/my_drawer.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_svg/svg.dart';
// import 'package:get/get.dart';
// import 'package:google_fonts/google_fonts.dart';
// import 'package:intl/intl.dart';
//
// import '../../controller/cart_controller.dart';
// import '../../controller/get_order_placed_controller.dart';
// import '../../models/product_model1.dart';
// import '../../models/oder_place_model.dart';
// import '../../utils/show_snackbar.dart'; // Ensure this import is correct
//
// class OrderManagementScreen extends StatefulWidget {
// final Product? productModel;
// PlacedOrderList? placeOrder;
// OrderManagementScreen({super.key, this.productModel, this.placeOrder});
//
// @override
// State<OrderManagementScreen> createState() => _OrderManagementScreenState();
// }
//
// class _OrderManagementScreenState extends State<OrderManagementScreen> {
// final _searchController = TextEditingController();
// final List<String> _filterList = ["Order Status", "Date Range"];
//
// final GetPlacedOrderController _getPlacedOrderController = Get.put(GetPlacedOrderController());
// final CartController _cartController = Get.put(CartController());
//
// @override
// void initState() {
// super.initState();
// getOrder1();
// }
//
// Future<void> getOrder1() async {
// await _getPlacedOrderController.getOrders();
// print("Order fetched successfully");
// }
//
// String capitalizeFirstLetter(String text) {
// if (text.isEmpty) return text;
// return text[0].toUpperCase() + text.substring(1).toLowerCase();
// }
//
// String formatDate(String apiDate) {
// DateTime parsedDate = DateTime.parse(apiDate);
// String formattedDate = DateFormat('dd-MMM-yyyy hh:mm:ss a').format(parsedDate);
// return formattedDate;
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// extendBodyBehindAppBar: true,
// appBar: AppBar(
// centerTitle: true,
// backgroundColor: Colors.transparent,
// elevation: 0,
// leading: Builder(
// builder: (context) {
// return GestureDetector(
// onTap: () => Scaffold.of(context).openDrawer(),
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SvgPicture.asset('assets/svg/menu.svg'),
// ),
// );
// },
// ),
// actions: [
// GestureDetector(
// onTap: () => Get.back(),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: SvgPicture.asset('assets/svg/back_arrow.svg'),
// ),
// ),
// ],
// title: const Text("Order Management"),
// ),
// drawer: const MyDrawer(),
// body: Stack(
// fit: StackFit.expand,
// children: [
// Image.asset('assets/images/image_1.png', fit: BoxFit.cover),
// SafeArea(
// child: SingleChildScrollView(
// child: Padding(
// padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// InputField(
// hintText: "Search Order",
// labelText: "Search Order",
// controller: _searchController,
// ),
// SizedBox(height: Get.height * 0.035),
// Card(
// margin: const EdgeInsets.symmetric(horizontal: 18),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(19),
// side: const BorderSide(color: Color(0xFFFDFDFD)),
// ),
// color: const Color(0xFFB4D1E5).withOpacity(0.9),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// SizedBox(
// height: Get.height * 0.05,
// child: ListView.builder(
// shrinkWrap: true,
// scrollDirection: Axis.horizontal,
// itemCount: _filterList.length,
// itemBuilder: (context, index) => Padding(
// padding: const EdgeInsets.symmetric(horizontal: 4),
// child: Chip(
// label: Text(
// _filterList[index],
// style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w500),
// ),
// ),
// ),
// ),
// ),
// SizedBox(
// height: Get.height * 0.6,
// child: Obx(() {
// return ListView.builder(
// padding: EdgeInsets.zero,
// shrinkWrap: true,
// itemCount: _getPlacedOrderController.placedOrders.length,
// itemBuilder: (context, index) {
// final order = _getPlacedOrderController.placedOrders[index];
//
// // Combine product names into a single string
// final productNames = order.orderItem
// .map((item) => capitalizeFirstLetter(item.name))
// .join(', ');
//
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 8),
// child: Card(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Order ID: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text("${order.id}")
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Product Names: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Expanded(
// child: Text(productNames,
// style: GoogleFonts.roboto(
// fontSize: 14,
// )),
// ),
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Order Date: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(formatDate("${order.createdAt}"))
// ],
// ),
// ),
// Padding(
// padding: const EdgeInsets.fromLTRB(16, 8, 8, 8),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text("Status: ", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.bold)),
// Text(capitalizeFirstLetter("${order.status}"))
// ],
// ),
// ),
// SizedBox(
// width: Get.width * 0.4,
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: ElevatedButton(
// onPressed: () => Get.to(() => OrderManagementDetailScreen(
// placedOrderList: _getPlacedOrderController.placedOrders[index])),
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF004791),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10)),
// ),
// child: Text("View Details", style: GoogleFonts.roboto(fontSize: 14, fontWeight: FontWeight.w400)),
// ),
// ),
// )
// ],
// ),
// ),
// );
// },
// );
// }),
// )
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// );
// }
// }
//

View File

@ -1,31 +1,58 @@
import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/screens/order/checkout_screen.dart'; import 'package:cheminova/screens/order/checkout_screen.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/widgets/product_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_core/get_core.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart';
import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart';
class CartScreen extends StatefulWidget { class CartScreen extends StatefulWidget {
const CartScreen({super.key}); Product? productModel;
PlacedOrderModel? placedOrder;
CartScreen({super.key, this.productModel, this.placedOrder});
@override @override
State<CartScreen> createState() => _CartScreenState(); State<CartScreen> createState() => _CartScreenState();
} }
class _CartScreenState extends State<CartScreen> { class _CartScreenState extends State<CartScreen> {
final List<ProductModel> _cartList = [ final CartController _cartController = Get.find<CartController>();
ProductModel(
id: "1", bool _selectAll = true; // Default to true to select all products
image: 'assets/images/product.png',
name: "Product 1", @override
category: ProductCategory.food, void initState() {
description: 'Product 1 description', super.initState();
price: 100, if (widget.productModel != null) {
), _cartController.addToCart(widget.productModel!);
]; }
// Ensure all products are pre-selected by default
_cartController.initializeSelections();
_checkIfAllSelected(); // Check if all products are selected by default
}
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_cartController.selectAllProducts(_selectAll);
});
}
void _checkIfAllSelected() {
// This function checks if all items are selected or not and updates _selectAll
setState(() {
_selectAll = _cartController.cartList.every(
(product) => _cartController.selectedProducts.contains(product),
);
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -57,8 +84,10 @@ class _CartScreenState extends State<CartScreen> {
), ),
), ),
], ],
title: const Text( title: const Center(
"Cart", child: Text(
"Cart",
),
), ),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(),
@ -70,81 +99,441 @@ class _CartScreenState extends State<CartScreen> {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
SafeArea( SafeArea(
child: Column( child: Obx(() {
children: [ if (_cartController.cartList.isEmpty) {
SizedBox( return Center(
height: Get.height * 0.02, child: Column(
), mainAxisAlignment: MainAxisAlignment.center,
Card( children: [
margin: const EdgeInsets.symmetric(horizontal: 18), Image.asset(
shape: RoundedRectangleBorder( 'assets/images/cart.png',
borderRadius: BorderRadius.circular(19), width: Get.width * 0.5,
side: const BorderSide(color: Color(0xFFFDFDFD)), height: Get.width * 0.5,
),
const SizedBox(height: 20),
Text(
'Your Cart is empty',
style: GoogleFonts.roboto(
fontSize: 24,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), );
child: Padding( }
padding: const EdgeInsets.all(12.0), return Column(
child: Column( children: [
mainAxisSize: MainAxisSize.min, SizedBox(
children: [ height: Get.height * 0.02,
SizedBox( ),
height: Get.height * 0.6, Card(
child: ListView.builder( margin: const EdgeInsets.symmetric(horizontal: 18),
padding: EdgeInsets.zero, shape: RoundedRectangleBorder(
itemCount: 10, borderRadius: BorderRadius.circular(19),
itemBuilder: (context, index) => ProductCard( side: const BorderSide(color: Color(0xFFFDFDFD)),
product: _cartList[0], ),
isInCart: true, color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// "Select All" Checkbox
Row(
children: [
Checkbox(
value: _selectAll,
onChanged: _toggleSelectAll,
),
Text(
"Select All",
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
SizedBox(
height: Get.height * 0.6,
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: _cartController.cartList.length,
itemBuilder: (context, index) {
return Row(
children: [
Checkbox(
value: _cartController.selectedProducts.contains(
_cartController.cartList[index]),
onChanged: (value) {
_cartController.toggleProductSelection(
_cartController.cartList[index],
value!,
);
_checkIfAllSelected(); // Check if all are selected after each toggle
},
),
Expanded(
child: ProductCard(
productModel:
_cartController.cartList[index],
isInCart: true,
placedOrder: widget.placedOrder,
),
),
],
);
},
), ),
), ),
), const SizedBox(height: 10),
const SizedBox( Row(
height: 10, mainAxisAlignment: MainAxisAlignment.spaceBetween,
), children: [
Text( Text(
"Total Price: ₹ Total", "Subtotal ",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 20, fontSize: 15,
fontWeight: FontWeight.w700, color: Colors.black,
color: Colors.white, fontWeight: FontWeight.bold,
),
),
Obx(() =>
Text("${_cartController.subtotal.value}")),
],
), ),
), Row(
const SizedBox( mainAxisAlignment: MainAxisAlignment.spaceBetween,
height: 16, children: [
), Text(
], "GST ",
), style: GoogleFonts.roboto(
), fontSize: 15,
), color: Colors.black,
SizedBox( fontWeight: FontWeight.bold,
height: Get.height * 0.025, ),
), ),
SizedBox( Obx(() =>
width: Get.width * 0.9, Text("${_cartController.gstTotal.value}")),
height: Get.height * 0.06, ],
child: ElevatedButton( ),
onPressed: () => Get.to(() => const CheckoutScreen()), Row(
style: ElevatedButton.styleFrom( mainAxisAlignment: MainAxisAlignment.spaceBetween,
foregroundColor: Colors.white, children: [
backgroundColor: const Color(0xFF00784C), Text(
shape: RoundedRectangleBorder( "Total Amount ",
borderRadius: BorderRadius.circular(10), style: GoogleFonts.roboto(
), fontSize: 15,
), color: Colors.black,
child: Text( fontWeight: FontWeight.bold,
"Proceed to Checkout", ),
style: GoogleFonts.roboto( ),
fontSize: 16, Obx(() => Text(
fontWeight: FontWeight.w600, "${_cartController.grandTotal.value}")),
],
),
],
), ),
), ),
), ),
), SizedBox(height: Get.height * 0.020),
], SizedBox(
), width: Get.width * 0.9,
height: Get.height * 0.06,
child: ElevatedButton(
onPressed: () => Get.to(() => CheckoutScreen(
selectedProducts: _cartController.selectedProducts,
)),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
"Proceed to Checkout",
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
],
);
}),
), ),
], ],
), ),
); );
} }
} }
// import 'package:cheminova/models/oder_place_model.dart';
// import 'package:cheminova/models/product_model.dart';
// import 'package:cheminova/screens/order/checkout_screen.dart';
// import 'package:cheminova/widgets/my_drawer.dart';
// import 'package:cheminova/widgets/product_card.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_svg/svg.dart';
// import 'package:get/get.dart';
// import 'package:google_fonts/google_fonts.dart';
//
// import '../../controller/cart_controller.dart';
// import '../../models/product_model1.dart';
//
// class CartScreen extends StatefulWidget {
// Product? productModel;
// PlacedOrderModel? placedOrder;
//
// CartScreen({super.key, this.productModel, this.placedOrder});
//
// @override
// State<CartScreen> createState() => _CartScreenState();
// }
//
// class _CartScreenState extends State<CartScreen> {
// final CartController _cartController = Get.find<CartController>();
//
// bool _selectAll = false; // State to track "Select All" checkbox
//
// @override
// void initState() {
// super.initState();
// if (widget.productModel != null) {
// _cartController.addToCart(widget.productModel!);
// }
// }
//
// void _toggleSelectAll(bool? value) {
// setState(() {
// _selectAll = value ?? false;
// _cartController.cartList.forEach((product) {
// _cartController.toggleProductSelection(product, _selectAll);
// });
// });
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// extendBodyBehindAppBar: true,
// appBar: AppBar(
// backgroundColor: Colors.transparent,
// elevation: 0,
// leading: Builder(
// builder: (context) {
// return GestureDetector(
// onTap: () => Scaffold.of(context).openDrawer(),
// child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: SvgPicture.asset(
// 'assets/svg/menu.svg',
// ),
// ),
// );
// },
// ),
// actions: [
// GestureDetector(
// onTap: () => Get.back(),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: SvgPicture.asset(
// 'assets/svg/back_arrow.svg',
// ),
// ),
// ),
// ],
// title: Center(
// child: const Text(
// "Cart",
// ),
// ),
// ),
// drawer: const MyDrawer(),
// body: Stack(
// fit: StackFit.expand,
// children: [
// Image.asset(
// 'assets/images/image_1.png',
// fit: BoxFit.cover,
// ),
// SafeArea(
// child: Obx(() {
// if (_cartController.cartList.isEmpty) {
// return Center(
// child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Image.asset(
// 'assets/images/cart.png',
// width: Get.width * 0.5,
// height: Get.width * 0.5,
// ),
// const SizedBox(height: 20),
// Text(
// 'Your Cart is empty',
// style: GoogleFonts.roboto(
// fontSize: 24,
// fontWeight: FontWeight.w500,
// color: Colors.white,
// ),
// ),
// ],
// ),
// );
// }
// return Column(
// children: [
// SizedBox(
// height: Get.height * 0.02,
// ),
// Card(
// margin: const EdgeInsets.symmetric(horizontal: 18),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(19),
// side: const BorderSide(color: Color(0xFFFDFDFD)),
// ),
// color: const Color(0xFFB4D1E5).withOpacity(0.9),
// child: Padding(
// padding: const EdgeInsets.all(12.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// // "Select All" Checkbox
// Row(
// children: [
// Checkbox(
// value: _selectAll,
// onChanged: _toggleSelectAll,
// ),
// Text(
// "Select All",
// style: GoogleFonts.roboto(
// fontSize: 16,
// fontWeight: FontWeight.w500,
// ),
// ),
// ],
// ),
// SizedBox(
// height: Get.height * 0.6,
// child: ListView.builder(
// padding: EdgeInsets.zero,
// itemCount: _cartController.cartList.length,
// itemBuilder: (context, index) {
// return Row(
// children: [
// Checkbox(
// value: _cartController
// .cartList[index].selected,
// onChanged: (value) {
// setState(() {
//
// });
// _cartController.toggleProductSelection(
// _cartController.cartList[index],
// value!);
// },
// ),
// Expanded(
// child: ProductCard(
// productModel:
// _cartController.cartList[index],
// isInCart: true,
// placedOrder: widget.placedOrder,
// ),
// ),
// ],
// );
// },
// ),
// ),
// const SizedBox(height: 10),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "Subtotal ",
// style: GoogleFonts.roboto(
// fontSize: 15,
// color: Colors.black,
// fontWeight: FontWeight.bold,
// ),
// ),
// Obx(() => Text("${_cartController.subtotal.value}")),
// ],
// ),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "GST ",
// style: GoogleFonts.roboto(
// fontSize: 15,
// color: Colors.black,
// fontWeight: FontWeight.bold,
// ),
// ),
// Obx(() => Text("${_cartController.gstTotal.value}")),
// ],
// ),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "Total Amount ",
// style: GoogleFonts.roboto(
// fontSize: 15,
// color: Colors.black,
// fontWeight: FontWeight.bold,
// ),
// ),
// Obx(() => Text("${_cartController.grandTotal.value}")),
// ],
// ),
// ],
// ),
// ),
// ),
// SizedBox(height: Get.height * 0.020),
// SizedBox(
// width: Get.width * 0.9,
// height: Get.height * 0.06,
// child: ElevatedButton(
// onPressed: () => Get.to(() => CheckoutScreen(
// productModel: widget.productModel,
// )),
// style: ElevatedButton.styleFrom(
// foregroundColor: Colors.white,
// backgroundColor: const Color(0xFF00784C),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(10),
// ),
// ),
// child: Text(
// "Proceed to Checkout",
// style: GoogleFonts.roboto(
// fontSize: 16,
// fontWeight: FontWeight.w600,
// ),
// ),
// ),
// ),
// ],
// );
// }),
// ),
// ],
// ),
// );
// }
// }

View File

@ -0,0 +1,26 @@
import 'package:cheminova/models/product_mannual_model.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
class ViewPdfScreen extends StatefulWidget {
final ProductManualModel productManualModel;
const ViewPdfScreen({super.key, required this.productManualModel});
@override
State<ViewPdfScreen> createState() => _ViewPdfScreenState();
}
class _ViewPdfScreenState extends State<ViewPdfScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SfPdfViewer.network(
widget.productManualModel.productManual.url,
),
),
);
}
}

View File

@ -1,10 +1,14 @@
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model1.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/screens/product/cart_screen.dart';
import 'package:cheminova/widgets/product_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart';
import '../../widgets/my_drawer.dart';
import '../../widgets/product_card.dart';
import '../../controller/product_service.dart';
import '../../models/product_model.dart'; // Import your ProductModel
class ProductCatalogScreen extends StatefulWidget { class ProductCatalogScreen extends StatefulWidget {
const ProductCatalogScreen({super.key}); const ProductCatalogScreen({super.key});
@ -14,22 +18,103 @@ class ProductCatalogScreen extends StatefulWidget {
} }
class _ProductCatalogScreenState extends State<ProductCatalogScreen> { class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
final List<ProductModel> _productList = [ final ProductService _productService = ProductService();
ProductModel( final ScrollController _scrollController = ScrollController();
id: '1', final CartController cartController = Get.put(CartController());
name: 'Product 1',
price: 100, List<Product> _products = []; // Use ProductModel here
description: 'Description 1', List<Map<String, dynamic>> _categories = [];
category: ProductCategory.food,
image: 'assets/images/product.png', int _currentPage = 1;
) bool _isLoading = false;
]; bool _hasMoreData = true;
String? _selectedCategory;
String? _selectedPriceRange;
String? _selectedAvailability;
@override
void initState() {
super.initState();
_fetchCategories();
_fetchProducts();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent &&
!_isLoading &&
_hasMoreData) {
_fetchMoreProducts();
}
});
}
Future<void> _fetchProducts() async {
setState(() {
_isLoading = true;
});
final category = _selectedCategory == 'All' ? null : _selectedCategory;
final products = await _productService.getProduct(
_currentPage, category: category);
setState(() {
if (products != null) {
_products.addAll(products); // Assuming products is a List<ProductModel>
_hasMoreData = products.isNotEmpty;
}
_isLoading = false;
});
}
Future<void> _fetchCategories() async {
final categories = await _productService.getCategory();
if (categories != null) {
setState(() {
_categories = categories;
_categories.insert(1, {'categoryName': 'All'});
_selectedCategory = 'All';
});
}
}
void _onCategoryChanged(String? newCategory) {
if (newCategory != null) {
setState(() {
_selectedCategory = newCategory;
_products.clear();
_currentPage = 1;
});
_fetchProducts();
}
}
Future<void> _fetchMoreProducts() async {
if (!_isLoading && _hasMoreData) {
setState(() {
_isLoading = true;
_currentPage++;
});
await _fetchProducts();
}
}
void _clearFilters() {
setState(() {
_selectedCategory = null;
_selectedPriceRange = null;
_selectedAvailability = null;
_products.clear();
_currentPage = 1;
});
_fetchProducts();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
final List<String> _filterList = [
"Category",
"Price Range",
"Availability",
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -52,17 +137,42 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
), ),
actions: [ actions: [
GestureDetector( GestureDetector(
onTap: () => Get.back(), onTap: () => Get.to(CartScreen()),
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset( child: Stack(
'assets/svg/back_arrow.svg', children: [
Icon(Icons.shopping_cart, size: 30,),
// Cart count display
Positioned(
right: 0,
child: Obx(() =>
cartController.cartCount.value > 0
? Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Text(
'${cartController.cartCount.value}',
style: TextStyle(
color: Colors.white,
fontSize: 12,
),
),
)
: SizedBox.shrink()),
),
],
), ),
), ),
), ),
], ],
title: const Text( title: Center(
"Product Catalogue", child: const Text(
"Product Catalogue",
),
), ),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(),
@ -74,67 +184,191 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
SafeArea( SafeArea(
child: Column( child: SingleChildScrollView(
children: [ child: Column(
SizedBox( children: [
height: Get.height * 0.02, SizedBox(height: Get.height * 0.02),
), Padding(
Card( padding: const EdgeInsets.symmetric(horizontal: 18.0),
margin: const EdgeInsets.symmetric(horizontal: 18), child: TextField(
shape: RoundedRectangleBorder( decoration: InputDecoration(
borderRadius: BorderRadius.circular(19), hintText: "Search Products",
side: const BorderSide(color: Color(0xFFFDFDFD)), border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
filled: true,
fillColor: Colors.white.withOpacity(0.9),
),
),
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), SizedBox(height: Get.height * 0.02),
child: Padding( Card(
padding: const EdgeInsets.all(12.0), margin: const EdgeInsets.symmetric(horizontal: 18),
child: Column( shape: RoundedRectangleBorder(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(19),
children: [ side: const BorderSide(color: Color(0xFFFDFDFD)),
SizedBox( ),
height: Get.height * 0.05, color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: ListView.builder( child: Padding(
shrinkWrap: true, padding: const EdgeInsets.all(12.0),
scrollDirection: Axis.horizontal, child: Column(
itemCount: _filterList.length, mainAxisSize: MainAxisSize.min,
itemBuilder: (context, index) => Padding( children: [
padding: Row(
const EdgeInsets.symmetric(horizontal: 4), mainAxisAlignment: MainAxisAlignment.spaceBetween,
child: Chip( children: [
label: Text( Text(
_filterList[index], "Filter",
style: GoogleFonts.roboto( style: GoogleFonts.poppins(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
TextButton(
onPressed: _clearFilters,
child: Text(
"Clear Filter",
style: GoogleFonts.poppins(
color: Colors.red,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500,
), ),
), ),
), ),
],
),
SizedBox(
height: Get.height * 0.05,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) =>
_buildFilterDropdown(index),
), ),
), ),
), SizedBox(
SizedBox( height: Get.height * 0.6,
height: Get.height * 0.6, child: ListView.builder(
child: ListView.builder( controller: _scrollController,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
shrinkWrap: true, itemCount: _products.length +
itemCount: 10, (_isLoading ? 1 : 0),
itemBuilder: (context, index) => Padding( itemBuilder: (context, index) {
padding: const EdgeInsets.symmetric(vertical: 8), if (index >= _products.length) {
child: ProductCard( print("Product length $_products");
product: _productList[0], return const Center(
), child: CircularProgressIndicator());
}
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 8),
child: ProductCard(
productModel: _products[index],
// Use ProductModel here
),
);
},
), ),
), ),
) ],
], ),
), ),
), ),
), ],
], ),
), ),
), ),
], ],
), ),
); );
} }
Widget _buildFilterDropdown(int index) {
switch (index) {
case 0:
return _buildStyledDropdown(
value: _selectedCategory,
onChanged: _onCategoryChanged,
items: _categories.map((category) {
return DropdownMenuItem<String>(
value: category['categoryName'],
child: Text(category['categoryName']),
);
}).toList(),
hint: "Category",
);
// case 1:
// return _buildStyledDropdown(
// value: _selectedPriceRange,
// onChanged: (value) {
// setState(() {
// _selectedPriceRange = value;
// });
// },
// items: [
// const DropdownMenuItem<String>(
// value: "Under ₹50",
// child: Text("Under ₹50"),
// ),
// const DropdownMenuItem<String>(
// value: "₹50 - ₹100",
// child: Text("₹50 - ₹100"),
// ),
// const DropdownMenuItem<String>(
// value: "Above ₹100",
// child: Text("Above ₹100"),
// ),
// ],
// hint: "Price Range",
// );
// case 2:
// return _buildStyledDropdown(
// value: _selectedAvailability,
// onChanged: (value) {
// setState(() {
// _selectedAvailability = value;
// });
// },
// items: [
// const DropdownMenuItem<String>(
// value: "In Stock",
// child: Text("In Stock"),
// ),
// const DropdownMenuItem<String>(
// value: "Out of Stock",
// child: Text("Out of Stock"),
// ),
// ],
// hint: "Availability",
// );
default:
return const SizedBox();
}
}
Widget _buildStyledDropdown({
required String? value,
required ValueChanged<String?> onChanged,
required List<DropdownMenuItem<String>> items,
required String hint,
}) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: Colors.grey.shade300),
color: Colors.white,
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: value,
onChanged: onChanged,
items: items,
hint: Text(hint),
icon: const Icon(Icons.arrow_drop_down),
),
),
);
}
} }

View File

@ -1,20 +1,30 @@
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/screens/product/cart_screen.dart'; import 'package:cheminova/models/product_model1.dart';
import 'package:cheminova/utils/show_snackbar.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart';
class ProductDetailScreen extends StatefulWidget { class ProductDetailScreen extends StatefulWidget {
final ProductModel product; Product? productModel;
const ProductDetailScreen({super.key, required this.product}); ProductModel? product;
ProductDetailScreen({super.key, this.product, this.productModel});
@override @override
State<ProductDetailScreen> createState() => _ProductDetailScreenState(); State<ProductDetailScreen> createState() => _ProductDetailScreenState();
} }
class _ProductDetailScreenState extends State<ProductDetailScreen> { class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController());
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -83,7 +93,7 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Container( child: Container(
height: Get.height * 0.4, height: Get.height * 0.4,
width: Get.width * 0.7, width: Get.width * 0.8,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
width: 4, width: 4,
@ -93,56 +103,80 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
child: Image.asset( child: Image.asset("assets/images/product.png", fit: BoxFit.cover,),
widget.product.image, // Image.asset(
fit: BoxFit.cover, // widget.product.image,
// fit: BoxFit.cover,
// ),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("Product Name ",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),),
Text(
capitalizeFirstLetter(widget.productModel!.name),
style: GoogleFonts.roboto(
fontSize: 16,
// fontWeight: FontWeight.w600,
color: Colors.black,
),
), ),
), ],
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Row(
widget.product.name, mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: GoogleFonts.roboto( children: [
fontSize: 20, const Text("Price ",style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold),),
fontWeight: FontWeight.w600, Text(
color: Colors.white, "${widget.productModel!.price.toString()}",
), style: GoogleFonts.roboto(
fontSize: 16,
//fontWeight: FontWeight.w800,
color: Colors.black,
),
),
],
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Row(
"${widget.product.price.toString()}", mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: GoogleFonts.roboto( children: [
fontSize: 24, const Text("Category ",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),),
fontWeight: FontWeight.w800, Text(
color: Colors.white, capitalizeFirstLetter(widget.productModel!.category.categoryName),
), style: GoogleFonts.roboto(
), fontSize: 16,
), fontWeight: FontWeight.w400,
Padding( color: Colors.black,
padding: const EdgeInsets.symmetric(horizontal: 8), ),
child: Text( ),
widget.product.category.name, ],
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.white,
),
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Row(
widget.product.description, children: [
style: GoogleFonts.roboto( const Text("Description",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16)),
fontSize: 16, Text(
fontWeight: FontWeight.w400, capitalizeFirstLetter(widget.productModel!.description),
color: Colors.white, style: GoogleFonts.roboto(
), fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black,
),
),
],
), ),
), ),
], ],
@ -154,7 +188,11 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
width: Get.width * 0.9, width: Get.width * 0.9,
height: Get.height * 0.06, height: Get.height * 0.06,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => Get.to(() => const CartScreen()), onPressed: () {
// Pass the product data to the CartScreen
_cartController.addToCart(widget.productModel!);
showSnackbar("Product successfully added to your cart");
},
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C), backgroundColor: const Color(0xFF00784C),

View File

@ -0,0 +1,134 @@
import 'package:cheminova/controller/product_mannual_controller.dart';
import 'package:cheminova/models/product_mannual_model.dart';
import 'package:cheminova/screens/product/pdf_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import '../../widgets/custom_button.dart';
class ProductsManualScreen extends StatefulWidget {
const ProductsManualScreen({super.key});
@override
_ProductsManualScreenState createState() => _ProductsManualScreenState();
}
class _ProductsManualScreenState extends State<ProductsManualScreen> {
final ProductManualController _productManualController = Get.put(ProductManualController());
@override
void initState() {
super.initState();
_productManualController.fetchProductManuals(); // Fetch product manual list from API
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: _buildAppBar(),
body: Stack(
alignment: Alignment.topCenter,
children: [
_buildBackgroundImage(),
Center(
child: SingleChildScrollView(
child: _buildCardContent(),
),
),
],
),
);
}
// Extract AppBar to its own method
AppBar _buildAppBar() {
return AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset('assets/svg/menu.svg'),
),
),
actions: [
GestureDetector(
onTap: () => Get.back(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset('assets/svg/back_arrow.svg'),
),
),
],
);
}
// Extract background image widget
Widget _buildBackgroundImage() {
return Container(
height: 900,
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage('assets/images/image_1.png'),
),
),
child: SizedBox(
width: Get.width,
height: Get.height * 0.7,
),
);
}
// Build the card content
Widget _buildCardContent() {
return Obx(() {
if (_productManualController.isLoading.value) {
return const CircularProgressIndicator(); // Loading state
}
if (_productManualController.productManualList.isEmpty) {
return const Text("No product manuals available"); // Empty state
}
return Card(
margin: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19),
side: const BorderSide(color: Color(0xFFFDFDFD)),
),
color: const Color(0xFFB4D1E5).withOpacity(0.9),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: _buildProductButtons(),
),
),
);
});
}
// Method to create a list of CustomButtons for products dynamically from API data
List<Widget> _buildProductButtons() {
return _productManualController.productManualList.map((productManual) {
return CustomButton(
text: productManual.title ?? "No Title", // Dynamically fetch product name
onPressed: () => _navigateToPdfScreen(productManual),
);
}).toList();
}
// Method to handle navigation to PDF screen
void _navigateToPdfScreen(ProductManualModel productManual) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewPdfScreen(
productManualModel: productManual,
),
),
);
}
}

View File

@ -0,0 +1,99 @@
// import 'package:cheminova/controller/home_controller.dart';
// import 'package:cheminova/widgets/my_drawer.dart';
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
//
// import '../widgets/comman_background.dart';
// import '../widgets/common_appbar.dart';
//
// class ProfileScreen extends StatelessWidget {
// const ProfileScreen({Key? key}) : super(key: key);
//
// @override
// Widget build(BuildContext context) {
// return Stack(
// children: [
// CommonBackground(
// isFullWidth: true,
// child: Scaffold(
// drawer: const MyDrawer(),
// backgroundColor: Colors.transparent,
// appBar: CommonAppBar(
// title: const Text('Profile'),
// backgroundColor: Colors.transparent,
// elevation: 0,
// actions: [
// IconButton(
// onPressed: () {
// Navigator.pop(context);
// },
// icon: Image.asset('assets/Back_attendance.png'),
// padding: const EdgeInsets.only(right: 20),
// ),
// ],
// ),
// body: Consumer<HomeController>(
// builder: (context, profileProvider, child) {
// final profileData = profileProvider.profileResponse?.myData!;
// return SingleChildScrollView(
// child: Column(
// children: [
// Container(
// padding: const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30),
// margin: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 20.0),
// decoration: BoxDecoration(
// border: Border.all(color: Colors.white),
// color: const Color(0xffB4D1E5).withOpacity(0.9),
// borderRadius: BorderRadius.circular(26.0),
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// SizedBox(height: 20),
// _buildProfileItem('Name', profileData?.name ?? ''),
// _buildProfileItem('ID', profileData?.uniqueId ?? ''),
// _buildProfileItem('Email ID', profileData?.email ?? ''),
// _buildProfileItem('Mobile Number', profileData?.mobileNumber ?? ''),
// _buildProfileItem('Designation', profileData?.designation ?? ''),
// ],
// ),
// ),
// ],
// ),
// );
// },
// ),
// ),
// ),
// ],
// );
// }
//
// Widget _buildProfileItem(String label, String value) {
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 10),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// label,
// style: const TextStyle(
// fontSize: 16,
// fontWeight: FontWeight.bold,
// color: Color(0xff004791),
// ),
// ),
// const SizedBox(height: 5),
// Text(
// value,
// style: const TextStyle(
// fontSize: 18,
// color: Colors.black,
// ),
// ),
// const Divider(color: Colors.grey),
// ],
// ),
// );
// }
// }

View File

@ -1,9 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'package:cheminova/screens/authentication/login_screen.dart'; import 'package:cheminova/screens/authentication/login_screen.dart';
import 'package:cheminova/screens/home_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SplashScreen extends StatefulWidget { class SplashScreen extends StatefulWidget {
const SplashScreen({super.key}); const SplashScreen({super.key});
@ -15,12 +17,25 @@ class SplashScreen extends StatefulWidget {
class _SplashScreenState extends State<SplashScreen> { class _SplashScreenState extends State<SplashScreen> {
@override @override
void initState() { void initState() {
super.initState(); Timer(const Duration(seconds: 3), () {
Timer(const Duration(seconds: 2), () { checkLogin();
Get.offAll(() => const LoginScreen());
}); });
super.initState();
} }
checkLogin() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
if (token != null) {
Get.offAll(() => const HomeScreen());
} else {
Get.offAll(() => const LoginScreen());
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(

18
lib/utils/api_urls.dart Normal file
View File

@ -0,0 +1,18 @@
class ApiUrls {
// static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/';
static const String baseUrl = 'https://api.cnapp.co.in';
static const String loginUrl = '/api/v1/user/login/';
static const String profileUrl = '/api/rd-get-me';
static const String forgetPasswordUrl = '/api/v1/user/password/forgot';
static const String changePasswordUrl = '/api/v1/user/password/update';
static const String fcmUrl = '/api/v1/user/fcm-token';
static const String getCategoryUrl = '/api/category/getCategories';
static const String getProductUrl = '/api/category/getCategories';
static const String getProductManualUrl = '/api/productmanual/getall';
static const String getKycUrl = '/api/kyc/getAll';
static const String getNotificationUrl = '/api/get-notification-pd';
static const String getPlacedOrderUrl ='/api/get-placed-order-pd';
static const String getSinglePlacedOrderUrl ='/api/get-single-placed-order-pd';
static const String placedOrderUrl ='${baseUrl}/api/order-place';
}

View File

@ -1,80 +1,86 @@
import 'dart:io'; import 'dart:io';
import 'package:cheminova/utils/constants.dart'; import 'package:cheminova/utils/constants.dart';
import 'package:cheminova/utils/show_snackbar.dart'; import 'package:cheminova/utils/show_snackbar.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
Future<BodyType?> commonApiService<BodyType>({ Future<BodyType?> commonApiService<BodyType>({
required String url, required String url,
required String method, required String method,
Map<String, dynamic> body = const {}, Map<String, dynamic> body = const {},
File? imageFile, File? imageFile,
bool isformData = true, bool isFormData = false,
Map<String, String>? additionalHeaders,
required BodyType Function(Map<String, dynamic>) fromJson, required BodyType Function(Map<String, dynamic>) fromJson,
}) async { }) async {
try { try {
Dio dio = Dio(); final dio = Dio();
final Response response;
print("body : $body"); // Add PrettyDioLogger
dio.interceptors.add(PrettyDioLogger(
requestHeader: true,
requestBody: true,
responseBody: true,
responseHeader: false,
error: true,
compact: true,
maxWidth: 90,
));
// Fetch the token from SharedPreferences final prefs = await SharedPreferences.getInstance();
SharedPreferences prefs = await SharedPreferences.getInstance(); final token = prefs.getString('token');
String? token = prefs.getString('token');
Map<String, String> headers = { final headers = <String, String>{
'Content-Type': isformData ? 'multipart/form-data' : 'application/json', 'Content-Type': isFormData ? 'multipart/form-data' : 'application/json',
if (token != null) 'Authorization': 'Bearer $token',
...?additionalHeaders,
}; };
if (token != null) { final options = Options(headers: headers);
headers['Authorization'] = 'Bearer $token';
}
Options options = Options(headers: headers); dynamic requestData = isFormData ? FormData.fromMap(body) : body;
FormData formData = FormData.fromMap(body); if (imageFile != null && isFormData) {
final fileName = imageFile.path.split('/').last;
if (imageFile != null) { (requestData as FormData).files.add(MapEntry(
String fileName = imageFile.path.split('/').last;
formData.files.add(MapEntry(
"image", "image",
await MultipartFile.fromFile(imageFile.path, filename: fileName), await MultipartFile.fromFile(imageFile.path, filename: fileName),
)); ));
} }
if (method == "POST") { final Response response;
response = await dio.post("$baseUrl$url", switch (method.toUpperCase()) {
data: isformData ? formData : body, options: options); case "POST":
} else if (method == "PUT") { response = await dio.post("$baseUrl$url", data: requestData, options: options);
response = await dio.put("$baseUrl$url", break;
data: isformData ? formData : body, options: options); case "PUT":
} else if (method == "DELETE") { response = await dio.put("$baseUrl$url", data: requestData, options: options);
response = await dio.delete("$baseUrl$url", options: options); break;
} else if (method == "PATCH") { case "DELETE":
response = await dio.patch("$baseUrl$url", response = await dio.delete("$baseUrl$url", options: options);
data: isformData ? formData : body, options: options); break;
} else { case "PATCH":
response = await dio.get("$baseUrl$url", options: options); response = await dio.patch("$baseUrl$url", data: requestData, options: options);
break;
case "GET":
response = await dio.get("$baseUrl$url", options: options);
break;
default:
throw Exception("Unsupported HTTP method: $method");
} }
print("response of $url : $response"); if (url == "/api/rd-login" && response.data['token'] != null) {
await prefs.setString('token', response.data['token']);
if (url == "/api/territorymanager/login" &&
response.data['token'] != null) {
prefs.setString('token', response.data['token']);
} }
if (url == "/api/territorymanager/my-profile") { if (url == "/api/rd-get-me" && response.data['myData'] != null) {
return fromJson(response.data['myData']); return fromJson(response.data['myData']);
} }
return fromJson(response.data); return fromJson(response.data);
} on DioException catch (e) { } on DioException catch (e) {
print("dio exception $url ${e.response?.data}}");
print("dio exception details: ${e.message} ${e.response?.statusCode}");
String errorMessage = "An error occurred"; String errorMessage = "An error occurred";
if (e.response?.data is Map<String, dynamic>) { if (e.response?.data is Map<String, dynamic>) {
errorMessage = e.response?.data['message'] ?? errorMessage; errorMessage = e.response?.data['message'] ?? errorMessage;
} else if (e.response?.data is String) { } else if (e.response?.data is String) {
@ -82,8 +88,10 @@ Future<BodyType?> commonApiService<BodyType>({
} }
showSnackbar(errorMessage); showSnackbar(errorMessage);
return null;
} catch (e) { } catch (e) {
print("exception $url $e"); print("Unexpected error for $url: $e");
showSnackbar("An unexpected error occurred");
return null;
} }
return null; }
}

View File

@ -1 +1,3 @@
String baseUrl = "https://cheminova-api-2.onrender.com"; //String baseUrl = "https://cheminova-api-2.onrender.com";
String baseUrl = "https://api.cnapp.co.in";

View File

@ -0,0 +1,7 @@
import 'package:logger/logger.dart';
final logger = Logger(
printer: PrettyPrinter(
lineLength: 500
)
);

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class CommonBackground extends StatelessWidget {
final Widget child;
final bool isFullWidth;
const CommonBackground(
{super.key, required this.child, this.isFullWidth = true, appBar});
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Stack(children: [
Container(
height: isFullWidth
? MediaQuery.sizeOf(context).height
: MediaQuery.sizeOf(context).height * 0.90,
decoration: BoxDecoration(
image: const DecorationImage(
image: AssetImage('assets/images/image_1.png'),
fit: BoxFit.cover))),
child
]),
);
}
}

View File

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CommonTextFormField extends StatefulWidget {
final String title;
final String? label;
final TextEditingController? controller;
//final TextCapitalization textCapitalization;
final String? Function(String?)? validator;
final Color? fillColor;
final bool? readOnly;
final int? maxLines;
final double? height;
final TextInputType? keyboardType;
final List<TextInputFormatter>? inputFormatters;
final int? maxLength;
final bool obscureText;
final void Function(String)? onChanged;
const CommonTextFormField({
super.key,
required this.title,
this.label,
this.controller,
this.validator,
this.fillColor,
this.readOnly,
this.maxLines,
this.height,
this.keyboardType,
this.inputFormatters,
this.maxLength,
this.onChanged,
// this.textCapitalization = TextCapitalization.sentences,
this.obscureText = false,
});
@override
_CommonTextFormFieldState createState() => _CommonTextFormFieldState();
}
class _CommonTextFormFieldState extends State<CommonTextFormField> {
bool _isObscured = true;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: widget.controller,
//textCapitalization: widget.textCapitalization,
readOnly: widget.readOnly ?? false,
maxLines: widget.maxLines ?? 1,
maxLength: widget.maxLength,
onChanged: widget.onChanged,
onTapOutside: (event) => FocusScope.of(context).unfocus(),
validator: widget.validator,
keyboardType: widget.keyboardType,
inputFormatters: widget.inputFormatters,
obscureText: widget.obscureText && _isObscured,
decoration: InputDecoration(
hintText: widget.title,
labelText: widget.label,
contentPadding: const EdgeInsets.only(bottom: 10, left: 10),
filled: true,
suffixIcon: widget.obscureText
? IconButton(
icon: Icon(
_isObscured ? Icons.visibility : Icons.visibility_off,
color: Colors.grey,
),
onPressed: () {
setState(() {
_isObscured = !_isObscured;
});
},
)
: null,
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(6)),
borderSide: BorderSide(color: Colors.transparent),
),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(6)),
borderSide: BorderSide(color: Colors.transparent),
),
fillColor: widget.fillColor ?? Colors.white,
),
),
],
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
class CommonAppBar extends StatelessWidget implements PreferredSizeWidget {
final Widget title;
final List<Widget>? actions;
final TabBar? bottom;
const CommonAppBar({super.key, required this.title, this.actions, required Color backgroundColor, required int elevation, this.bottom});
@override
Widget build(BuildContext context) {
return AppBar(
centerTitle: true,
leading: Builder(builder: (context) {
return IconButton(
onPressed: () => Scaffold.of(context).openDrawer(),
icon: const Icon(Icons.menu),
color: Colors.white);
}),
backgroundColor: Colors.transparent,
bottom: bottom,
title: title,
toolbarHeight: kToolbarHeight+20,
actions: actions);
}
@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

View File

@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
class CommonElevatedButton extends StatelessWidget {
final String text;
final void Function()? onPressed;
final double? height;
final double? width;
final double? borderRadius;
final Color? backgroundColor;
final bool isLoading;
const CommonElevatedButton(
{super.key,
required this.text,
this.onPressed,
this.borderRadius,
this.backgroundColor,
this.height,
this.width,
this.isLoading = false});
@override
Widget build(BuildContext context) {
return SizedBox(
height: height ?? kToolbarHeight - 25,
width: width ?? 200,
child: ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius ?? 6)),
backgroundColor: backgroundColor ?? const Color(0xff1E1E1E),
side: const BorderSide(color: Colors.transparent)),
child: Center(
child: isLoading
? const CircularProgressIndicator(
backgroundColor: Colors.white,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
: Text(text,
style: const TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.w400,
fontFamily: 'Anek')))));
}
}

View File

@ -1,22 +1,31 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class InputField extends StatelessWidget { class InputField extends StatefulWidget {
final String hintText; final String hintText;
final String labelText; final String labelText;
final TextEditingController controller; final TextEditingController controller;
final bool obscureText; final bool obscureText;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final String? Function(String?)? validator;// Add this line for validation
const InputField({ InputField({
super.key, super.key,
required this.hintText, required this.hintText,
required this.labelText, required this.labelText,
required this.controller, required this.controller,
this.obscureText = false, this.obscureText = false,
this.keyboardType = TextInputType.text, this.keyboardType = TextInputType.text,
this.validator, // Add this
}); });
@override
State<InputField> createState() => _InputFieldState();
}
class _InputFieldState extends State<InputField> {
bool _isObscured = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -24,15 +33,16 @@ class InputField extends StatelessWidget {
width: Get.width * 0.9, width: Get.width * 0.9,
padding: const EdgeInsets.fromLTRB(6, 10, 10, 0), padding: const EdgeInsets.fromLTRB(6, 10, 10, 0),
child: TextFormField( child: TextFormField(
controller: controller, controller: widget.controller,
obscureText: obscureText, obscureText: widget.obscureText && _isObscured,
keyboardType: keyboardType, keyboardType: widget.keyboardType,
decoration: InputDecoration( decoration: InputDecoration(
labelText: labelText, labelText: widget.labelText,
hintText: hintText, hintText: widget.hintText,
labelStyle: const TextStyle( labelStyle: const TextStyle(
color: Color(0xFF000000), color: Color(0xFF000000),
), ),
enabledBorder: const OutlineInputBorder( enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey), borderSide: BorderSide(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(8)), borderRadius: BorderRadius.all(Radius.circular(8)),
@ -42,10 +52,24 @@ class InputField extends StatelessWidget {
borderRadius: BorderRadius.all(Radius.circular(8)), borderRadius: BorderRadius.all(Radius.circular(8)),
), ),
contentPadding: contentPadding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 16), const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
fillColor: Colors.white, fillColor: Colors.white,
filled: true, filled: true,
// suffixIcon: widget.obscureText
// ? IconButton(
// icon: Icon(
// _isObscured ? Icons.visibility : Icons.visibility_off,
// color: Colors.grey,
// ),
// onPressed: () {
// setState(() {
// _isObscured = !_isObscured;
// });
// },
// )
// : null,
), ),
validator: widget.validator, // Add this for validation
), ),
); );
} }

View File

@ -1,9 +1,12 @@
import 'package:cheminova/controller/home_controller.dart'; import 'package:cheminova/controller/home_controller.dart';
import 'package:cheminova/screens/authentication/change_password_screen.dart';
import 'package:cheminova/screens/authentication/login_screen.dart'; import 'package:cheminova/screens/authentication/login_screen.dart';
import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/home_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../screens/authentication/Profile.dart';
class MyDrawer extends StatefulWidget { class MyDrawer extends StatefulWidget {
const MyDrawer({super.key}); const MyDrawer({super.key});
@ -21,32 +24,37 @@ class _MyDrawerState extends State<MyDrawer> {
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(
height: 150, height: 150,
child: Obx( child:(
() => DrawerHeader( DrawerHeader(
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.black87, color: Colors.black87,
), ),
child: Column( child: GetBuilder(
crossAxisAlignment: CrossAxisAlignment.start, init: homeController,
mainAxisAlignment: MainAxisAlignment.start, builder: (controller) {
children: [ return Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
homeController.user.value?.name ?? "username", mainAxisAlignment: MainAxisAlignment.start,
style: const TextStyle( children: [
color: Colors.white, Text(
fontSize: 18, controller.user?.name?? "username",
), style: const TextStyle(
), color: Colors.white,
Text( fontSize: 18,
homeController.user.value?.uniqueId ?? 'Employee ID', ),
style: const TextStyle( ),
color: Colors.white, Text(
fontSize: 20, controller.user?.uniqueId?? 'Employee ID',
), style: const TextStyle(
), color: Colors.white,
], fontSize: 20,
), ),
), ),
],
);
}
),
)
), ),
), ),
ListTile( ListTile(
@ -58,13 +66,15 @@ class _MyDrawerState extends State<MyDrawer> {
leading: const Icon(Icons.account_circle), leading: const Icon(Icons.account_circle),
title: const Text('Profile'), title: const Text('Profile'),
onTap: () { onTap: () {
Navigator.pop(context); Get.to(ProfileScreen());
}, },
), ),
ListTile( ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: const Text('Change Password'), title: const Text('Change Password'),
onTap: () {}, onTap: () {
Get.to(ChangePasswordScreen());
},
), ),
ListTile( ListTile(
leading: const Icon(Icons.exit_to_app), leading: const Icon(Icons.exit_to_app),

View File

@ -1,26 +1,64 @@
import 'package:cheminova/controller/cart_controller.dart';
import 'package:cheminova/models/oder_place_model.dart';
import 'package:cheminova/models/order_item_model.dart';
import 'package:cheminova/models/place_order_list_model.dart';
import 'package:cheminova/models/product_model.dart'; import 'package:cheminova/models/product_model.dart';
import 'package:cheminova/screens/product/product_detail_screen.dart'; import 'package:cheminova/screens/product/product_detail_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
class ProductCard extends StatelessWidget { import '../models/product_model1.dart';
final ProductModel product; import '../utils/show_snackbar.dart';
class ProductCard extends StatefulWidget {
final Product? productModel;
PlacedOrderModel? placedOrder;
PlacedOrderList? placedOrderList;
PlaceOrderItem1? placeorderItem;
ProductModel? product;
final bool isInCart; final bool isInCart;
final bool isCheckout; final bool isCheckout;
const ProductCard({ final bool isConfirmation;
int? quantity;
ProductCard({
super.key, super.key,
required this.product, this.product,
this.quantity = 1,
this.productModel,
this.placedOrder,
this.placedOrderList,
this.placeorderItem,
this.isInCart = false, this.isInCart = false,
this.isCheckout = false, this.isCheckout = false,
this.isConfirmation = false,
}); });
@override
State<ProductCard> createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard> {
String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1).toLowerCase();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final CartController _cartController = Get.put(CartController());
bool showQuantity = widget.isInCart || widget.isCheckout || widget.isConfirmation;
bool isProductInCart = _cartController.cartList.any((p) => p.id == widget.productModel!.id);
int currentQuantity = isProductInCart
? _cartController.cartList.firstWhere((p) => p.id == widget.productModel!.id).quantity
: widget.productModel!.quantity;
return GestureDetector( return GestureDetector(
onTap: () => isInCart || isCheckout onTap: () => widget.isInCart || widget.isCheckout
? null ? null
: Get.to(() => ProductDetailScreen(product: product)), : Get.to(() => ProductDetailScreen(productModel: widget.productModel)),
child: Card( child: Card(
child: Row( child: Row(
children: [ children: [
@ -30,142 +68,179 @@ class ProductCard extends StatelessWidget {
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
child: Container( child: Container(
height: Get.height * 0.15, height: Get.height * 0.15,
width: Get.width * 0.30, width: Get.width * 0.31,
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: Image.asset(product.image).image, image: AssetImage("assets/images/product.png"),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
), ),
), ),
), ),
const SizedBox( Expanded(
width: 10, child: Padding(
), padding: const EdgeInsets.symmetric(horizontal: 3.0),
Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
product.name, capitalizeFirstLetter(widget.productModel!.name),
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
Text( Text(
product.category.name, capitalizeFirstLetter(widget.productModel!.category!.categoryName),
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
Text( Text(
"${product.price.toString()}0", "${widget.productModel!.price.toString()}",
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
isCheckout if (showQuantity)
? const SizedBox() Text(
: isInCart "Quantity: ${currentQuantity}",
? Row( style: GoogleFonts.roboto(
mainAxisAlignment: MainAxisAlignment.spaceBetween, fontSize: 15,
children: [ fontWeight: FontWeight.w700,
Container( ),
height: 40, ),
width: 100, if (!widget.isCheckout)
decoration: BoxDecoration( widget.isInCart
color: const Color(0xFF004791), ? Row(
borderRadius: BorderRadius.circular(10), mainAxisAlignment: MainAxisAlignment.spaceBetween,
), children: [
child: Row( Container(
mainAxisAlignment: height: Get.height * 0.04,
MainAxisAlignment.spaceAround, width: Get.width * 0.21,
children: [ decoration: BoxDecoration(
SizedBox( color: const Color(0xFF004791),
height: 24, borderRadius: BorderRadius.circular(10),
width: 24,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
Text(
product.quantity.toString(),
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
SizedBox(
height: 24,
width: 24,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
],
),
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.delete_outline_rounded,
color: Colors.red,
),
)
],
)
: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C),
padding: const EdgeInsets.symmetric(
horizontal: 18, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
), ),
child: Text( child: Row(
"Add To Cart", mainAxisAlignment: MainAxisAlignment.spaceAround,
style: GoogleFonts.roboto( children: [
fontSize: 14, SizedBox(
fontWeight: FontWeight.w600, height: 24,
), width: 24,
child: ElevatedButton(
onPressed: () {
_cartController.decreaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'-',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
Text(
"${currentQuantity}",
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
SizedBox(
height: 22,
width: 22,
child: ElevatedButton(
onPressed: () {
_cartController.increaseQuantity(widget.productModel!);
setState(() {
currentQuantity = _cartController
.cartList
.firstWhere((p) => p.id == widget.productModel!.id)
.quantity;
});
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
'+',
style: GoogleFonts.roboto(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
),
),
],
), ),
), ),
], SizedBox(
) width: 2.0,
),
IconButton(
onPressed: () {
_cartController.removeFromCart(widget.productModel!);
showSnackbar("Product has been removed successfully!");
setState(() {
currentQuantity = 1;
});
},
icon: const Icon(
Icons.delete_outline_rounded,
color: Colors.red,
),
),
],
)
: ElevatedButton(
onPressed: () {
if (isProductInCart) {
showSnackbar("Product already added to cart");
} else {
_cartController.addToCart(widget.productModel!);
showSnackbar("Product successfully added to your cart");
}
},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C),
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
child: Text(
"Add To Cart",
style: GoogleFonts.roboto(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
),
], ],
), ),
), ),

View File

@ -6,6 +6,14 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { 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);
} }

View File

@ -3,6 +3,8 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
url_launcher_linux
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -5,10 +5,28 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import device_info_plus
import file_selector_macos
import firebase_analytics
import firebase_core
import firebase_crashlytics
import firebase_messaging
import flutter_local_notifications
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation import shared_preferences_foundation
import syncfusion_pdfviewer_macos
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
} }

View File

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: ddc6f775260b89176d329dee26f88b9469ef46aa3228ff6a0b91caf2b2989692
url: "https://pub.dev"
source: hosted
version: "1.3.42"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -17,6 +25,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.11.0"
auto_size_text:
dependency: "direct main"
description:
name: auto_size_text
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -49,6 +65,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev"
source: hosted
version: "0.3.4+2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -57,6 +89,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.3"
csc_picker:
dependency: "direct main"
description:
name: csc_picker
sha256: "7e5d6023a81f53b89a7fb0369953fd4dc676f7ea20e9a0c0707973a5f0aedf14"
url: "https://pub.dev"
source: hosted
version: "0.2.7"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -65,6 +105,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
dbus:
dependency: transitive
description:
name: dbus
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
url: "https://pub.dev"
source: hosted
version: "10.1.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
dio: dio:
dependency: "direct main" dependency: "direct main"
description: description:
@ -105,6 +169,134 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.0.0"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
url: "https://pub.dev"
source: hosted
version: "0.9.2+1"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
url: "https://pub.dev"
source: hosted
version: "0.9.4"
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: "2ad726953f6e8affbc4df8dc78b77c3b4a060967a291e528ef72ae846c60fb69"
url: "https://pub.dev"
source: hosted
version: "0.9.3+2"
firebase_analytics:
dependency: "direct main"
description:
name: firebase_analytics
sha256: "7b5ae39d853ead76f9d030dc23389bfec4ea826d7cccb4eea4873dcb0cdd172b"
url: "https://pub.dev"
source: hosted
version: "11.3.1"
firebase_analytics_platform_interface:
dependency: transitive
description:
name: firebase_analytics_platform_interface
sha256: "0205e05bb37abd29d5dec5cd89aeb04f3f58bf849aad21dd938be0507d52a40c"
url: "https://pub.dev"
source: hosted
version: "4.2.3"
firebase_analytics_web:
dependency: transitive
description:
name: firebase_analytics_web
sha256: "434807f8b30526e21cc062410c28ee5c6680a13626c4443b5ffede29f84b0c74"
url: "https://pub.dev"
source: hosted
version: "0.5.10"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "40921de9795fbf5887ed5c0adfdf4972d5a8d7ae7e1b2bb98dea39bc02626a88"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: f7d7180c7f99babd4b4c517754d41a09a4943a0f7a69b65c894ca5c68ba66315
url: "https://pub.dev"
source: hosted
version: "5.2.1"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: f4ee170441ca141c5f9ee5ad8737daba3ee9c8e7efb6902aee90b4fbd178ce25
url: "https://pub.dev"
source: hosted
version: "2.18.0"
firebase_crashlytics:
dependency: "direct main"
description:
name: firebase_crashlytics
sha256: c4fdbb14ba6f36794f89dc27fb5c759c9cc67ecbaeb079edc4dba515bbf9f555
url: "https://pub.dev"
source: hosted
version: "4.1.1"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
sha256: "891d6f7ba4b93672d0e1265f27b6a9dccd56ba2cc30ce6496586b32d1d8770ac"
url: "https://pub.dev"
source: hosted
version: "3.6.42"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: cc02c4afd6510cd84586020670140c4a23fbe52af16cd260ccf8ede101bb8d1b
url: "https://pub.dev"
source: hosted
version: "15.1.1"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: d8a4984635f09213302243ea670fe5c42f3261d7d8c7c0a5f7dcd5d6c84be459
url: "https://pub.dev"
source: hosted
version: "4.5.44"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "258b9d637965db7855299b123533609ed95e52350746a723dfd1d8d6f3fac678"
url: "https://pub.dev"
source: hosted
version: "3.9.0"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -118,6 +310,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: c500d5d9e7e553f06b61877ca6b9c8b92c570a4c8db371038702e8ce57f8a50f
url: "https://pub.dev"
source: hosted
version: "17.2.2"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
url: "https://pub.dev"
source: hosted
version: "4.0.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
url: "https://pub.dev"
source: hosted
version: "7.2.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
url: "https://pub.dev"
source: hosted
version: "2.0.22"
flutter_svg: flutter_svg:
dependency: "direct main" dependency: "direct main"
description: description:
@ -144,6 +368,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.6.6" version: "4.6.6"
get_storage:
dependency: "direct main"
description:
name: get_storage
sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
google_fonts: google_fonts:
dependency: "direct main" dependency: "direct main"
description: description:
@ -152,6 +384,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.1" version: "6.2.1"
hive:
dependency: transitive
description:
name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
hive_flutter:
dependency: "direct main"
description:
name: hive_flutter
sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
url: "https://pub.dev"
source: hosted
version: "1.1.0"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
@ -168,22 +416,102 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" 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: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56"
url: "https://pub.dev"
source: hosted
version: "0.8.12+12"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "65d94623e15372c5c51bebbcb820848d7bcb323836e12dfdba60b5d3a8b39e50"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447"
url: "https://pub.dev"
source: hosted
version: "0.8.12"
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: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
url: "https://pub.dev"
source: hosted
version: "0.2.1+1"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
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:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.19.0"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.4" version: "10.0.5"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.5"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
@ -200,6 +528,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
logger:
dependency: "direct main"
description:
name: logger
sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -212,18 +548,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.0" version: "0.11.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.12.0" version: "1.15.0"
mime:
dependency: transitive
description:
name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -320,6 +664,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.8" version: "2.1.8"
pretty_dio_logger:
dependency: "direct main"
description:
name: pretty_dio_logger
sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@ -389,6 +741,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -413,6 +773,70 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: "6e67726b85812afc7105725a23620b876ab7f6b04b8410e211330ffb8c2cdbe8"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_flutter_pdf:
dependency: transitive
description:
name: syncfusion_flutter_pdf
sha256: "59a1173dc34a1fac0a41aff7a2bb6f3c1578f1bfd749ea8b24379018434ba5a5"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_flutter_pdfviewer:
dependency: "direct main"
description:
name: syncfusion_flutter_pdfviewer
sha256: b54ffe621a0e2155cfc913ee55efcd160e2dc8d21c2b9185f4a9996e0ccc9424
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_flutter_signaturepad:
dependency: transitive
description:
name: syncfusion_flutter_signaturepad
sha256: "5f8955d4ee64f342b389928111ebfad041e75003415eedee802f3af1d4ce7036"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_pdfviewer_macos:
dependency: transitive
description:
name: syncfusion_pdfviewer_macos
sha256: "1eec60fe44cc357072a0b872e4b0a82edef741463fda2b3a95a6973d7a615ec1"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_pdfviewer_platform_interface:
dependency: transitive
description:
name: syncfusion_pdfviewer_platform_interface
sha256: e128a2875226dc1d922ac0366d0804aa0ee7a52be23799cc6d84d78fd32ce092
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_pdfviewer_web:
dependency: transitive
description:
name: syncfusion_pdfviewer_web
sha256: "5625c2e658e5d680ea240ea5f5daedf6a0acd563cec026a38b8cb5643783ce4f"
url: "https://pub.dev"
source: hosted
version: "26.2.14"
syncfusion_pdfviewer_windows:
dependency: transitive
description:
name: syncfusion_pdfviewer_windows
sha256: f6c56fea4b77ada9d7ddab6ed67a4a25317a2efd1007309e8938c01f1d952b20
url: "https://pub.dev"
source: hosted
version: "26.2.14"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -425,10 +849,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" version: "0.7.2"
timezone:
dependency: transitive
description:
name: timezone
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
url: "https://pub.dev"
source: hosted
version: "0.9.4"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -437,6 +869,78 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.2"
url_launcher:
dependency: transitive
description:
name: url_launcher
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev"
source: hosted
version: "6.3.0"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
url: "https://pub.dev"
source: hosted
version: "6.3.9"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
url: "https://pub.dev"
source: hosted
version: "6.3.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
url: "https://pub.dev"
source: hosted
version: "3.2.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
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: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
uuid:
dependency: transitive
description:
name: uuid
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
url: "https://pub.dev"
source: hosted
version: "4.5.0"
vector_graphics: vector_graphics:
dependency: transitive dependency: transitive
description: description:
@ -473,10 +977,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.1" version: "14.2.4"
web: web:
dependency: transitive dependency: transitive
description: description:
@ -485,6 +989,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
win32:
dependency: transitive
description:
name: win32
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
url: "https://pub.dev"
source: hosted
version: "5.5.4"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -41,6 +41,20 @@ dependencies:
dio: ^5.5.0+1 dio: ^5.5.0+1
http: ^1.2.2 http: ^1.2.2
shared_preferences: ^2.2.3 shared_preferences: ^2.2.3
logger: ^2.4.0
get_storage: ^2.1.1
intl: ^0.19.0
hive_flutter: ^1.1.0
syncfusion_flutter_pdfviewer: ^26.2.14
image_picker: ^1.1.2
csc_picker: ^0.2.7
auto_size_text: ^3.0.0
firebase_core: ^3.3.0
firebase_messaging: ^15.0.4
flutter_local_notifications: ^17.2.1+2
firebase_crashlytics: ^4.0.4
firebase_analytics: ^11.2.1
pretty_dio_logger: ^1.3.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -6,6 +6,18 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
} }

View File

@ -3,6 +3,10 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
firebase_core
syncfusion_pdfviewer_windows
url_launcher_windows
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST