Skip to content

Commit a79ee67

Browse files
feat: added csv functionalities in accelerometer screen. (#2820)
Co-authored-by: Marc Nause <[email protected]>
1 parent 023870b commit a79ee67

File tree

2 files changed

+191
-27
lines changed

2 files changed

+191
-27
lines changed

lib/providers/accelerometer_state_provider.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
55
import 'package:pslab/others/logger_service.dart';
66
import 'package:sensors_plus/sensors_plus.dart';
77
import 'package:flutter/foundation.dart';
8+
import 'package:intl/intl.dart';
89

910
class AccelerometerStateProvider extends ChangeNotifier {
1011
AccelerometerEvent _accelerometerEvent =
@@ -22,6 +23,9 @@ class AccelerometerStateProvider extends ChangeNotifier {
2223
double _xMin = 0, _xMax = 0;
2324
double _yMin = 0, _yMax = 0;
2425
double _zMin = 0, _zMax = 0;
26+
bool _isRecording = false;
27+
List<List<dynamic>> _recordedData = [];
28+
bool get isRecording => _isRecording;
2529

2630
void initializeSensors() {
2731
_accelerometerSubscription = accelerometerEventStream().listen(
@@ -53,6 +57,19 @@ class AccelerometerStateProvider extends ChangeNotifier {
5357
final x = _accelerometerEvent.x;
5458
final y = _accelerometerEvent.y;
5559
final z = _accelerometerEvent.z;
60+
if (_isRecording) {
61+
final now = DateTime.now();
62+
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS');
63+
_recordedData.add([
64+
now.millisecondsSinceEpoch.toString(),
65+
dateFormat.format(now),
66+
x.toStringAsFixed(6),
67+
y.toStringAsFixed(6),
68+
z.toStringAsFixed(6),
69+
0,
70+
0
71+
]);
72+
}
5673

5774
_xData.add(x);
5875
_yData.add(y);
@@ -82,6 +99,28 @@ class AccelerometerStateProvider extends ChangeNotifier {
8299
notifyListeners();
83100
}
84101

102+
void startRecording() {
103+
_isRecording = true;
104+
_recordedData = [
105+
[
106+
'Timestamp',
107+
'DateTime',
108+
'ReadingsX',
109+
'ReadingsY',
110+
'ReadingsZ',
111+
'Latitude',
112+
'Longitude'
113+
]
114+
];
115+
notifyListeners();
116+
}
117+
118+
List<List<dynamic>> stopRecording() {
119+
_isRecording = false;
120+
notifyListeners();
121+
return _recordedData;
122+
}
123+
85124
List<FlSpot> getAxisData(String axis) {
86125
switch (axis) {
87126
case 'x':

lib/view/accelerometer_screen.dart

Lines changed: 152 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import 'package:pslab/view/widgets/guide_widget.dart';
66
import 'package:pslab/providers/accelerometer_state_provider.dart';
77
import 'package:pslab/view/widgets/common_scaffold_widget.dart';
88
import 'package:pslab/view/widgets/accelerometer_card.dart';
9+
import 'package:pslab/others/csv_service.dart';
10+
import 'package:pslab/view/logged_data_screen.dart';
911

1012
import '../providers/accelerometer_config_provider.dart';
1113
import '../theme/colors.dart';
14+
import '../constants.dart';
1215
import 'accelerometer_config_screen.dart';
1316

1417
class AccelerometerScreen extends StatefulWidget {
@@ -22,6 +25,27 @@ class _AccelerometerScreenState extends State<AccelerometerScreen> {
2225
AppLocalizations appLocalizations = getIt.get<AppLocalizations>();
2326
bool _showGuide = false;
2427
static const imagePath = 'assets/images/bh1750_schematic.png';
28+
final CsvService _csvService = CsvService();
29+
late AccelerometerStateProvider _provider;
30+
31+
@override
32+
void initState() {
33+
super.initState();
34+
_provider = AccelerometerStateProvider();
35+
WidgetsBinding.instance.addPostFrameCallback((_) {
36+
if (mounted) {
37+
_provider.initializeSensors();
38+
}
39+
});
40+
}
41+
42+
@override
43+
void dispose() {
44+
_provider.disposeSensors();
45+
_provider.dispose();
46+
super.dispose();
47+
}
48+
2549
void _showInstrumentGuide() {
2650
setState(() {
2751
_showGuide = true;
@@ -80,7 +104,7 @@ class _AccelerometerScreenState extends State<AccelerometerScreen> {
80104
if (value != null) {
81105
switch (value) {
82106
case 'show_logged_data':
83-
// TODO
107+
_navigateToLoggedData();
84108
break;
85109
case 'accelerometer_config':
86110
_navigateToConfig();
@@ -90,6 +114,19 @@ class _AccelerometerScreenState extends State<AccelerometerScreen> {
90114
});
91115
}
92116

117+
Future<void> _navigateToLoggedData() async {
118+
await Navigator.push(
119+
context,
120+
MaterialPageRoute(
121+
builder: (context) => LoggedDataScreen(
122+
instrumentName: 'accelerometer',
123+
appBarName: appLocalizations.accelerometer,
124+
instrumentIcon: instrumentIcons[7],
125+
),
126+
),
127+
);
128+
}
129+
93130
void _navigateToConfig() {
94131
Navigator.push(
95132
context,
@@ -102,36 +139,124 @@ class _AccelerometerScreenState extends State<AccelerometerScreen> {
102139
);
103140
}
104141

142+
Future<void> _toggleRecording() async {
143+
if (_provider.isRecording) {
144+
final data = _provider.stopRecording();
145+
await _showSaveFileDialog(data);
146+
} else {
147+
_provider.startRecording();
148+
ScaffoldMessenger.of(context).showSnackBar(
149+
SnackBar(
150+
content: Text(
151+
'${appLocalizations.recordingStarted}...',
152+
style: TextStyle(color: snackBarContentColor),
153+
),
154+
backgroundColor: snackBarBackgroundColor,
155+
),
156+
);
157+
}
158+
}
159+
160+
Future<void> _showSaveFileDialog(List<List<dynamic>> data) async {
161+
final TextEditingController filenameController = TextEditingController();
162+
final String defaultFilename = '';
163+
filenameController.text = defaultFilename;
164+
165+
final String? fileName = await showDialog<String>(
166+
context: context,
167+
builder: (context) {
168+
return AlertDialog(
169+
title: Text(appLocalizations.saveRecording),
170+
content: TextField(
171+
controller: filenameController,
172+
decoration: InputDecoration(
173+
hintText: appLocalizations.enterFileName,
174+
labelText: appLocalizations.fileName,
175+
),
176+
),
177+
actions: [
178+
TextButton(
179+
onPressed: () => Navigator.pop(context),
180+
child: Text(appLocalizations.cancel.toUpperCase()),
181+
),
182+
ElevatedButton(
183+
onPressed: () {
184+
Navigator.pop(context, filenameController.text);
185+
},
186+
child: Text(appLocalizations.save),
187+
),
188+
],
189+
);
190+
},
191+
);
192+
193+
if (fileName != null) {
194+
_csvService.writeMetaData('accelerometer', data);
195+
final file =
196+
await _csvService.saveCsvFile('accelerometer', fileName, data);
197+
if (mounted) {
198+
if (file != null) {
199+
ScaffoldMessenger.of(context).showSnackBar(
200+
SnackBar(
201+
content: Text(
202+
'${appLocalizations.fileSaved}: ${file.path.split('/').last}',
203+
style: TextStyle(color: snackBarContentColor),
204+
),
205+
backgroundColor: snackBarBackgroundColor,
206+
),
207+
);
208+
} else {
209+
ScaffoldMessenger.of(context).showSnackBar(
210+
SnackBar(
211+
content: Text(
212+
appLocalizations.failedToSave,
213+
style: TextStyle(color: snackBarContentColor),
214+
),
215+
backgroundColor: snackBarBackgroundColor,
216+
),
217+
);
218+
}
219+
}
220+
}
221+
}
222+
105223
@override
106224
Widget build(BuildContext context) {
107-
return MultiProvider(
108-
providers: [
109-
ChangeNotifierProvider<AccelerometerStateProvider>(
110-
create: (_) => AccelerometerStateProvider()..initializeSensors(),
111-
),
112-
],
225+
return ChangeNotifierProvider<AccelerometerStateProvider>.value(
226+
value: _provider,
113227
child: Stack(children: [
114-
CommonScaffold(
115-
title: appLocalizations.accelerometerTitle,
116-
onGuidePressed: _showInstrumentGuide,
117-
onOptionsPressed: _showOptionsMenu,
118-
body: SafeArea(
228+
Consumer<AccelerometerStateProvider>(
229+
builder: (context, provider, child) {
230+
return CommonScaffold(
231+
title: appLocalizations.accelerometerTitle,
232+
onGuidePressed: _showInstrumentGuide,
233+
onOptionsPressed: _showOptionsMenu,
234+
onRecordPressed: _toggleRecording,
235+
isRecording: provider.isRecording,
236+
body: SafeArea(
119237
child: Column(
120-
children: [
121-
Expanded(
122-
child: AccelerometerCard(
123-
color: xOrientationChartLineColor,
124-
axis: appLocalizations.xAxis)),
125-
Expanded(
126-
child: AccelerometerCard(
127-
color: yOrientationChartLineColor,
128-
axis: appLocalizations.yAxis)),
129-
Expanded(
130-
child: AccelerometerCard(
131-
color: zOrientationChartLineColor,
132-
axis: appLocalizations.zAxis)),
133-
],
134-
))),
238+
children: [
239+
Expanded(
240+
child: AccelerometerCard(
241+
color: xOrientationChartLineColor,
242+
axis: appLocalizations.xAxis),
243+
),
244+
Expanded(
245+
child: AccelerometerCard(
246+
color: yOrientationChartLineColor,
247+
axis: appLocalizations.yAxis),
248+
),
249+
Expanded(
250+
child: AccelerometerCard(
251+
color: zOrientationChartLineColor,
252+
axis: appLocalizations.zAxis),
253+
),
254+
],
255+
),
256+
),
257+
);
258+
},
259+
),
135260
if (_showGuide)
136261
InstrumentOverviewDrawer(
137262
instrumentName: appLocalizations.accelerometer,

0 commit comments

Comments
 (0)