Refactor: Separate UI screens into

This commit is contained in:
Hadi Mottale 2025-07-04 18:16:00 +03:30
parent dd623f1b04
commit 8c47eb9519
3 changed files with 312 additions and 27 deletions

View File

@ -1,6 +1,12 @@
import 'package:flutter/material.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'screens/product_list_screen.dart';
import 'screens/add_edit_product_screen.dart';
void main() {
void main() async {
WidgetsFlutterBinding.ensureInitialized();
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
runApp(const MyApp());
}
@ -10,34 +16,12 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
title: 'ابزار ساده ثبت کالا',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
primarySwatch: Colors.blueGrey,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(),
home: ProductListScreen(),
);
}
}

View File

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import '../models/product.dart';
import '../services/database_helper.dart';
class AddEditProductScreen extends StatefulWidget {
final Product? product;
const AddEditProductScreen({super.key, this.product});
@override
State<AddEditProductScreen> createState() => _AddEditProductScreenState();
}
class _AddEditProductScreenState extends State<AddEditProductScreen> {
final _formKey = GlobalKey<FormState>();
late TextEditingController _nameController;
late TextEditingController _codeController;
late TextEditingController _quantityController;
late TextEditingController _priceController;
late TextEditingController _descriptionController;
late DatabaseHelper _databaseHelper;
bool get isEditing => widget.product != null;
@override
void initState() {
super.initState();
_databaseHelper = DatabaseHelper();
_nameController = TextEditingController(text: widget.product?.name);
_codeController = TextEditingController(text: widget.product?.code);
_quantityController = TextEditingController(
text: widget.product?.quantity.toString(),
);
_priceController = TextEditingController(
text: widget.product?.price.toString(),
);
_descriptionController = TextEditingController(
text: widget.product?.description,
);
}
@override
void dispose() {
_nameController.dispose();
_codeController.dispose();
_quantityController.dispose();
_priceController.dispose();
_descriptionController.dispose();
super.dispose();
}
Future<void> _saveProduct() async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
final product = Product(
id: isEditing ? widget.product!.id : null,
name: _nameController.text,
code: _codeController.text,
quantity: int.parse(_quantityController.text),
price: double.parse(_priceController.text),
description:
_descriptionController.text.isEmpty
? null
: _descriptionController.text,
);
if (isEditing) {
await _databaseHelper.updateProduct(product);
} else {
await _databaseHelper.insertProduct(product);
}
if (!mounted) return;
Navigator.pop(context, true);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(isEditing ? 'ویرایش کالا' : 'افزودن کالا'),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: ListView(
children: [
TextFormField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'نام کالا'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفا نام کالا را وارد کنید';
}
return null;
},
),
const SizedBox(height: 10),
TextFormField(
controller: _codeController,
decoration: const InputDecoration(labelText: 'کد کالا'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفا کد کالا را وارد کنید';
}
return null;
},
),
const SizedBox(height: 10),
TextFormField(
controller: _quantityController,
decoration: const InputDecoration(labelText: 'تعداد'),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفا تعداد را وارد کنید';
}
if (int.tryParse(value) == null) {
return 'تعداد باید عدد باشد';
}
return null;
},
),
const SizedBox(height: 10),
TextFormField(
controller: _priceController,
decoration: const InputDecoration(labelText: 'قیمت'),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'لطفا قیمت را وارد کنید';
}
if (double.tryParse(value) == null) {
return 'قیمت باید عدد باشد';
}
return null;
},
),
const SizedBox(height: 10),
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: 'توضیحات (اختیاری)',
),
maxLines: 3,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _saveProduct,
child: Text(isEditing ? 'ذخیره تغییرات' : 'افزودن کالا'),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,139 @@
import 'package:flutter/material.dart';
import '../services/database_helper.dart';
import '../models/product.dart';
import 'add_edit_product_screen.dart';
class ProductListScreen extends StatefulWidget {
const ProductListScreen({super.key});
@override
State<ProductListScreen> createState() => _ProductListScreenState();
}
class _ProductListScreenState extends State<ProductListScreen> {
late DatabaseHelper _databaseHelper;
List<Product> _products = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_databaseHelper = DatabaseHelper();
_loadProducts();
}
Future<void> _loadProducts() async {
setState(() {
_isLoading = true;
});
final products = await _databaseHelper.getProducts();
if (!mounted) return;
setState(() {
_products = products;
_isLoading = false;
});
}
Future<void> _deleteProduct(int id) async {
await _databaseHelper.deleteProduct(id);
_loadProducts();
}
void _navigateToAddEditProduct([Product? product]) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddEditProductScreen(product: product),
),
);
if (!mounted) return;
if (result == true) {
_loadProducts();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('لیست کالاها'), centerTitle: true),
body:
_isLoading
? const Center(child: CircularProgressIndicator())
: _products.isEmpty
? const Center(
child: Text(
'هیچ کالایی یافت نشد. برای شروع، یک کالا اضافه کنید.',
),
)
: ListView.builder(
itemCount: _products.length,
itemBuilder: (context, index) {
final product = _products[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: ListTile(
leading: CircleAvatar(
child: Text(product.quantity.toString()),
),
title: Text(product.name),
subtitle: Text(
'کد: ${product.code} | قیمت: ${product.price} تومان',
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit, color: Colors.blue),
onPressed: () => _navigateToAddEditProduct(product),
),
IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () {
showDialog(
context: context,
builder:
(context) => AlertDialog(
title: const Text('حذف کالا'),
content: Text(
'آیا مطمئنید که می‌خواهید ${product.name} را حذف کنید؟',
),
actions: [
TextButton(
onPressed:
() => Navigator.pop(context),
child: const Text('خیر'),
),
TextButton(
onPressed: () {
_deleteProduct(product.id!);
if (!mounted)
return; // Add this check
Navigator.pop(context);
},
child: const Text('بله'),
),
],
),
);
},
),
],
),
onTap: () {
_navigateToAddEditProduct(product);
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _navigateToAddEditProduct(),
child: const Icon(Icons.add),
),
);
}
}