Integration fonctionnalités V1 ( resas + gestion machines
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'wash_progress.dart';
|
||||
|
||||
/// Modèle lavage (cycle en cours ou terminé).
|
||||
class Wash {
|
||||
const Wash({
|
||||
@@ -9,6 +11,9 @@ class Wash {
|
||||
this.startedAt,
|
||||
this.endedAt,
|
||||
this.durationMinutes,
|
||||
this.machineType,
|
||||
this.cycleEndsAt,
|
||||
this.progress,
|
||||
});
|
||||
|
||||
final String uuid;
|
||||
@@ -19,14 +24,27 @@ class Wash {
|
||||
final DateTime? startedAt;
|
||||
final DateTime? endedAt;
|
||||
final int? durationMinutes;
|
||||
final String? machineType;
|
||||
final DateTime? cycleEndsAt;
|
||||
final WashProgress? progress;
|
||||
|
||||
WashProgress get liveProgress => WashProgress.compute(
|
||||
startedAt: startedAt,
|
||||
estimatedEndAt: progress?.estimatedEndAt ?? cycleEndsAt,
|
||||
durationMinutes: durationMinutes,
|
||||
machineType: machineType,
|
||||
status: status,
|
||||
);
|
||||
|
||||
factory Wash.fromJson(Map<String, dynamic> json) {
|
||||
final machine = json['machine'] as Map<String, dynamic>?;
|
||||
final progressJson = json['progress'] as Map<String, dynamic>?;
|
||||
|
||||
return Wash(
|
||||
uuid: json['uuid'] as String,
|
||||
machineUuid: machine?['uuid'] as String? ?? json['machine_uuid'] as String? ?? '',
|
||||
machineName: machine?['name'] as String? ?? 'Machine',
|
||||
machineType: machine?['type'] as String?,
|
||||
status: json['status'] as String? ?? 'pending_start',
|
||||
cost: (json['cost'] as num?)?.toDouble() ?? 0,
|
||||
startedAt: json['started_at'] != null
|
||||
@@ -36,6 +54,10 @@ class Wash {
|
||||
? DateTime.tryParse(json['ended_at'] as String)
|
||||
: null,
|
||||
durationMinutes: json['duration_minutes'] as int?,
|
||||
cycleEndsAt: machine?['cycle_ends_at'] != null
|
||||
? DateTime.tryParse(machine!['cycle_ends_at'] as String)
|
||||
: null,
|
||||
progress: progressJson != null ? WashProgress.fromJson(progressJson) : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/// Progression d'un lavage en cours.
|
||||
class WashProgress {
|
||||
const WashProgress({
|
||||
required this.percent,
|
||||
required this.phaseLabel,
|
||||
this.phase,
|
||||
this.estimatedEndAt,
|
||||
this.remainingSeconds,
|
||||
});
|
||||
|
||||
final int percent;
|
||||
final String phaseLabel;
|
||||
final String? phase;
|
||||
final DateTime? estimatedEndAt;
|
||||
final int? remainingSeconds;
|
||||
|
||||
String get remainingLabel {
|
||||
if (remainingSeconds == null) return '';
|
||||
final s = remainingSeconds!;
|
||||
if (s <= 0) return 'Bientôt terminé';
|
||||
if (s < 60) return '$s s restantes';
|
||||
final min = (s / 60).ceil();
|
||||
return '$min min restantes';
|
||||
}
|
||||
|
||||
factory WashProgress.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) {
|
||||
return const WashProgress(percent: 0, phaseLabel: 'En cours');
|
||||
}
|
||||
return WashProgress(
|
||||
percent: json['percent'] as int? ?? 0,
|
||||
phase: json['phase'] as String?,
|
||||
phaseLabel: json['phase_label'] as String? ?? 'En cours',
|
||||
estimatedEndAt: json['estimated_end_at'] != null
|
||||
? DateTime.tryParse(json['estimated_end_at'] as String)
|
||||
: null,
|
||||
remainingSeconds: json['remaining_seconds'] as int?,
|
||||
);
|
||||
}
|
||||
|
||||
/// Calcul local si pas de données API (rafraîchissement chaque seconde).
|
||||
factory WashProgress.compute({
|
||||
required DateTime? startedAt,
|
||||
required DateTime? estimatedEndAt,
|
||||
required int? durationMinutes,
|
||||
required String? machineType,
|
||||
required String status,
|
||||
}) {
|
||||
if (status == 'pending_start') {
|
||||
return const WashProgress(percent: 0, phaseLabel: 'En attente de démarrage', phase: 'pending');
|
||||
}
|
||||
|
||||
final now = DateTime.now();
|
||||
final end = estimatedEndAt ??
|
||||
(startedAt != null && durationMinutes != null
|
||||
? startedAt.add(Duration(minutes: durationMinutes))
|
||||
: null);
|
||||
|
||||
if (startedAt == null || end == null) {
|
||||
return const WashProgress(percent: 5, phaseLabel: 'Démarrage…', phase: 'lock');
|
||||
}
|
||||
|
||||
final total = end.difference(startedAt).inSeconds.clamp(1, 999999);
|
||||
final elapsed = now.difference(startedAt).inSeconds.clamp(0, total);
|
||||
final percent = ((elapsed / total) * 100).round().clamp(0, 99);
|
||||
final remaining = end.difference(now).inSeconds.clamp(0, total);
|
||||
|
||||
return WashProgress(
|
||||
percent: percent,
|
||||
phaseLabel: _phaseLabel(percent, machineType),
|
||||
phase: _phase(percent, machineType),
|
||||
estimatedEndAt: end,
|
||||
remainingSeconds: remaining,
|
||||
);
|
||||
}
|
||||
|
||||
static String _phase(int percent, String? type) {
|
||||
final isDryer = type?.startsWith('dryer') ?? false;
|
||||
if (percent < 5) return 'lock';
|
||||
if (isDryer) {
|
||||
if (percent < 15) return 'heat';
|
||||
if (percent < 85) return 'dry';
|
||||
return 'finish';
|
||||
}
|
||||
if (percent < 15) return 'fill';
|
||||
if (percent < 55) return 'wash';
|
||||
if (percent < 75) return 'rinse';
|
||||
if (percent < 90) return 'spin';
|
||||
return 'finish';
|
||||
}
|
||||
|
||||
static String _phaseLabel(int percent, String? type) {
|
||||
switch (_phase(percent, type)) {
|
||||
case 'lock':
|
||||
return 'Verrouillage';
|
||||
case 'heat':
|
||||
return 'Préchauffage';
|
||||
case 'dry':
|
||||
return 'Séchage';
|
||||
case 'fill':
|
||||
return 'Remplissage';
|
||||
case 'wash':
|
||||
return 'Lavage';
|
||||
case 'rinse':
|
||||
return 'Rinçage';
|
||||
case 'spin':
|
||||
return 'Essorage';
|
||||
case 'finish':
|
||||
return 'Finition';
|
||||
default:
|
||||
return 'En cours';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user