handle product
This commit is contained in:
parent
12f9fd063a
commit
fbf4cea2e1
@ -13,6 +13,7 @@ import '../Components/app_bar.dart';
|
|||||||
import '../Models/produit.dart';
|
import '../Models/produit.dart';
|
||||||
import '../Services/productDatabase.dart';
|
import '../Services/productDatabase.dart';
|
||||||
|
|
||||||
|
|
||||||
class ProductManagementPage extends StatefulWidget {
|
class ProductManagementPage extends StatefulWidget {
|
||||||
const ProductManagementPage({super.key});
|
const ProductManagementPage({super.key});
|
||||||
|
|
||||||
@ -31,13 +32,7 @@ class _ProductManagementPageState extends State<ProductManagementPage> {
|
|||||||
|
|
||||||
// Catégories prédéfinies pour l'ajout de produits
|
// Catégories prédéfinies pour l'ajout de produits
|
||||||
final List<String> _predefinedCategories = [
|
final List<String> _predefinedCategories = [
|
||||||
'Sucré',
|
'Sucré', 'Salé', 'Jus', 'Gateaux', 'Snacks', 'Boissons', 'Non catégorisé'
|
||||||
'Salé',
|
|
||||||
'Jus',
|
|
||||||
'Gateaux',
|
|
||||||
'Snacks',
|
|
||||||
'Boissons',
|
|
||||||
'Non catégorisé'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -53,14 +48,19 @@ class _ProductManagementPageState extends State<ProductManagementPage> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//======================================================================================================
|
//======================================================================================================
|
||||||
// Ajoutez ces variables à la classe _ProductManagementPageState
|
// Ajoutez ces variables à la classe _ProductManagementPageState
|
||||||
bool _isImporting = false;
|
bool _isImporting = false;
|
||||||
double _importProgress = 0.0;
|
double _importProgress = 0.0;
|
||||||
String _importStatusText = '';
|
String _importStatusText = '';
|
||||||
|
|
||||||
// Ajoutez ces méthodes à la classe _ProductManagementPageState
|
// Ajoutez ces méthodes à la classe _ProductManagementPageState
|
||||||
|
|
||||||
void _resetImportState() {
|
void _resetImportState() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isImporting = false;
|
_isImporting = false;
|
||||||
@ -195,137 +195,6 @@ Future<void> _importFromExcel() async {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_isImporting = false;
|
|
||||||
_importProgress = 0.0;
|
|
||||||
_importStatusText = '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showExcelCompatibilityError() {
|
|
||||||
Get.dialog(
|
|
||||||
AlertDialog(
|
|
||||||
title: const Text('Fichier Excel incompatible'),
|
|
||||||
content: const Text(
|
|
||||||
'Ce fichier Excel contient des éléments qui ne sont pas compatibles avec notre système d\'importation.\n\n'
|
|
||||||
'Solutions recommandées :\n'
|
|
||||||
'• Téléchargez notre modèle Excel et copiez-y vos données\n'
|
|
||||||
'• Ou exportez votre fichier en format simple: Classeur Excel .xlsx depuis Excel\n'
|
|
||||||
'• Ou créez un nouveau fichier Excel simple sans formatage complexe'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Get.back(),
|
|
||||||
child: const Text('Annuler'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
_downloadExcelTemplate();
|
|
||||||
},
|
|
||||||
child: const Text('Télécharger modèle'),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _downloadExcelTemplate() async {
|
|
||||||
try {
|
|
||||||
final excel = Excel.createExcel();
|
|
||||||
excel.delete('Sheet1');
|
|
||||||
excel.copy('Sheet1', 'Produits');
|
|
||||||
excel.delete('Sheet1');
|
|
||||||
|
|
||||||
final sheet = excel['Produits'];
|
|
||||||
|
|
||||||
final headers = ['Nom', 'Prix', 'Catégorie', 'Description', 'Stock'];
|
|
||||||
for (int i = 0; i < headers.length; i++) {
|
|
||||||
final cell =
|
|
||||||
sheet.cell(CellIndex.indexByColumnRow(columnIndex: i, rowIndex: 0));
|
|
||||||
cell.value = headers[i];
|
|
||||||
cell.cellStyle = CellStyle(
|
|
||||||
bold: true,
|
|
||||||
backgroundColorHex: '#E8F4FD',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final examples = [
|
|
||||||
['Croissant', '1.50', 'Sucré', 'Délicieux croissant beurré', '20'],
|
|
||||||
['Sandwich jambon', '4.00', 'Salé', 'Sandwich fait maison', '15'],
|
|
||||||
['Jus d\'orange', '2.50', 'Jus', 'Jus d\'orange frais', '30'],
|
|
||||||
[
|
|
||||||
'Gâteau chocolat',
|
|
||||||
'18.00',
|
|
||||||
'Gateaux',
|
|
||||||
'Gâteau au chocolat portion 8 personnes',
|
|
||||||
'5'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
for (int row = 0; row < examples.length; row++) {
|
|
||||||
for (int col = 0; col < examples[row].length; col++) {
|
|
||||||
final cell = sheet.cell(
|
|
||||||
CellIndex.indexByColumnRow(columnIndex: col, rowIndex: row + 1));
|
|
||||||
cell.value = examples[row][col];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sheet.setColWidth(0, 20);
|
|
||||||
sheet.setColWidth(1, 10);
|
|
||||||
sheet.setColWidth(2, 15);
|
|
||||||
sheet.setColWidth(3, 30);
|
|
||||||
sheet.setColWidth(4, 10);
|
|
||||||
|
|
||||||
final bytes = excel.save();
|
|
||||||
|
|
||||||
if (bytes == null) {
|
|
||||||
Get.snackbar('Erreur', 'Impossible de créer le fichier modèle');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String? outputFile = await FilePicker.platform.saveFile(
|
|
||||||
fileName: 'modele_import_produits.xlsx',
|
|
||||||
allowedExtensions: ['xlsx'],
|
|
||||||
type: FileType.custom,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (outputFile != null) {
|
|
||||||
try {
|
|
||||||
await File(outputFile).writeAsBytes(bytes);
|
|
||||||
Get.snackbar(
|
|
||||||
'Succès',
|
|
||||||
'Modèle téléchargé avec succès\n$outputFile',
|
|
||||||
duration: const Duration(seconds: 4),
|
|
||||||
backgroundColor: Colors.green,
|
|
||||||
colorText: Colors.white,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
Get.snackbar('Erreur', 'Impossible d\'écrire le fichier: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Get.snackbar('Erreur', 'Erreur lors de la création du modèle: $e');
|
|
||||||
debugPrint('Erreur création modèle Excel: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _importFromExcel() async {
|
|
||||||
try {
|
|
||||||
final result = await FilePicker.platform.pickFiles(
|
|
||||||
type: FileType.custom,
|
|
||||||
allowedExtensions: ['xlsx', 'xls', 'csv'],
|
|
||||||
allowMultiple: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null || result.files.isEmpty) {
|
|
||||||
Get.snackbar('Annulé', 'Aucun fichier sélectionné');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isImporting = true;
|
_isImporting = true;
|
||||||
_importProgress = 0.0;
|
_importProgress = 0.0;
|
||||||
@ -372,13 +241,11 @@ Future<void> _importFromExcel() async {
|
|||||||
_resetImportState();
|
_resetImportState();
|
||||||
debugPrint('Erreur décodage Excel: $e');
|
debugPrint('Erreur décodage Excel: $e');
|
||||||
|
|
||||||
if (e.toString().contains('styles') ||
|
if (e.toString().contains('styles') || e.toString().contains('Damaged')) {
|
||||||
e.toString().contains('Damaged')) {
|
|
||||||
_showExcelCompatibilityError();
|
_showExcelCompatibilityError();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Erreur',
|
Get.snackbar('Erreur', 'Impossible de lire le fichier Excel. Format non supporté.');
|
||||||
'Impossible de lire le fichier Excel. Format non supporté.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,12 +350,10 @@ Future<void> _importFromExcel() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String reference = _generateUniqueReference();
|
String reference = _generateUniqueReference();
|
||||||
var existingProduct =
|
var existingProduct = await _productDatabase.getProductByReference(reference);
|
||||||
await _productDatabase.getProductByReference(reference);
|
|
||||||
while (existingProduct != null) {
|
while (existingProduct != null) {
|
||||||
reference = _generateUniqueReference();
|
reference = _generateUniqueReference();
|
||||||
existingProduct =
|
existingProduct = await _productDatabase.getProductByReference(reference);
|
||||||
await _productDatabase.getProductByReference(reference);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final product = Product(
|
final product = Product(
|
||||||
@ -511,6 +376,7 @@ Future<void> _importFromExcel() async {
|
|||||||
|
|
||||||
await _productDatabase.createProduct(product);
|
await _productDatabase.createProduct(product);
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorCount++;
|
errorCount++;
|
||||||
errorMessages.add('Ligne ${i + 1}: Erreur de traitement - $e');
|
errorMessages.add('Ligne ${i + 1}: Erreur de traitement - $e');
|
||||||
@ -546,15 +412,16 @@ Future<void> _importFromExcel() async {
|
|||||||
|
|
||||||
// Recharger la liste des produits après importation
|
// Recharger la liste des produits après importation
|
||||||
_loadProducts();
|
_loadProducts();
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_resetImportState();
|
_resetImportState();
|
||||||
Get.snackbar('Erreur', 'Erreur lors de l\'importation Excel: $e');
|
Get.snackbar('Erreur', 'Erreur lors de l\'importation Excel: $e');
|
||||||
debugPrint('Erreur générale import Excel: $e');
|
debugPrint('Erreur générale import Excel: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ajoutez ce widget dans votre méthode build, par exemple dans la partie supérieure
|
// Ajoutez ce widget dans votre méthode build, par exemple dans la partie supérieure
|
||||||
Widget _buildImportProgressIndicator() {
|
Widget _buildImportProgressIndicator() {
|
||||||
if (!_isImporting) return const SizedBox.shrink();
|
if (!_isImporting) return const SizedBox.shrink();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
@ -601,8 +468,7 @@ Future<void> _importFromExcel() async {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================================================================
|
//=============================================================================================================================
|
||||||
Future<void> _loadProducts() async {
|
Future<void> _loadProducts() async {
|
||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
@ -674,8 +540,7 @@ Future<void> _importFromExcel() async {
|
|||||||
final path = '${directory.path}/$reference.png';
|
final path = '${directory.path}/$reference.png';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final picData =
|
final picData = await painter.toImageData(2048, format: ImageByteFormat.png);
|
||||||
await painter.toImageData(2048, format: ImageByteFormat.png);
|
|
||||||
if (picData != null) {
|
if (picData != null) {
|
||||||
await File(path).writeAsBytes(picData.buffer.asUint8List());
|
await File(path).writeAsBytes(picData.buffer.asUint8List());
|
||||||
} else {
|
} else {
|
||||||
@ -695,8 +560,7 @@ Future<void> _importFromExcel() async {
|
|||||||
final descriptionController = TextEditingController();
|
final descriptionController = TextEditingController();
|
||||||
final imageController = TextEditingController();
|
final imageController = TextEditingController();
|
||||||
|
|
||||||
String selectedCategory =
|
String selectedCategory = _predefinedCategories.last; // 'Non catégorisé' par défaut
|
||||||
_predefinedCategories.last; // 'Non catégorisé' par défaut
|
|
||||||
File? pickedImage;
|
File? pickedImage;
|
||||||
String? qrPreviewData;
|
String? qrPreviewData;
|
||||||
String? currentReference;
|
String? currentReference;
|
||||||
@ -724,8 +588,7 @@ Future<void> _importFromExcel() async {
|
|||||||
color: Colors.green.shade100,
|
color: Colors.green.shade100,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child:
|
child: Icon(Icons.add_shopping_cart, color: Colors.green.shade700),
|
||||||
Icon(Icons.add_shopping_cart, color: Colors.green.shade700),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
const Text('Ajouter un produit'),
|
const Text('Ajouter un produit'),
|
||||||
@ -751,13 +614,11 @@ Future<void> _importFromExcel() async {
|
|||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.info,
|
Icon(Icons.info, color: Colors.red.shade600, size: 16),
|
||||||
color: Colors.red.shade600, size: 16),
|
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const Text(
|
const Text(
|
||||||
'Les champs marqués d\'un * sont obligatoires',
|
'Les champs marqués d\'un * sont obligatoires',
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
|
||||||
fontSize: 12, fontWeight: FontWeight.w500),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -788,10 +649,9 @@ Future<void> _importFromExcel() async {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: priceController,
|
controller: priceController,
|
||||||
keyboardType: const TextInputType.numberWithOptions(
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||||
decimal: true),
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Prix (MGA) *',
|
labelText: 'Prix (FCFA) *',
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
prefixIcon: const Icon(Icons.attach_money),
|
prefixIcon: const Icon(Icons.attach_money),
|
||||||
filled: true,
|
filled: true,
|
||||||
@ -820,10 +680,8 @@ Future<void> _importFromExcel() async {
|
|||||||
// Catégorie
|
// Catégorie
|
||||||
DropdownButtonFormField<String>(
|
DropdownButtonFormField<String>(
|
||||||
value: selectedCategory,
|
value: selectedCategory,
|
||||||
items: _predefinedCategories
|
items: _predefinedCategories.map((category) =>
|
||||||
.map((category) => DropdownMenuItem(
|
DropdownMenuItem(value: category, child: Text(category))).toList(),
|
||||||
value: category, child: Text(category)))
|
|
||||||
.toList(),
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setDialogState(() => selectedCategory = value!);
|
setDialogState(() => selectedCategory = value!);
|
||||||
},
|
},
|
||||||
@ -892,13 +750,10 @@ Future<void> _importFromExcel() async {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await FilePicker.platform
|
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
||||||
.pickFiles(type: FileType.image);
|
if (result != null && result.files.single.path != null) {
|
||||||
if (result != null &&
|
|
||||||
result.files.single.path != null) {
|
|
||||||
setDialogState(() {
|
setDialogState(() {
|
||||||
pickedImage =
|
pickedImage = File(result.files.single.path!);
|
||||||
File(result.files.single.path!);
|
|
||||||
imageController.text = pickedImage!.path;
|
imageController.text = pickedImage!.path;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -921,13 +776,11 @@ Future<void> _importFromExcel() async {
|
|||||||
width: 100,
|
width: 100,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border:
|
border: Border.all(color: Colors.grey.shade300),
|
||||||
Border.all(color: Colors.grey.shade300),
|
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Image.file(pickedImage!,
|
child: Image.file(pickedImage!, fit: BoxFit.cover),
|
||||||
fit: BoxFit.cover),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -949,8 +802,7 @@ Future<void> _importFromExcel() async {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.qr_code_2,
|
Icon(Icons.qr_code_2, color: Colors.green.shade700),
|
||||||
color: Colors.green.shade700),
|
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Aperçu du QR Code',
|
'Aperçu du QR Code',
|
||||||
@ -980,8 +832,7 @@ Future<void> _importFromExcel() async {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Réf: $currentReference',
|
'Réf: $currentReference',
|
||||||
style: const TextStyle(
|
style: const TextStyle(fontSize: 10, color: Colors.grey),
|
||||||
fontSize: 10, color: Colors.grey),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -1010,15 +861,12 @@ Future<void> _importFromExcel() async {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Générer une référence unique et vérifier son unicité
|
// Générer une référence unique et vérifier son unicité
|
||||||
String finalReference =
|
String finalReference = currentReference ?? _generateUniqueReference();
|
||||||
currentReference ?? _generateUniqueReference();
|
var existingProduct = await _productDatabase.getProductByReference(finalReference);
|
||||||
var existingProduct = await _productDatabase
|
|
||||||
.getProductByReference(finalReference);
|
|
||||||
|
|
||||||
while (existingProduct != null) {
|
while (existingProduct != null) {
|
||||||
finalReference = _generateUniqueReference();
|
finalReference = _generateUniqueReference();
|
||||||
existingProduct = await _productDatabase
|
existingProduct = await _productDatabase.getProductByReference(finalReference);
|
||||||
.getProductByReference(finalReference);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Générer le QR code
|
// Générer le QR code
|
||||||
@ -1149,12 +997,9 @@ Future<void> _importFromExcel() async {
|
|||||||
|
|
||||||
void _editProduct(Product product) {
|
void _editProduct(Product product) {
|
||||||
final nameController = TextEditingController(text: product.name);
|
final nameController = TextEditingController(text: product.name);
|
||||||
final priceController =
|
final priceController = TextEditingController(text: product.price.toString());
|
||||||
TextEditingController(text: product.price.toString());
|
final stockController = TextEditingController(text: product.stock.toString());
|
||||||
final stockController =
|
final descriptionController = TextEditingController(text: product.description ?? '');
|
||||||
TextEditingController(text: product.stock.toString());
|
|
||||||
final descriptionController =
|
|
||||||
TextEditingController(text: product.description ?? '');
|
|
||||||
final imageController = TextEditingController(text: product.image);
|
final imageController = TextEditingController(text: product.image);
|
||||||
|
|
||||||
String selectedCategory = product.category;
|
String selectedCategory = product.category;
|
||||||
@ -1177,16 +1022,17 @@ Future<void> _importFromExcel() async {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
controller: priceController,
|
controller: priceController,
|
||||||
keyboardType:
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Prix*',
|
labelText: 'Prix*',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
controller: stockController,
|
controller: stockController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
@ -1196,6 +1042,7 @@ Future<void> _importFromExcel() async {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
StatefulBuilder(
|
StatefulBuilder(
|
||||||
builder: (context, setDialogState) {
|
builder: (context, setDialogState) {
|
||||||
return Column(
|
return Column(
|
||||||
@ -1215,14 +1062,11 @@ Future<void> _importFromExcel() async {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await FilePicker.platform
|
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
||||||
.pickFiles(type: FileType.image);
|
if (result != null && result.files.single.path != null) {
|
||||||
if (result != null &&
|
|
||||||
result.files.single.path != null) {
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
setDialogState(() {
|
setDialogState(() {
|
||||||
pickedImage =
|
pickedImage = File(result.files.single.path!);
|
||||||
File(result.files.single.path!);
|
|
||||||
imageController.text = pickedImage!.path;
|
imageController.text = pickedImage!.path;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1233,6 +1077,7 @@ Future<void> _importFromExcel() async {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
if (pickedImage != null || product.image!.isNotEmpty)
|
if (pickedImage != null || product.image!.isNotEmpty)
|
||||||
Container(
|
Container(
|
||||||
height: 100,
|
height: 100,
|
||||||
@ -1246,19 +1091,16 @@ Future<void> _importFromExcel() async {
|
|||||||
child: pickedImage != null
|
child: pickedImage != null
|
||||||
? Image.file(pickedImage!, fit: BoxFit.cover)
|
? Image.file(pickedImage!, fit: BoxFit.cover)
|
||||||
: (product.image!.isNotEmpty
|
: (product.image!.isNotEmpty
|
||||||
? Image.file(File(product.image!),
|
? Image.file(File(product.image!), fit: BoxFit.cover)
|
||||||
fit: BoxFit.cover)
|
|
||||||
: const Icon(Icons.image, size: 50)),
|
: const Icon(Icons.image, size: 50)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
DropdownButtonFormField<String>(
|
DropdownButtonFormField<String>(
|
||||||
value: selectedCategory,
|
value: selectedCategory,
|
||||||
items: _categories
|
items: _categories.skip(1).map((category) =>
|
||||||
.skip(1)
|
DropdownMenuItem(value: category, child: Text(category))).toList(),
|
||||||
.map((category) => DropdownMenuItem(
|
|
||||||
value: category, child: Text(category)))
|
|
||||||
.toList(),
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
setDialogState(() => selectedCategory = value!);
|
setDialogState(() => selectedCategory = value!);
|
||||||
@ -1270,6 +1112,7 @@ Future<void> _importFromExcel() async {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
TextField(
|
TextField(
|
||||||
controller: descriptionController,
|
controller: descriptionController,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
@ -1363,8 +1206,7 @@ Future<void> _importFromExcel() async {
|
|||||||
Get.snackbar('Erreur', 'Suppression échouée: $e');
|
Get.snackbar('Erreur', 'Suppression échouée: $e');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child:
|
child: const Text('Supprimer', style: TextStyle(color: Colors.white)),
|
||||||
const Text('Supprimer', style: TextStyle(color: Colors.white)),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -1426,8 +1268,7 @@ Future<void> _importFromExcel() async {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||||
horizontal: 8, vertical: 2),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue.shade100,
|
color: Colors.blue.shade100,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
@ -1576,10 +1417,8 @@ Future<void> _importFromExcel() async {
|
|||||||
),
|
),
|
||||||
child: DropdownButton<String>(
|
child: DropdownButton<String>(
|
||||||
value: _selectedCategory,
|
value: _selectedCategory,
|
||||||
items: _categories
|
items: _categories.map((category) =>
|
||||||
.map((category) => DropdownMenuItem(
|
DropdownMenuItem(value: category, child: Text(category))).toList(),
|
||||||
value: category, child: Text(category)))
|
|
||||||
.toList(),
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCategory = value!;
|
_selectedCategory = value!;
|
||||||
@ -1609,8 +1448,7 @@ Future<void> _importFromExcel() async {
|
|||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_searchController.text.isNotEmpty ||
|
if (_searchController.text.isNotEmpty || _selectedCategory != 'Tous')
|
||||||
_selectedCategory != 'Tous')
|
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user