enum CalibrationPhase { idle, selectingTag, ready, collecting, done, error } const calibrationDistances = [0.5, 1.0, 2.0, 3.0]; class CalibrationState { const CalibrationState({ this.phase = CalibrationPhase.idle, this.samplesNeeded = 0, this.samplesCollected = 0, this.selectedDistance, this.completedDistances = const {}, this.waveform = const [], this.latestRssi, this.avgRssi, this.resultRssiRef, this.resultPathLossExp, this.tagRssiReadings = const {}, this.selectedTagId, this.error, }); final CalibrationPhase phase; final int samplesNeeded; final int samplesCollected; final double? selectedDistance; final Set completedDistances; /// Circular buffer of recent RSSI readings for the waveform, max 30. final List waveform; final double? latestRssi; final double? avgRssi; final double? resultRssiRef; final double? resultPathLossExp; /// Latest scan RSSI per tag device ID, updated during selectingTag phase. final Map tagRssiReadings; /// The tag device ID committed for this calibration session. final String? selectedTagId; final String? error; bool get canFinish => completedDistances.length >= 2 && phase != CalibrationPhase.collecting; double get progress => samplesNeeded == 0 ? 0 : samplesCollected / samplesNeeded; CalibrationState copyWith({ CalibrationPhase? phase, int? samplesNeeded, int? samplesCollected, double? selectedDistance, Set? completedDistances, List? waveform, double? latestRssi, double? avgRssi, double? resultRssiRef, double? resultPathLossExp, Map? tagRssiReadings, String? selectedTagId, String? error, bool clearSelectedDistance = false, bool clearLatestRssi = false, bool clearAvgRssi = false, bool clearTagRssiReadings = false, bool clearSelectedTagId = false, bool clearError = false, }) => CalibrationState( phase: phase ?? this.phase, samplesNeeded: samplesNeeded ?? this.samplesNeeded, samplesCollected: samplesCollected ?? this.samplesCollected, selectedDistance: clearSelectedDistance ? null : selectedDistance ?? this.selectedDistance, completedDistances: completedDistances ?? this.completedDistances, waveform: waveform ?? this.waveform, latestRssi: clearLatestRssi ? null : latestRssi ?? this.latestRssi, avgRssi: clearAvgRssi ? null : avgRssi ?? this.avgRssi, resultRssiRef: resultRssiRef ?? this.resultRssiRef, resultPathLossExp: resultPathLossExp ?? this.resultPathLossExp, tagRssiReadings: clearTagRssiReadings ? const {} : tagRssiReadings ?? this.tagRssiReadings, selectedTagId: clearSelectedTagId ? null : selectedTagId ?? this.selectedTagId, error: clearError ? null : error ?? this.error, ); }