diff --git a/lib/providers/accelerometer_state_provider.dart b/lib/providers/accelerometer_state_provider.dart index 9dfde23de..0eb94159f 100644 --- a/lib/providers/accelerometer_state_provider.dart +++ b/lib/providers/accelerometer_state_provider.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:pslab/others/logger_service.dart'; import 'package:sensors_plus/sensors_plus.dart'; import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; class AccelerometerStateProvider extends ChangeNotifier { AccelerometerEvent _accelerometerEvent = @@ -22,6 +23,9 @@ class AccelerometerStateProvider extends ChangeNotifier { double _xMin = 0, _xMax = 0; double _yMin = 0, _yMax = 0; double _zMin = 0, _zMax = 0; + bool _isRecording = false; + List> _recordedData = []; + bool get isRecording => _isRecording; void initializeSensors() { _accelerometerSubscription = accelerometerEventStream().listen( @@ -53,6 +57,19 @@ class AccelerometerStateProvider extends ChangeNotifier { final x = _accelerometerEvent.x; final y = _accelerometerEvent.y; final z = _accelerometerEvent.z; + if (_isRecording) { + final now = DateTime.now(); + final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS'); + _recordedData.add([ + now.millisecondsSinceEpoch.toString(), + dateFormat.format(now), + x.toStringAsFixed(6), + y.toStringAsFixed(6), + z.toStringAsFixed(6), + 0, + 0 + ]); + } _xData.add(x); _yData.add(y); @@ -82,6 +99,28 @@ class AccelerometerStateProvider extends ChangeNotifier { notifyListeners(); } + void startRecording() { + _isRecording = true; + _recordedData = [ + [ + 'Timestamp', + 'DateTime', + 'ReadingsX', + 'ReadingsY', + 'ReadingsZ', + 'Latitude', + 'Longitude' + ] + ]; + notifyListeners(); + } + + List> stopRecording() { + _isRecording = false; + notifyListeners(); + return _recordedData; + } + List getAxisData(String axis) { switch (axis) { case 'x': diff --git a/lib/view/accelerometer_screen.dart b/lib/view/accelerometer_screen.dart index 49c489aa5..c8ef68e57 100644 --- a/lib/view/accelerometer_screen.dart +++ b/lib/view/accelerometer_screen.dart @@ -6,9 +6,12 @@ import 'package:pslab/view/widgets/guide_widget.dart'; import 'package:pslab/providers/accelerometer_state_provider.dart'; import 'package:pslab/view/widgets/common_scaffold_widget.dart'; import 'package:pslab/view/widgets/accelerometer_card.dart'; +import 'package:pslab/others/csv_service.dart'; +import 'package:pslab/view/logged_data_screen.dart'; import '../providers/accelerometer_config_provider.dart'; import '../theme/colors.dart'; +import '../constants.dart'; import 'accelerometer_config_screen.dart'; class AccelerometerScreen extends StatefulWidget { @@ -22,6 +25,27 @@ class _AccelerometerScreenState extends State { AppLocalizations appLocalizations = getIt.get(); bool _showGuide = false; static const imagePath = 'assets/images/bh1750_schematic.png'; + final CsvService _csvService = CsvService(); + late AccelerometerStateProvider _provider; + + @override + void initState() { + super.initState(); + _provider = AccelerometerStateProvider(); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + _provider.initializeSensors(); + } + }); + } + + @override + void dispose() { + _provider.disposeSensors(); + _provider.dispose(); + super.dispose(); + } + void _showInstrumentGuide() { setState(() { _showGuide = true; @@ -80,7 +104,7 @@ class _AccelerometerScreenState extends State { if (value != null) { switch (value) { case 'show_logged_data': - // TODO + _navigateToLoggedData(); break; case 'accelerometer_config': _navigateToConfig(); @@ -90,6 +114,19 @@ class _AccelerometerScreenState extends State { }); } + Future _navigateToLoggedData() async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LoggedDataScreen( + instrumentName: 'accelerometer', + appBarName: appLocalizations.accelerometer, + instrumentIcon: instrumentIcons[7], + ), + ), + ); + } + void _navigateToConfig() { Navigator.push( context, @@ -102,36 +139,124 @@ class _AccelerometerScreenState extends State { ); } + Future _toggleRecording() async { + if (_provider.isRecording) { + final data = _provider.stopRecording(); + await _showSaveFileDialog(data); + } else { + _provider.startRecording(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + '${appLocalizations.recordingStarted}...', + style: TextStyle(color: snackBarContentColor), + ), + backgroundColor: snackBarBackgroundColor, + ), + ); + } + } + + Future _showSaveFileDialog(List> data) async { + final TextEditingController filenameController = TextEditingController(); + final String defaultFilename = ''; + filenameController.text = defaultFilename; + + final String? fileName = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(appLocalizations.saveRecording), + content: TextField( + controller: filenameController, + decoration: InputDecoration( + hintText: appLocalizations.enterFileName, + labelText: appLocalizations.fileName, + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(appLocalizations.cancel.toUpperCase()), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(context, filenameController.text); + }, + child: Text(appLocalizations.save), + ), + ], + ); + }, + ); + + if (fileName != null) { + _csvService.writeMetaData('accelerometer', data); + final file = + await _csvService.saveCsvFile('accelerometer', fileName, data); + if (mounted) { + if (file != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + '${appLocalizations.fileSaved}: ${file.path.split('/').last}', + style: TextStyle(color: snackBarContentColor), + ), + backgroundColor: snackBarBackgroundColor, + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + appLocalizations.failedToSave, + style: TextStyle(color: snackBarContentColor), + ), + backgroundColor: snackBarBackgroundColor, + ), + ); + } + } + } + } + @override Widget build(BuildContext context) { - return MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (_) => AccelerometerStateProvider()..initializeSensors(), - ), - ], + return ChangeNotifierProvider.value( + value: _provider, child: Stack(children: [ - CommonScaffold( - title: appLocalizations.accelerometerTitle, - onGuidePressed: _showInstrumentGuide, - onOptionsPressed: _showOptionsMenu, - body: SafeArea( + Consumer( + builder: (context, provider, child) { + return CommonScaffold( + title: appLocalizations.accelerometerTitle, + onGuidePressed: _showInstrumentGuide, + onOptionsPressed: _showOptionsMenu, + onRecordPressed: _toggleRecording, + isRecording: provider.isRecording, + body: SafeArea( child: Column( - children: [ - Expanded( - child: AccelerometerCard( - color: xOrientationChartLineColor, - axis: appLocalizations.xAxis)), - Expanded( - child: AccelerometerCard( - color: yOrientationChartLineColor, - axis: appLocalizations.yAxis)), - Expanded( - child: AccelerometerCard( - color: zOrientationChartLineColor, - axis: appLocalizations.zAxis)), - ], - ))), + children: [ + Expanded( + child: AccelerometerCard( + color: xOrientationChartLineColor, + axis: appLocalizations.xAxis), + ), + Expanded( + child: AccelerometerCard( + color: yOrientationChartLineColor, + axis: appLocalizations.yAxis), + ), + Expanded( + child: AccelerometerCard( + color: zOrientationChartLineColor, + axis: appLocalizations.zAxis), + ), + ], + ), + ), + ); + }, + ), if (_showGuide) InstrumentOverviewDrawer( instrumentName: appLocalizations.accelerometer,