Add equipment management features (and qr generation support)
This commit is contained in:
133
em2rp/lib/views/equipment_form/brand_model_selector.dart
Normal file
133
em2rp/lib/views/equipment_form/brand_model_selector.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:em2rp/providers/equipment_provider.dart';
|
||||
|
||||
class BrandModelSelector extends StatefulWidget {
|
||||
final TextEditingController brandController;
|
||||
final TextEditingController modelController;
|
||||
final ValueChanged<String?>? onBrandChanged;
|
||||
final List<String> filteredModels;
|
||||
final String? selectedBrand;
|
||||
final Function(List<String>) onModelsChanged;
|
||||
|
||||
const BrandModelSelector({
|
||||
super.key,
|
||||
required this.brandController,
|
||||
required this.modelController,
|
||||
this.onBrandChanged,
|
||||
required this.filteredModels,
|
||||
required this.selectedBrand,
|
||||
required this.onModelsChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BrandModelSelector> createState() => _BrandModelSelectorState();
|
||||
}
|
||||
|
||||
class _BrandModelSelectorState extends State<BrandModelSelector> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Consumer<EquipmentProvider>(
|
||||
builder: (context, provider, child) {
|
||||
return Autocomplete<String>(
|
||||
initialValue: TextEditingValue(text: widget.brandController.text),
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
if (textEditingValue.text.isEmpty) {
|
||||
return provider.brands;
|
||||
}
|
||||
return provider.brands.where((String brand) {
|
||||
return brand.toLowerCase().contains(
|
||||
textEditingValue.text.toLowerCase(),
|
||||
);
|
||||
});
|
||||
},
|
||||
onSelected: (String selection) async {
|
||||
widget.brandController.text = selection;
|
||||
widget.onBrandChanged?.call(selection);
|
||||
final equipmentProvider = Provider.of<EquipmentProvider>(context, listen: false);
|
||||
final models = await equipmentProvider.loadModelsByBrand(selection);
|
||||
widget.onModelsChanged(models);
|
||||
},
|
||||
fieldViewBuilder: (context, controller, focusNode, onEditingComplete) {
|
||||
if (controller.text != widget.brandController.text) {
|
||||
controller.text = widget.brandController.text;
|
||||
}
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Marque *',
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.business),
|
||||
helperText: 'Champ obligatoire',
|
||||
),
|
||||
onChanged: (value) async {
|
||||
widget.brandController.text = value;
|
||||
widget.modelController.clear();
|
||||
widget.onBrandChanged?.call(value.isNotEmpty ? value : null);
|
||||
if (value.isNotEmpty) {
|
||||
final equipmentProvider = Provider.of<EquipmentProvider>(context, listen: false);
|
||||
final models = await equipmentProvider.loadModelsByBrand(value);
|
||||
widget.onModelsChanged(models);
|
||||
} else {
|
||||
widget.onModelsChanged([]);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Autocomplete<String>(
|
||||
initialValue: TextEditingValue(text: widget.modelController.text),
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
if (widget.selectedBrand == null || widget.selectedBrand!.isEmpty) {
|
||||
return const Iterable<String>.empty();
|
||||
}
|
||||
if (textEditingValue.text.isEmpty) {
|
||||
return widget.filteredModels;
|
||||
}
|
||||
return widget.filteredModels.where((String model) {
|
||||
return model.toLowerCase().contains(
|
||||
textEditingValue.text.toLowerCase(),
|
||||
);
|
||||
});
|
||||
},
|
||||
onSelected: (String selection) {
|
||||
widget.modelController.text = selection;
|
||||
},
|
||||
fieldViewBuilder: (context, controller, focusNode, onEditingComplete) {
|
||||
if (controller.text != widget.modelController.text) {
|
||||
controller.text = widget.modelController.text;
|
||||
}
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
enabled: widget.selectedBrand != null && widget.selectedBrand!.isNotEmpty,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Modèle *',
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.inventory_2),
|
||||
hintText: widget.selectedBrand == null || widget.selectedBrand!.isEmpty
|
||||
? 'Marque requise'
|
||||
: 'Saisissez le modèle',
|
||||
helperText: 'Champ obligatoire',
|
||||
),
|
||||
onChanged: (value) {
|
||||
widget.modelController.text = value;
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
26
em2rp/lib/views/equipment_form/id_generator.dart
Normal file
26
em2rp/lib/views/equipment_form/id_generator.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:em2rp/services/equipment_service.dart';
|
||||
|
||||
class EquipmentIdGenerator {
|
||||
static String generate({required String brand, required String model, int? number}) {
|
||||
final brandTrim = brand.trim().replaceAll(' ', '_');
|
||||
final modelTrim = model.trim().replaceAll(' ', '_');
|
||||
if (brandTrim.isEmpty && modelTrim.isEmpty) {
|
||||
return 'EQ-${DateTime.now().millisecondsSinceEpoch}${number != null ? '_$number' : ''}';
|
||||
}
|
||||
final brandPrefix = brandTrim.length >= 4 ? brandTrim.substring(0, 4) : brandTrim;
|
||||
String baseId = modelTrim.isNotEmpty ? '${brandPrefix}_$modelTrim' : (brandPrefix.isNotEmpty ? brandPrefix : 'EQ');
|
||||
if (number != null) {
|
||||
baseId += '_#$number';
|
||||
}
|
||||
return baseId;
|
||||
}
|
||||
|
||||
static Future<String> ensureUniqueId(String baseId, EquipmentService service) async {
|
||||
if (await service.isIdUnique(baseId)) {
|
||||
return baseId;
|
||||
}
|
||||
return '${baseId}_${DateTime.now().millisecondsSinceEpoch}';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user