
This will add a line like this to your package’s pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
sqflite: ^2.4.1
get: ^4.6.6
Main class
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'productviewscreen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo', theme: ThemeData(), home: ProductDetailScreen());
}
}
Explanation of Components:
main
Function
- Purpose: The entry point of the app, calling
runApp
withMyApp
as the root widget. - Significance: Starts the Flutter app and initializes the widget tree.
MyApp
Class
- Type: StatelessWidget.
- Purpose: The root widget of the application that provides global configurations like theme and navigation.
- Key Features:
- Wraps the app with
GetMaterialApp
, a GetX-provided widget for enhanced navigation, routing, and state management.
- Wraps the app with
Imports
addproduct.dart
: Manages the form and logic for adding new products to the app.product_viewmodel.dart
: Contains theProductController
, a ViewModel for handling product data and business logic.productviewscreen.dart
: Represents the screen where users can view and manage the list of products.
GetMaterialApp
- Purpose: A specialized version of Flutter’s
MaterialApp
, offering built-in features for GetX state management and routing. - Key Properties:
title
: Sets the app’s title displayed in the task manager or system-level UI.theme
: Configures the visual appearance of the app.home
: Specifies the initial screen (ProductDetailScreen
) displayed when the app launches.
Summary
This app uses the GetX package for:
- Streamlined Navigation: Simplifies routing without boilerplate.
- Reactive State Management: Automatically updates the UI based on state changes in the
ProductController
. - Dependency Injection: Manages dependencies efficiently, ensuring scalability and maintainability.
Product Model
class ProductModel {
// Fields to represent the attributes of a product
int? id; // Unique identifier for the product, can be null for new products
int? itemCode; // Optional item code for the product
String productName; // Name of the product
String category; // Category to which the product belongs
String brand; // Brand of the product
double price; // Selling price of the product
double quantity; // Quantity available for the product
String manufacture; // Manufacturer or manufacturing details
double purchasePrice; // Purchase price of the product
double margin; // Profit margin for the product
DateTime date; // Date associated with the product (e.g., added date)
// Constructor to initialize the fields
ProductModel({
this.id,
this.itemCode,
required this.productName,
required this.category,
required this.brand,
required this.price,
required this.quantity,
required this.manufacture,
required this.purchasePrice,
required this.margin,
required this.date,
});
/// `copyWith` Method:
/// This creates a copy of the current `ProductModel` with updated values.
/// Any field not provided in the parameters will retain its current value.
ProductModel copyWith({
int? id,
int? itemCode,
String? productName,
String? category,
String? brand,
double? price,
double? quantity,
String? manufacture,
double? purchasePrice,
double? margin,
DateTime? date,
}) {
return ProductModel(
id: id ?? this.id, // Use new `id` if provided, otherwise retain current value
itemCode: itemCode ?? this.itemCode,
productName: productName ?? this.productName,
category: category ?? this.category,
brand: brand ?? this.brand,
price: price ?? this.price,
quantity: quantity ?? this.quantity,
manufacture: manufacture ?? this.manufacture,
purchasePrice: purchasePrice ?? this.purchasePrice,
margin: margin ?? this.margin,
date: date ?? this.date,
);
}
/// Converts the `ProductModel` object into a `Map<String, dynamic>`.
/// Useful for saving the object to a database or serializing it.
Map<String, dynamic> toMap() {
return {
'id': id,
'itemCode': itemCode,
'productName': productName,
'category': category,
'brand': brand,
'price': price,
'quantity': quantity,
'manufacture': manufacture,
'purchasePrice': purchasePrice,
'margin': margin,
'date': date.toIso8601String(), // Converts `DateTime` to ISO8601 string format
};
}
/// Converts a `Map<String, dynamic>` back into a `ProductModel` object.
/// Useful for reading the object from a database or deserializing it.
static ProductModel fromMap(Map<String, dynamic> json) {
return ProductModel(
id: json['id'] as int?, // Extract `id` as an integer (nullable)
itemCode: json['itemCode'] as int?, // Extract `itemCode` as an integer (nullable)
productName: json['productName'] as String, // Extract `productName` as a string
category: json['category'] as String, // Extract `category` as a string
brand: json['brand'] as String, // Extract `brand` as a string
price: json['price'] as double, // Extract `price` as a double
quantity: json['quantity'] as double, // Extract `quantity` as a double
manufacture: json['manufacture'] as String, // Extract `manufacture` as a string
purchasePrice: json['purchasePrice'] as double, // Extract `purchasePrice` as a double
margin: json['margin'] as double, // Extract `margin` as a double
date: DateTime.parse(json['date'] as String), // Parse `date` from a string
);
}
}
Explanation of Key Components:
- Fields:
- Represent the product’s attributes such as
id
,itemCode
,price
, etc.
- Represent the product’s attributes such as
- Constructor:
- Ensures required fields like
productName
,price
, andquantity
must always be provided when creating aProductModel
object.
- Ensures required fields like
copyWith
Method:- Provides a convenient way to create a modified copy of a
ProductModel
object without mutating the original.
- Provides a convenient way to create a modified copy of a
toMap
Method:- Transforms the
ProductModel
object into aMap<String, dynamic>
. This format is ideal for storing in SQLite, Firebase, or other databases.
- Transforms the
fromMap
Method:- Reconstructs a
ProductModel
object from aMap<String, dynamic>
. This is particularly useful when retrieving data from a database or deserializing JSON responses.
- Reconstructs a
- Date Handling:
- The
date
field usestoIso8601String()
for serialization andDateTime.parse()
for deserialization, ensuring compatibility with various storage and API formats.
- The
ProductController
import 'package:get/get.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'model.dart'; // Ensure this imports your ProductModel class
class ProductController extends GetxController {
late Database db;
var products = <ProductModel>[].obs;
@override
void onInit() {
super.onInit();
_initDatabase();
}
Future<void> _initDatabase() async {
try {
String path = join(await getDatabasesPath(), 'products.db');
db = await openDatabase(
path,
version: 1,
onCreate: (db, version) {
return db.execute('''
CREATE TABLE products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
itemCode INTEGER,
productName TEXT,
category TEXT,
brand TEXT,
price REAL,
quantity REAL,
manufacture TEXT,
purchasePrice REAL,
margin REAL,
date TEXT
)
''');
},
);
fetchProducts();
} catch (e) {
print('Database Initialization Error: $e');
}
}
Future<void> fetchProducts() async {
try {
final List<Map<String, dynamic>> maps = await db.query('products');
products.value = maps.map((map) => ProductModel.fromMap(map)).toList();
} catch (e) {
print('Error Fetching Products: $e');
}
}
Future<void> addProduct(ProductModel product) async {
try {
await db.insert('products', product.toMap());
fetchProducts();
} catch (e) {
print('Error Adding Product: $e');
}
}
Future<void> updateProduct(int id, ProductModel updatedProduct) async {
try {
await db.update(
'products',
updatedProduct.toMap(),
where: 'id = ?',
whereArgs: [id],
);
fetchProducts(); // Refresh the list after the update
} catch (e) {
print('Error Updating Product: $e');
}
}
Future<void> deleteProduct(int id) async {
try {
await db.delete(
'products',
where: 'id = ?',
whereArgs: [id],
);
fetchProducts(); // Refresh the list after deletion
} catch (e) {
print('Error Deleting Product: $e');
}
}
}
This code snippet defines a ProductController
class that uses the GetX
package for state management and sqflite
for local database management in a Flutter application. Here’s an overview of what each part does:
onInit()
Method: This is called when theProductController
is initialized. It calls_initDatabase()
to set up the local database._initDatabase()
Method: It initializes the SQLite database. ThegetDatabasesPath()
method gets the path where the database will be stored, andopenDatabase()
is used to open the database. If the database doesn’t exist, it will create a new one with aproducts
table.fetchProducts()
Method: This method queries the database for all products and updates theproducts
list, which is an observable (RxList<ProductModel>
). TheProductModel.fromMap()
method is used to convert the database result into product objects.addProduct(ProductModel product)
Method: This method inserts a new product into the database and then callsfetchProducts()
to reload the product list.
updateProduct(int id, ProductModel updatedProduct) Method: This method is used to update the details of an existing product in the database. It takes two parameters: the product’s unique id
and the updated ProductModel
object.
- The
db.update()
function updates the record in theproducts
table, matching the specifiedid
, with the new values from theupdatedProduct
object (converted into a map usingtoMap()
). - After successfully updating the database, it calls
fetchProducts()
to refresh the observable product list, ensuring that the UI reflects the updated product details. - If an error occurs during the update, it is caught and logged to the console for debugging purposes.
add Product Screen
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'model.dart';
import 'product_viewmodel.dart';
class AddProductScreen extends StatelessWidget {
final ProductController controller = Get.find<ProductController>();
final _formKey = GlobalKey<FormState>();
final TextEditingController nameController = TextEditingController();
final TextEditingController categoryController = TextEditingController();
final TextEditingController brandController = TextEditingController();
final TextEditingController priceController = TextEditingController();
final TextEditingController quantityController = TextEditingController();
final TextEditingController manufactureController = TextEditingController();
final TextEditingController purchasePriceController = TextEditingController();
final TextEditingController marginController = TextEditingController();
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Add Product'),
backgroundColor: Colors.deepPurple,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: ListView(
children: [
Text(
'Fill in the details below to add a new product',
style: theme.textTheme.titleLarge!
.copyWith(color: Colors.grey[700]),
),
SizedBox(height: 20),
_buildTextField(
controller: nameController,
label: 'Product Name',
validator: (value) => value == null || value.isEmpty
? 'Enter product name'
: null,
),
_buildTextField(
controller: categoryController,
label: 'Category',
),
_buildTextField(
controller: brandController,
label: 'Brand',
),
_buildTextField(
controller: priceController,
label: 'Price',
keyboardType: TextInputType.number,
),
_buildTextField(
controller: quantityController,
label: 'Quantity',
keyboardType: TextInputType.number,
),
_buildTextField(
controller: manufactureController,
label: 'Manufacture',
),
_buildTextField(
controller: purchasePriceController,
label: 'Purchase Price',
keyboardType: TextInputType.number,
),
_buildTextField(
controller: marginController,
label: 'Margin',
keyboardType: TextInputType.number,
),
SizedBox(height: 30),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
controller.addProduct(ProductModel(
productName: nameController.text,
category: categoryController.text,
brand: brandController.text,
price: double.tryParse(priceController.text) ?? 0,
quantity: double.tryParse(quantityController.text) ?? 0,
manufacture: manufactureController.text,
purchasePrice:
double.tryParse(purchasePriceController.text) ?? 0,
margin: double.tryParse(marginController.text) ?? 0,
date: DateTime.now(),
));
Get.back();
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
padding: EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
'Add Product',
style: TextStyle(fontSize: 18),
),
),
],
),
),
),
);
}
Widget _buildTextField({
required TextEditingController controller,
required String label,
TextInputType keyboardType = TextInputType.text,
String? Function(String?)? validator,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
controller: controller,
keyboardType: keyboardType,
validator: validator,
decoration: InputDecoration(
labelText: label,
labelStyle: TextStyle(color: Colors.deepPurple),
filled: true,
fillColor: Colors.grey[100],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.deepPurple, width: 2),
borderRadius: BorderRadius.circular(10),
),
),
),
);
}
}
This Flutter code defines a screen (AddProductScreen
) for adding a product to a local database using a form. It employs the GetX
package for state management and organizes the input fields using a Form
widget to handle validation.
Key Parts of the Code:
- Form and Validation:
- A
GlobalKey<FormState>
is used to manage the form state and trigger validation. - Several
TextEditingController
objects are defined for each field (e.g.,nameController
,priceController
, etc.). - The
TextFormField
widget is used for each input, with validation functions to ensure required fields are filled. For example, the product name field ensures that the user doesn’t leave it empty.
- A
- Text Fields:
- Each text field is wrapped in a custom
_buildTextField
widget. This widget accepts aTextEditingController
, alabel
,keyboardType
, and an optionalvalidator
function. - The fields include
Product Name
,Category
,Brand
,Price
,Quantity
,Manufacture
,Purchase Price
, andMargin
. - The fields for numeric values (like price, quantity, etc.) use
TextInputType.number
to make sure the keyboard is appropriate.
- Each text field is wrapped in a custom
- Form Submission:
- When the “Add Product” button is pressed, it checks if the form is valid by calling
_formKey.currentState!.validate()
. - If the form is valid, it creates a new
ProductModel
object using the data entered in the form fields and then calls theaddProduct()
method on theProductController
to add the product to the database. - After adding the product, the screen is popped from the navigation stack (
Get.back()
), returning to the previous screen.
- When the “Add Product” button is pressed, it checks if the form is valid by calling
- Product Model:
- The
ProductModel
constructor is used to create a new product object. It includes properties likeproductName
,category
,brand
,price
, etc., that are populated with the data from the controllers. - The
date
is set to the current timestamp (DateTime.now()
).
- The
- UI Design:
- The
Scaffold
provides the basic structure of the page with anAppBar
titled “Add Product” and a body containing aForm
. - The
TextFormField
widgets have a consistent style with a purple theme for labels, borders, and a rounded shape. - The
ElevatedButton
is styled with a deep purple background, rounded corners, and padding for a modern look.
- The
Detailed Explanation of AddProductScreen
:
- Form Structure:
- The
Form
widget contains aListView
to enable scrolling, especially if the keyboard is visible. - Each input field is placed inside
_buildTextField()
, which applies consistent styling. - A validator is provided for the
Product Name
field, ensuring the user cannot submit an empty name.
- The
- Button Handling:
- The “Add Product” button performs form validation. If all fields are valid, it adds the product to the database via
controller.addProduct()
. - After the product is added, the user is returned to the previous screen using
Get.back()
.
- The “Add Product” button performs form validation. If all fields are valid, it adds the product to the database via
- UI Styling:
- Colors are defined using
Colors.deepPurple
for the button and label colors. - The form fields are styled with a light background (
Colors.grey[100]
), rounded borders, and focused borders that change color when selected.
- Colors are defined using
ProductViewScreen
This Flutter code defines a ProductDetailScreen that displays a list of products fetched from a local database, using GetX for state management and reactive updates. The screen provides the ability to view, update, delete, and add products.
Key Components:
ProductController Initialization:
The ProductController is instantiated using Get.put(ProductController()). This makes the controller available for the screen and manages the state of products. The ProductController is responsible for fetching and deleting products from the database.
Reactive State with Obx:
Obx() is used to observe the controller.products list. It automatically rebuilds the widget whenever the products list is updated (e.g., when a product is added, updated, or deleted).
If the controller.products list is empty, a message ("No Products Found.") is displayed using Center().
Otherwise, a ListView.builder is used to display the list of products.
ListView to Display Products:
Each product is displayed inside a Card widget with a ListTile.
The title of the ListTile displays the product's name (product.productName).
The subtitle contains the product's price and category.
The trailing section of the ListTile has two action buttons: an edit button and a delete button.
Update Button to Edit Products:
An edit button, represented by the Icons.edit icon, is included in the trailing section of each product's ListTile.
Clicking this button navigates to the UpdateProductScreen, passing the selected product as a parameter.
The update functionality allows users to modify the product's details, such as name, price, or category. After editing, the updated product is saved back to the database or state, and the UI dynamically reflects the changes.
Product Deletion:
Each product also has a delete button (represented by the Icons.delete icon). Clicking this button triggers the deleteProduct method from the ProductController, which deletes the product from the database using the product's ID.
Floating Action Button to Add Products:
A FloatingActionButton is placed at the bottom right of the screen, which navigates to the AddProductScreen when clicked. This allows the user to add new products.
The Get.to(() => AddProductScreen()) is used to navigate to the AddProductScreen where users can input product details.
Detailed Explanation:
State Management:
The ProductController is used to manage the state of products. The list of products is observed by the Obx widget, which triggers a UI update whenever the product list changes. Obx ensures that only the part of the widget tree that depends on controller.products is rebuilt, making the UI more efficient.
Product List Display:
If there are products, the ListView.builder creates a list item for each product. The ListTile widget shows the product name, price, and category.
If the product list is empty, a message is shown telling the user that no products are available.
Navigation:
The edit button uses Get.to(() => UpdateProductScreen(product: product)) to navigate to the update screen for editing the selected product.
The delete button calls controller.deleteProduct(product.id!) to remove the product from the list.
The floating action button navigates to the "Add Product" screen.
UI Components:
AppBar: Displays the title "Product List" at the top of the screen.
Card: Used to style the individual product entries in the list, giving them a material design look.
ListTile: Used to display the product's name and other details like price and category.
IconButton: Allows the user to edit or delete a product.
FloatingActionButton: A button that allows the user to navigate to the "Add Product" screen.import 'package:blockgame/viewModel.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'UPDATESCREEN.DART';
import 'addproduct.dart';
class ProductDetailScreen extends StatelessWidget {
final ProductController controller = Get.put(ProductController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Product List')),
body: Obx(() {
if (controller.products.isEmpty) {
return Center(child: Text('No Products Found.'));
}
return ListView.builder(
itemCount: controller.products.length,
itemBuilder: (context, index) {
final product = controller.products[index];
return Card(
child: ListTile(
title: Text(product.productName),
subtitle: Text(
'Price: ${product.price}\nCategory: ${product.category}'),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Get.to(() => UpdateProductScreen(product: product));
},
),
),
);
},
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.to(() => AddProductScreen());
},
child: Icon(Icons.add),
),
);
}
}
This Flutter code defines a ProductDetailScreen that displays a list of products fetched from a local database, using GetX for state management and reactive updates. The screen provides the ability to view, update, delete, and add products.
Key Components:
ProductController Initialization:
The ProductController is instantiated using Get.put(ProductController())
. This makes the controller available for the screen and manages the state of products. The ProductController is responsible for fetching and deleting products from the database.
Reactive State with Obx:
Obx()
is used to observe the controller.products
list. It automatically rebuilds the widget whenever the products list is updated (e.g., when a product is added, updated, or deleted).
- If the
controller.products
list is empty, a message (“No Products Found.”) is displayed usingCenter()
. - Otherwise, a
ListView.builder
is used to display the list of products.
ListView to Display Products:
Each product is displayed inside a Card
widget with a ListTile
.
- The title of the
ListTile
displays the product’s name (product.productName
). - The subtitle contains the product’s price and category.
- The trailing section of the
ListTile
has two action buttons: an edit button and a delete button.
Update Button to Edit Products:
- An edit button, represented by the
Icons.edit
icon, is included in the trailing section of each product’sListTile
. - Clicking this button navigates to the
UpdateProductScreen
, passing the selected product as a parameter. - The update functionality allows users to modify the product’s details, such as name, price, or category. After editing, the updated product is saved back to the database or state, and the UI dynamically reflects the changes.
Product Deletion:
Each product also has a delete button (represented by the Icons.delete
icon). Clicking this button triggers the deleteProduct
method from the ProductController
, which deletes the product from the database using the product’s ID.
Floating Action Button to Add Products:
A FloatingActionButton
is placed at the bottom right of the screen, which navigates to the AddProductScreen
when clicked. This allows the user to add new products.
The Get.to(() => AddProductScreen())
is used to navigate to the AddProductScreen
where users can input product details.
Detailed Explanation:
State Management:
The ProductController
is used to manage the state of products. The list of products is observed by the Obx
widget, which triggers a UI update whenever the product list changes. Obx
ensures that only the part of the widget tree that depends on controller.products
is rebuilt, making the UI more efficient.
Product List Display:
If there are products, the ListView.builder
creates a list item for each product. The ListTile
widget shows the product name, price, and category.
If the product list is empty, a message is shown telling the user that no products are available.
Navigation:
- The edit button uses
Get.to(() => UpdateProductScreen(product: product))
to navigate to the update screen for editing the selected product. - The delete button calls
controller.deleteProduct(product.id!)
to remove the product from the list. - The floating action button navigates to the “Add Product” screen.
UI Components:
- AppBar: Displays the title “Product List” at the top of the screen.
- Card: Used to style the individual product entries in the list, giving them a material design look.
- ListTile: Used to display the product’s name and other details like price and category.
- IconButton: Allows the user to edit or delete a product.
- FloatingActionButton: A button that allows the user to navigate to the “Add Product” screen.
Update Screen
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'viewModel.dart'; // Import the ProductController and ProductModel
import 'package:blockgame/model.dart'; // Adjust this path to your actual file location
class UpdateProductScreen extends StatelessWidget {
final ProductModel product;
final ProductController controller = Get.find();
UpdateProductScreen({required this.product});
final TextEditingController productNameController = TextEditingController();
final TextEditingController priceController = TextEditingController();
final TextEditingController categoryController = TextEditingController();
final TextEditingController brandController = TextEditingController();
final TextEditingController quantityController = TextEditingController();
final TextEditingController manufactureController = TextEditingController();
final TextEditingController purchasePriceController = TextEditingController();
final TextEditingController marginController = TextEditingController();
@override
Widget build(BuildContext context) {
// Initialize controllers with product details
productNameController.text = product.productName;
priceController.text = product.price.toString();
categoryController.text = product.category;
brandController.text = product.brand;
quantityController.text = product.quantity.toString();
manufactureController.text = product.manufacture;
purchasePriceController.text = product.purchasePrice.toString();
marginController.text = product.margin.toString();
return Scaffold(
appBar: AppBar(title: Text('Update Product')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
children: [
TextField(
controller: productNameController,
decoration: InputDecoration(labelText: 'Product Name'),
),
TextField(
controller: priceController,
decoration: InputDecoration(labelText: 'Price'),
keyboardType: TextInputType.number,
),
TextField(
controller: categoryController,
decoration: InputDecoration(labelText: 'Category'),
),
TextField(
controller: brandController,
decoration: InputDecoration(labelText: 'Brand'),
),
TextField(
controller: quantityController,
decoration: InputDecoration(labelText: 'Quantity'),
keyboardType: TextInputType.number,
),
TextField(
controller: manufactureController,
decoration: InputDecoration(labelText: 'Manufacture Date'),
),
TextField(
controller: purchasePriceController,
decoration: InputDecoration(labelText: 'Purchase Price'),
keyboardType: TextInputType.number,
),
TextField(
controller: marginController,
decoration: InputDecoration(labelText: 'Margin'),
keyboardType: TextInputType.number,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Create an updated product model without updating the date
final updatedProduct = ProductModel(
id: product.id,
productName: productNameController.text,
price: double.tryParse(priceController.text) ?? 0.0,
category: categoryController.text,
brand: brandController.text,
quantity: double.tryParse(quantityController.text) ?? 0.0,
manufacture: manufactureController.text,
purchasePrice: double.tryParse(purchasePriceController.text) ?? 0.0,
margin: double.tryParse(marginController.text) ?? 0.0,
date: product.date, // Retain the original date
);
// Update product in the database
controller.updateProduct(product.id!, updatedProduct);
// Navigate back after update
Get.back();
},
child: Text('Update Product'),
),
],
),
),
),
);
}
}
This Flutter code defines an UpdateProductScreen
, which allows the user to update the details of an existing product. The screen uses the GetX package for state management and navigation. It pre-populates the form fields with the product’s current data and saves the updated details when the user submits the form.
Key Components:
1. Input Parameters:
ProductModel product
: The product to be updated is passed to this screen.ProductController
: The controller instance is obtained usingGet.find()
, which ensures the same instance of the controller is shared across screens.
2. TextEditingControllers:
- Several
TextEditingController
objects are initialized to manage the input fields for product details:productNameController
priceController
categoryController
brandController
quantityController
manufactureController
purchasePriceController
marginController
4. UI Layout:
- The screen is built using a
Scaffold
containing:- AppBar: Displays the title “Update Product.”
- Body: A
SingleChildScrollView
with aColumn
ofTextField
widgets for each product attribute (e.g., name, price, category). Each field has a corresponding label to guide the user.
5. Update Button:
- An
ElevatedButton
labeled “Update Product” is included. - When pressed:
- A new
ProductModel
is created using the updated values from the input fields. - The
updateProduct
method fromProductController
is called with the product’sid
and the updated model. - The screen navigates back to the previous screen using
Get.back()
.
- A new
6. Key Considerations:
- Date Retention: The
date
field is not updated. Instead, the original value (product.date
) is retained. - Data Validation: Values like
price
,quantity
,purchasePrice
, andmargin
are parsed todouble
usingdouble.tryParse()
to handle invalid or empty inputs safely.
Detailed Explanation:
State Management:
- The
ProductController
manages the state of the products, including updating them in the database or local state.
Pre-Populated Form:
- The product’s current details are displayed in the form, making it easier for users to modify only the fields they want to change.
Dynamic Updates:
- After editing the product and pressing “Update Product,” the
updateProduct
method inProductController
updates the product in the database or state. The use ofGet.back()
ensures smooth navigation back to the previous screen.
UI Design:
- TextField Widgets: Each product attribute is represented by a
TextField
, providing an intuitive way for users to input or modify data. - Keyboard Types: Numeric fields (e.g., price, quantity) use
keyboardType: TextInputType.number
for better user experience.
Example Workflow:
- The user navigates to the
UpdateProductScreen
from the product list. - The form is pre-filled with the selected product’s details.
- The user modifies the desired fields.
- On clicking the “Update Product” button:
- The controller updates the product details.
- The app navigates back to the previous screen, displaying the updated product list.
Key Functions:
- Pre-Filling Details: Ensures that users do not have to re-enter all the product details, making the editing process quicker and more efficient.
- Validation and Type Conversion: Handles potential input errors gracefully by using
double.tryParse()
. - State Update and Navigation: Uses the
updateProduct
method inProductController
to save changes andGet.back()
for seamless navigation.