@@ -34,7 +34,15 @@ class BarometerStateProvider extends ChangeNotifier {
3434 bool _sensorAvailable = false ;
3535 bool _isRecording = false ;
3636 List <List <dynamic >> _recordedData = [];
37+ bool _isPlayingBack = false ;
38+ List <List <dynamic >>? _playbackData;
39+ int _playbackIndex = 0 ;
40+ Timer ? _playbackTimer;
41+ bool _isPlaybackPaused = false ;
42+
3743 bool get isRecording => _isRecording;
44+ bool get isPlayingBack => _isPlayingBack;
45+ bool get isPlaybackPaused => _isPlaybackPaused;
3846
3947 StreamSubscription ? _barometerSubscription;
4048
@@ -46,6 +54,7 @@ class BarometerStateProvider extends ChangeNotifier {
4654 String _currentSensorType = 'In-built Sensor' ;
4755
4856 Function (String )? onSensorError;
57+ Function ? onPlaybackEnd;
4958
5059 BarometerStateProvider (this ._configProvider) {
5160 _configProvider.addListener (_onConfigChanged);
@@ -232,6 +241,118 @@ class BarometerStateProvider extends ChangeNotifier {
232241 logger.e ("${appLocalizations .barometerSensorError } $error " );
233242 }
234243
244+ void startPlayback (List <List <dynamic >> data) {
245+ if (data.length <= 1 ) return ;
246+
247+ _isPlayingBack = true ;
248+ _isPlaybackPaused = false ;
249+ _playbackData = data;
250+ _playbackIndex = 1 ;
251+
252+ _timeTimer? .cancel ();
253+ _dataTimer? .cancel ();
254+
255+ _pressureData.clear ();
256+ pressureChartData.clear ();
257+ _timeData.clear ();
258+ _startTime = DateTime .now ().millisecondsSinceEpoch / 1000.0 ;
259+ _currentTime = 0 ;
260+ _pressureSum = 0 ;
261+ _dataCount = 0 ;
262+
263+ _startPlaybackTimer ();
264+ notifyListeners ();
265+ }
266+
267+ void _startPlaybackTimer () {
268+ if (_playbackIndex >= _playbackData! .length) {
269+ stopPlayback ();
270+ return ;
271+ }
272+
273+ final currentRow = _playbackData! [_playbackIndex];
274+ if (currentRow.length > 2 ) {
275+ _currentPressure = double .tryParse (currentRow[2 ].toString ()) ?? 0.0 ;
276+ if (currentRow.length > 3 ) {
277+ _currentAltitude = double .tryParse (currentRow[3 ].toString ());
278+ }
279+ _currentTime = (_playbackIndex - 1 ).toDouble ();
280+ _updateData ();
281+ _playbackIndex++ ;
282+ notifyListeners ();
283+ } else {
284+ logger.e (
285+ 'Skipping playback row at index $_playbackIndex due to insufficient columns (found ${currentRow .length }, expected at least 3' );
286+ _playbackIndex++ ;
287+ notifyListeners ();
288+ }
289+
290+ Duration interval = const Duration (seconds: 1 );
291+
292+ if (_playbackIndex < _playbackData! .length && _playbackIndex > 1 ) {
293+ try {
294+ final currentTimestamp =
295+ int .tryParse (_playbackData! [_playbackIndex - 1 ][0 ].toString ());
296+ final nextTimestamp =
297+ int .tryParse (_playbackData! [_playbackIndex][0 ].toString ());
298+
299+ if (currentTimestamp != null && nextTimestamp != null ) {
300+ final timeDiff = nextTimestamp - currentTimestamp;
301+ interval = Duration (milliseconds: timeDiff);
302+ if (interval.inMilliseconds < 100 ) {
303+ interval = const Duration (milliseconds: 100 );
304+ } else if (interval.inMilliseconds > 10000 ) {
305+ interval = const Duration (seconds: 10 );
306+ }
307+ }
308+ } catch (e) {
309+ interval = const Duration (seconds: 1 );
310+ }
311+ }
312+
313+ _playbackTimer = Timer (interval, () {
314+ if (_isPlayingBack && ! _isPlaybackPaused) {
315+ _startPlaybackTimer ();
316+ }
317+ });
318+ }
319+
320+ Future <void > stopPlayback () async {
321+ _isPlayingBack = false ;
322+ _isPlaybackPaused = false ;
323+ _playbackTimer? .cancel ();
324+ _playbackData = null ;
325+ _playbackIndex = 0 ;
326+
327+ _pressureData.clear ();
328+ pressureChartData.clear ();
329+ _timeData.clear ();
330+ _pressureSum = 0 ;
331+ _dataCount = 0 ;
332+ _currentPressure = 0.0 ;
333+ _currentTemperature = 0.0 ;
334+ _currentAltitude = null ;
335+ _currentTime = 0 ;
336+ notifyListeners ();
337+ onPlaybackEnd? .call ();
338+ }
339+
340+ void pausePlayback () {
341+ if (_isPlayingBack) {
342+ _isPlaybackPaused = true ;
343+ _playbackTimer? .cancel ();
344+ notifyListeners ();
345+ }
346+ }
347+
348+ void resumePlayback () {
349+ if (_isPlayingBack && _isPlaybackPaused) {
350+ _isPlaybackPaused = false ;
351+ _startPlaybackTimer ();
352+ notifyListeners ();
353+ }
354+ }
355+
235356 void disposeSensors () {
236357 logger.d ("Disposing sensors..." );
237358 _barometerSubscription? .cancel ();
@@ -240,19 +361,21 @@ class BarometerStateProvider extends ChangeNotifier {
240361 _timeTimer = null ;
241362 _dataTimer? .cancel ();
242363 _dataTimer = null ;
364+ _playbackTimer? .cancel ();
243365 _bmp180Sensor = null ;
244366 _sensorAvailable = false ;
245367 }
246368
247369 @override
248370 void dispose () {
249371 _configProvider.removeListener (_onConfigChanged);
372+ _playbackTimer? .cancel ();
250373 disposeSensors ();
251374 super .dispose ();
252375 }
253376
254377 void _updateData () {
255- if (! _sensorAvailable) return ;
378+ if (! _sensorAvailable && ! _isPlayingBack ) return ;
256379
257380 final pressure = _currentPressure;
258381 final time = _currentTime;
0 commit comments