feat(ui): improve mobile equipment card and unify travel cost dialog
This commit is contained in:
@@ -34,16 +34,17 @@ assets/assets/images/tshirt-incrust.webp,1737393735487,af7cb34adfca19c0b41c8eb63
|
|||||||
assets/assets/icons/truss.svg,1761734811263,8ddfbbb4f96de5614348eb23fa55f61b2eb1edb064719a8bbd791c35883ec4cc
|
assets/assets/icons/truss.svg,1761734811263,8ddfbbb4f96de5614348eb23fa55f61b2eb1edb064719a8bbd791c35883ec4cc
|
||||||
assets/assets/icons/tape.svg,1761734809221,631183f0ff972aa4dc3f9f51dc7abd41a607df749d1f9a44fa7e77202d95ccde
|
assets/assets/icons/tape.svg,1761734809221,631183f0ff972aa4dc3f9f51dc7abd41a607df749d1f9a44fa7e77202d95ccde
|
||||||
assets/assets/icons/flight-case.svg,1761734822495,0cef47fdf5d7efdd110763c32f792ef9735df35c4f42ae7d02d5fbda40e6148d
|
assets/assets/icons/flight-case.svg,1761734822495,0cef47fdf5d7efdd110763c32f792ef9735df35c4f42ae7d02d5fbda40e6148d
|
||||||
version.json,1779802456392,7626a7c596308bd2eb1add2ed984cd6dda5d4a3f0dedb3338244d2ae45c496cf
|
version.json,1780665878737,68547869ca05df156c49f1b529d27d6b3f9aa32f5e172ba673c2d6bfd369a89e
|
||||||
index.html,1779802461141,4e8c00552c71ef134bead8bc03706952e7a415d70fca602a3839dc02a3f7ae10
|
index.html,1780665885661,7dd070b4e8d51aa49d899690a8e2603bf8de2bd9e31f202a84d3f19ff280ae4b
|
||||||
flutter_service_worker.js,1779802555396,fadec2c9a1e8e16c22e332aef080b0b2aacc3998c4e260e5821b79afb9e000da
|
flutter_service_worker.js,1780665975318,9533de2726499249f727cb931dcb97b27a8ac01f13ccf6aa299c8d7eafb5e71e
|
||||||
flutter_bootstrap.js,1779802461128,ad20054b92acf16bb75fbffd65f81c63c6d3cb6d752f799230dca5f2118af783
|
assets/FontManifest.json,1780665970544,e38b95988f5d060cf9b7ce97cb5ac9236d6f4cc04a11d69567df97b2b4cbc5e5
|
||||||
assets/FontManifest.json,1779802551869,e38b95988f5d060cf9b7ce97cb5ac9236d6f4cc04a11d69567df97b2b4cbc5e5
|
assets/AssetManifest.json,1780665970542,a75793b913dabecfa1b5eade2735ec6f8f280210572cf25d0ce010d2a6d95e8f
|
||||||
assets/AssetManifest.json,1779802551869,0e35e7214421c832bf41b0af7c03037e66fee508b857d3143f40f6862e454dd6
|
assets/AssetManifest.bin,1780665970544,61f45b0f17a664717759ebf0f1271212f4658bd4b83e35bd5d134689b73a01d6
|
||||||
assets/AssetManifest.bin.json,1779802551869,3a244f5f866d93c17f420cc01b1ba318584b4da92af9512d9ba4acd099b49d53
|
assets/AssetManifest.bin.json,1780665970542,a26149597dbbee9aeaec0377943061e2b76c73bf974246f6af0b1a82e7455eaa
|
||||||
assets/AssetManifest.bin,1779802551869,205908d2fcf1ca9708b7d1f91ec7ea80c5f07eaf6cfc1458cb9364a4d9106907
|
flutter_bootstrap.js,1780665885636,0806f900f0da893ed0ee72b8fc42b6bed886a3c74165d69e1db4cedf41559e2a
|
||||||
assets/shaders/ink_sparkle.frag,1779802552052,591c7517d5cb43eb91ea451e0d3f9f585cbf8298cf6c46a9144b77cb0775a406
|
assets/packages/flutter_map/lib/assets/flutter_map_logo.png,1780664966224,26fe50c9203ccf93512b80d4ee1a7578184a910457b36a6a5b7d41b799efb966
|
||||||
assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1779802554433,d41473de1f7708a0702d7f19327693486512db442f6ab0cf7774e6d6576f9fcb
|
assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1780665974258,d41473de1f7708a0702d7f19327693486512db442f6ab0cf7774e6d6576f9fcb
|
||||||
assets/fonts/MaterialIcons-Regular.otf,1779802554440,710dc8fc35289048b52970355f64206fb1b2c5e67c71ae77a46b53f0e2daecd6
|
assets/shaders/ink_sparkle.frag,1780665970843,591c7517d5cb43eb91ea451e0d3f9f585cbf8298cf6c46a9144b77cb0775a406
|
||||||
assets/NOTICES,1779802551871,5522e1307c65771d1fbf26fcd9dc0548c751413f42196c4acaba5ee674eede1e
|
assets/fonts/MaterialIcons-Regular.otf,1780665974268,1551d6f32ad2bc8ed771c39fdef3fc01f0188517d44127e47ad826188ca8c82f
|
||||||
main.dart.js,1779802550741,ab892e930c97940c1ea4ff33079922082c7f688047d307acad0644a78cfda2d7
|
assets/NOTICES,1780665970544,102c38a40984e6287801c2c98c5920dab4edead49226e54933bf706c4d1bb18e
|
||||||
|
main.dart.js,1780665969500,785425f0c4c27c7197b0ed160f75ef9f98b250e39141df71b471d0138bf38888
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
|
||||||
|
|
||||||
|
## 05/06/2026
|
||||||
|
Ajout de la fonctionnalité de génération d'itinéraire avec calcul de coût.
|
||||||
|
|
||||||
## 27/05/2026
|
## 27/05/2026
|
||||||
Ajout de la fonction retour en arriere pour la validation du chargement des equipements et des conteneurs.
|
Ajout de la fonction retour en arriere pour la validation du chargement des equipements et des conteneurs.
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
/// Configuration de la version de l'application
|
/// Configuration de la version de l'application
|
||||||
class AppVersion {
|
class AppVersion {
|
||||||
static const String version = '1.2.4';
|
static const String version = '1.2.7';
|
||||||
|
|
||||||
/// Retourne la version complète de l'application
|
/// Retourne la version complète de l'application
|
||||||
static String get fullVersion => 'v$version';
|
static String get fullVersion => 'v$version';
|
||||||
|
|
||||||
|
|
||||||
/// Retourne la version avec un préfixe personnalisé
|
/// Retourne la version avec un préfixe personnalisé
|
||||||
static String getVersionWithPrefix(String prefix) => '$prefix $version';
|
static String getVersionWithPrefix(String prefix) => '$prefix $version';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,24 +72,22 @@ class RouteResult {
|
|||||||
required double maintenanceCostPerKm,
|
required double maintenanceCostPerKm,
|
||||||
required int nbTechnicians,
|
required int nbTechnicians,
|
||||||
required double hourlyRate,
|
required double hourlyRate,
|
||||||
bool applyFreeZone = false,
|
double freeZoneKm = 0,
|
||||||
|
double freeZoneMinutes = 0,
|
||||||
}) {
|
}) {
|
||||||
const freeKm = 20.0;
|
|
||||||
const freeMinutes = 20.0;
|
|
||||||
|
|
||||||
return fuelCost(
|
return fuelCost(
|
||||||
consumptionPer100km: consumptionPer100km,
|
consumptionPer100km: consumptionPer100km,
|
||||||
fuelPricePerLiter: fuelPricePerLiter,
|
fuelPricePerLiter: fuelPricePerLiter,
|
||||||
freeZoneKm: applyFreeZone ? freeKm : 0,
|
freeZoneKm: freeZoneKm,
|
||||||
) +
|
) +
|
||||||
maintenanceCost(
|
maintenanceCost(
|
||||||
costPerKm: maintenanceCostPerKm,
|
costPerKm: maintenanceCostPerKm,
|
||||||
freeZoneKm: applyFreeZone ? freeKm : 0,
|
freeZoneKm: freeZoneKm,
|
||||||
) +
|
) +
|
||||||
laborCost(
|
laborCost(
|
||||||
nbTechnicians: nbTechnicians,
|
nbTechnicians: nbTechnicians,
|
||||||
hourlyRate: hourlyRate,
|
hourlyRate: hourlyRate,
|
||||||
freeZoneMinutes: applyFreeZone ? freeMinutes : 0,
|
freeZoneMinutes: freeZoneMinutes,
|
||||||
) +
|
) +
|
||||||
tollCost;
|
tollCost;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -523,6 +523,7 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage>
|
|||||||
|
|
||||||
Widget _buildEquipmentCard(EquipmentModel equipment) {
|
Widget _buildEquipmentCard(EquipmentModel equipment) {
|
||||||
final isSelected = isItemSelected(equipment.id);
|
final isSelected = isItemSelected(equipment.id);
|
||||||
|
final isMobile = MediaQuery.of(context).size.width < 800;
|
||||||
|
|
||||||
// ✅ RepaintBoundary pour isoler le repaint de chaque carte
|
// ✅ RepaintBoundary pour isoler le repaint de chaque carte
|
||||||
return RepaintBoundary(
|
return RepaintBoundary(
|
||||||
@@ -563,9 +564,12 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage>
|
|||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
// 1. leading selection or icon
|
// 1. leading selection or icon
|
||||||
if (isSelectionMode)
|
if (isSelectionMode)
|
||||||
Padding(
|
Padding(
|
||||||
@@ -642,15 +646,15 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage>
|
|||||||
|
|
||||||
// 3. Status Badge OR Quantity Display (centered vertically in the row!)
|
// 3. Status Badge OR Quantity Display (centered vertically in the row!)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 16),
|
padding: EdgeInsets.only(right: (!isSelectionMode && !isMobile) ? 16 : 0),
|
||||||
child: (equipment.category == EquipmentCategory.consumable ||
|
child: (equipment.category == EquipmentCategory.consumable ||
|
||||||
equipment.category == EquipmentCategory.cable)
|
equipment.category == EquipmentCategory.cable)
|
||||||
? _buildQuantityDisplay(equipment)
|
? _buildQuantityDisplay(equipment)
|
||||||
: EquipmentStatusBadge(equipment: equipment),
|
: EquipmentStatusBadge(equipment: equipment),
|
||||||
),
|
),
|
||||||
|
|
||||||
// 4. Trailing Action Buttons
|
// 4. Trailing Action Buttons (Desktop inline)
|
||||||
if (!isSelectionMode)
|
if (!isSelectionMode && !isMobile)
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -711,6 +715,69 @@ class _EquipmentManagementPageState extends State<EquipmentManagementPage>
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (!isSelectionMode && isMobile) ...[
|
||||||
|
const Divider(height: 24),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
// Bouton Restock (uniquement pour consommables/câbles avec permission)
|
||||||
|
if (equipment.category == EquipmentCategory.consumable ||
|
||||||
|
equipment.category == EquipmentCategory.cable)
|
||||||
|
PermissionGate(
|
||||||
|
requiredPermissions: const ['manage_equipment'],
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.add_shopping_cart,
|
||||||
|
color: AppColors.rouge, size: 20),
|
||||||
|
tooltip: 'Restock',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => _showRestockDialog(equipment),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (equipment.category == EquipmentCategory.consumable ||
|
||||||
|
equipment.category == EquipmentCategory.cable)
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
// Bouton QR Code
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.qr_code, color: AppColors.rouge, size: 20),
|
||||||
|
tooltip: 'QR Code',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) =>
|
||||||
|
QRCodeDialog.forEquipment(equipment),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
// Bouton Modifier (permission required)
|
||||||
|
PermissionGate(
|
||||||
|
requiredPermissions: const ['manage_equipment'],
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.edit, color: AppColors.rouge, size: 20),
|
||||||
|
tooltip: 'Modifier',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => _editEquipment(equipment),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
// Bouton Supprimer (permission required)
|
||||||
|
PermissionGate(
|
||||||
|
requiredPermissions: const ['manage_equipment'],
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.delete, color: Colors.red, size: 20),
|
||||||
|
tooltip: 'Supprimer',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => _deleteEquipment(equipment),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
|
|||||||
int _nbTechnicians = 2;
|
int _nbTechnicians = 2;
|
||||||
double _hourlyRate = 25.0;
|
double _hourlyRate = 25.0;
|
||||||
bool _applyFreeZone = false;
|
bool _applyFreeZone = false;
|
||||||
|
double _freeZoneKm = 20.0;
|
||||||
|
int _freeZoneMinutes = 20;
|
||||||
|
|
||||||
// Résultats
|
// Résultats
|
||||||
List<RouteResult> _routes = [];
|
List<RouteResult> _routes = [];
|
||||||
@@ -142,7 +144,8 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
|
|||||||
maintenanceCostPerKm: _selectedVehicle!.maintenanceCostPerKm,
|
maintenanceCostPerKm: _selectedVehicle!.maintenanceCostPerKm,
|
||||||
nbTechnicians: _nbTechnicians,
|
nbTechnicians: _nbTechnicians,
|
||||||
hourlyRate: _hourlyRate,
|
hourlyRate: _hourlyRate,
|
||||||
applyFreeZone: _applyFreeZone,
|
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
|
||||||
|
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
|
||||||
);
|
);
|
||||||
Navigator.of(context).pop(total);
|
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 screenW = MediaQuery.of(context).size.width;
|
||||||
final isWide = screenW > 900;
|
final isWide = screenW > 900;
|
||||||
|
|
||||||
if (isWide) {
|
if (isWide) {
|
||||||
return Row(
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
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(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
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(
|
return SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
if (_routes.isNotEmpty)
|
||||||
height: 260,
|
SizedBox(
|
||||||
child: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
|
height: 260,
|
||||||
),
|
child: RouteMapWidget(routes: _routes, selectedRoute: _selectedRoute),
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
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,
|
activeColor: AppColors.rouge,
|
||||||
title: const Text('Appliquer la zone de gratuité'),
|
title: const Text('Appliquer la zone de gratuité'),
|
||||||
subtitle:
|
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,
|
contentPadding: EdgeInsets.zero,
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
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),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
@@ -492,21 +550,22 @@ class _TravelCostDialogState extends State<TravelCostDialog> {
|
|||||||
maintenanceCostPerKm: vehicle.maintenanceCostPerKm,
|
maintenanceCostPerKm: vehicle.maintenanceCostPerKm,
|
||||||
nbTechnicians: _nbTechnicians,
|
nbTechnicians: _nbTechnicians,
|
||||||
hourlyRate: _hourlyRate,
|
hourlyRate: _hourlyRate,
|
||||||
applyFreeZone: _applyFreeZone,
|
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
|
||||||
|
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
|
||||||
);
|
);
|
||||||
final fuel = route.fuelCost(
|
final fuel = route.fuelCost(
|
||||||
consumptionPer100km: vehicle.consumptionPer100km,
|
consumptionPer100km: vehicle.consumptionPer100km,
|
||||||
fuelPricePerLiter: fuelPrice,
|
fuelPricePerLiter: fuelPrice,
|
||||||
freeZoneKm: _applyFreeZone ? 20 : 0,
|
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
|
||||||
);
|
);
|
||||||
final maint = route.maintenanceCost(
|
final maint = route.maintenanceCost(
|
||||||
costPerKm: vehicle.maintenanceCostPerKm,
|
costPerKm: vehicle.maintenanceCostPerKm,
|
||||||
freeZoneKm: _applyFreeZone ? 20 : 0,
|
freeZoneKm: _applyFreeZone ? _freeZoneKm : 0.0,
|
||||||
);
|
);
|
||||||
final labor = route.laborCost(
|
final labor = route.laborCost(
|
||||||
nbTechnicians: _nbTechnicians,
|
nbTechnicians: _nbTechnicians,
|
||||||
hourlyRate: _hourlyRate,
|
hourlyRate: _hourlyRate,
|
||||||
freeZoneMinutes: _applyFreeZone ? 20 : 0,
|
freeZoneMinutes: _applyFreeZone ? _freeZoneMinutes.toDouble() : 0.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
final isToll = route.routeType == 'TOLL';
|
final isToll = route.routeType == 'TOLL';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "1.2.4",
|
"version": "1.2.7",
|
||||||
"updateUrl": "https://app.em2events.fr",
|
"updateUrl": "https://app.em2events.fr",
|
||||||
"forceUpdate": true,
|
"forceUpdate": true,
|
||||||
"releaseNotes": "Ajout de la fonction retour en arriere pour la validation du chargement des equipements et des conteneurs.",
|
"releaseNotes": "Ajout de la fonctionnalité de génération d'itinéraire avec calcul de coût.",
|
||||||
"timestamp": "2026-05-27T20:00:59.431Z"
|
"timestamp": "2026-06-05T14:03:37.401Z"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user