feat(ui): improve mobile equipment card and unify travel cost dialog

This commit is contained in:
ElPoyo
2026-06-05 19:26:07 +02:00
parent cb94badafe
commit 752b86ec58
8 changed files with 179 additions and 53 deletions
@@ -46,6 +46,8 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
int _nbTechnicians = 2;
double _hourlyRate = 25.0;
bool _applyFreeZone = false;
double _freeZoneKm = 20.0;
int _freeZoneMinutes = 20;
// Résultats
List<RouteResult> _routes = [];
@@ -142,7 +144,8 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
maintenanceCostPerKm: _selectedVehicle!.maintenanceCostPerKm,
nbTechnicians: _nbTechnicians,
hourlyRate: _hourlyRate,
applyFreeZone: _applyFreeZone,
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
);
Navigator.of(context).pop(total);
}
@@ -230,29 +233,32 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
);
}
if (_routes.isEmpty) {
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: _buildConfigPanel(),
);
}
// Résultats
final screenW = MediaQuery.of(context).size.width;
final isWide = screenW > 900;
if (isWide) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 3,
child: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
child: _routes.isEmpty
? const Center(child: Text("Configurez le trajet et cliquez sur Calculer"))
: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
),
Expanded(
flex: 2,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: _buildResultsPanel(),
child: Column(
children: [
_buildConfigPanel(),
if (_routes.isNotEmpty) ...[
const Divider(height: 32),
_buildResultsPanel(),
]
],
),
),
),
],
@@ -261,13 +267,22 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
return SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 260,
child: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
),
if (_routes.isNotEmpty)
SizedBox(
height: 260,
child: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
),
Padding(
padding: const EdgeInsets.all(16),
child: _buildResultsPanel(),
child: Column(
children: [
_buildConfigPanel(),
if (_routes.isNotEmpty) ...[
const Divider(height: 32),
_buildResultsPanel(),
]
],
),
),
],
),
@@ -413,10 +428,53 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
activeColor: AppColors.rouge,
title: const Text('Appliquer la zone de gratuité'),
subtitle:
const Text('Déduit 20 km (carburant + maintenance) et 20 min (main-d\'œuvre)'),
Text('Déduit ${_freeZoneKm.toStringAsFixed(0)} km (carburant + maintenance) et $_freeZoneMinutes min (main-d\'œuvre)'),
contentPadding: EdgeInsets.zero,
controlAffinity: ListTileControlAffinity.leading,
),
if (_applyFreeZone)
Padding(
padding: const EdgeInsets.only(left: 32, top: 8),
child: Row(
children: [
Expanded(
child: TextFormField(
initialValue: _freeZoneKm.toStringAsFixed(0),
decoration: const InputDecoration(
labelText: 'Distance déduite',
border: OutlineInputBorder(),
suffixText: 'km',
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}'))
],
onChanged: (v) {
final parsed = double.tryParse(v);
if (parsed != null) setState(() => _freeZoneKm = parsed);
},
),
),
const SizedBox(width: 16),
Expanded(
child: TextFormField(
initialValue: _freeZoneMinutes.toString(),
decoration: const InputDecoration(
labelText: 'Temps déduit',
border: OutlineInputBorder(),
suffixText: 'min',
),
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onChanged: (v) {
final parsed = int.tryParse(v);
if (parsed != null) setState(() => _freeZoneMinutes = parsed);
},
),
),
],
),
),
const SizedBox(height: 24),
@@ -492,21 +550,22 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
maintenanceCostPerKm: vehicle.maintenanceCostPerKm,
nbTechnicians: _nbTechnicians,
hourlyRate: _hourlyRate,
applyFreeZone: _applyFreeZone,
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
);
final fuel = route.fuelCost(
consumptionPer100km: vehicle.consumptionPer100km,
fuelPricePerLiter: fuelPrice,
freeZoneKm: _applyFreeZone ? 20 : 0,
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
);
final maint = route.maintenanceCost(
costPerKm: vehicle.maintenanceCostPerKm,
freeZoneKm: _applyFreeZone ? 20 : 0,
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
);
final labor = route.laborCost(
nbTechnicians: _nbTechnicians,
hourlyRate: _hourlyRate,
freeZoneMinutes: _applyFreeZone ? 20 : 0,
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
);
final isToll = route.routeType == 'TOLL';