Skip to content

Commit 307c4bc

Browse files
authored
Merge branch 'flutter' into connect_device
2 parents 32a2671 + 589775f commit 307c4bc

File tree

3 files changed

+177
-10
lines changed

3 files changed

+177
-10
lines changed

lib/providers/barometer_state_provider.dart

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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;

lib/view/barometer_screen.dart

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ import 'dart:async';
2424

2525
class BarometerScreen extends StatefulWidget {
2626
final dynamic isExperiment;
27+
final List<List<dynamic>>? playbackData;
28+
2729
const BarometerScreen({
2830
super.key,
2931
this.isExperiment = false,
32+
this.playbackData,
3033
});
3134
@override
3235
State<StatefulWidget> createState() => _BarometerScreenState();
@@ -286,12 +289,28 @@ class _BarometerScreenState extends State<BarometerScreen> {
286289
create: (context) {
287290
final configProvider =
288291
Provider.of<BarometerConfigProvider>(context, listen: false);
289-
_provider = BarometerStateProvider(configProvider)
290-
..initializeSensors(
291-
onError: _showSensorErrorSnackbar,
292-
i2c: _i2c,
293-
scienceLab: _scienceLab,
294-
);
292+
_provider = BarometerStateProvider(configProvider);
293+
294+
_provider.onPlaybackEnd = () {
295+
if (mounted && Navigator.canPop(context)) {
296+
Navigator.pop(context);
297+
}
298+
};
299+
300+
WidgetsBinding.instance.addPostFrameCallback((_) {
301+
if (mounted) {
302+
if (widget.playbackData != null) {
303+
_provider.startPlayback(widget.playbackData!);
304+
} else {
305+
_provider.initializeSensors(
306+
onError: _showSensorErrorSnackbar,
307+
i2c: _i2c,
308+
scienceLab: _scienceLab,
309+
);
310+
}
311+
}
312+
});
313+
295314
return _provider;
296315
},
297316
update: (context, configProvider, previous) {
@@ -303,11 +322,26 @@ class _BarometerScreenState extends State<BarometerScreen> {
303322
Consumer<BarometerStateProvider>(
304323
builder: (context, provider, child) {
305324
return CommonScaffold(
306-
title: appLocalizations.barometerTitle,
325+
title: provider.isPlayingBack
326+
? '${appLocalizations.barometerTitle} - ${appLocalizations.playback}'
327+
: appLocalizations.barometerTitle,
307328
onGuidePressed: _showInstrumentGuide,
308-
onOptionsPressed: _showOptionsMenu,
309-
onRecordPressed: _toggleRecording,
329+
onOptionsPressed:
330+
provider.isPlayingBack ? null : _showOptionsMenu,
331+
onRecordPressed: provider.isPlayingBack ? null : _toggleRecording,
310332
isRecording: provider.isRecording,
333+
isPlayingBack: provider.isPlayingBack,
334+
isPlaybackPaused: provider.isPlaybackPaused,
335+
onPlaybackPauseResume: provider.isPlayingBack
336+
? (provider.isPlaybackPaused
337+
? _provider.resumePlayback
338+
: _provider.pausePlayback)
339+
: null,
340+
onPlaybackStop: provider.isPlayingBack
341+
? () async {
342+
await _provider.stopPlayback();
343+
}
344+
: null,
311345
body: SafeArea(
312346
child: LayoutBuilder(builder: (context, constraints) {
313347
final isLargeScreen = constraints.maxWidth > 900;

lib/view/logged_data_screen.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
33
import 'package:intl/intl.dart';
44
import 'package:pslab/others/csv_service.dart';
55
import 'package:pslab/theme/colors.dart';
6+
import 'package:pslab/view/barometer_screen.dart';
67
import 'package:pslab/view/gyroscope_screen.dart';
78
import 'package:pslab/view/logged_data_chart_screen.dart';
89
import 'package:pslab/view/luxmeter_screen.dart';
@@ -178,6 +179,14 @@ class _LoggedDataScreenState extends State<LoggedDataScreen> {
178179
),
179180
);
180181
break;
182+
case 'barometer':
183+
Navigator.push(
184+
context,
185+
MaterialPageRoute(
186+
builder: (context) => BarometerScreen(playbackData: data),
187+
),
188+
);
189+
break;
181190
case 'gyroscope':
182191
Navigator.push(
183192
context,
@@ -323,6 +332,7 @@ class _LoggedDataScreenState extends State<LoggedDataScreen> {
323332
mainAxisSize: MainAxisSize.min,
324333
children: [
325334
if (widget.instrumentName == "soundmeter" ||
335+
widget.instrumentName == "barometer" ||
326336
widget.instrumentName == "gyroscope" ||
327337
widget.instrumentName == "luxmeter")
328338
IconButton(

0 commit comments

Comments
 (0)