Skip to content

Commit 023870b

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

File tree

5 files changed

+297
-48
lines changed

5 files changed

+297
-48
lines changed

lib/providers/gyroscope_state_provider.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:fl_chart/fl_chart.dart';
44
import 'package:flutter/foundation.dart';
55
import 'package:sensors_plus/sensors_plus.dart';
66
import 'package:pslab/others/logger_service.dart';
7+
import 'package:intl/intl.dart';
78

89
class GyroscopeProvider extends ChangeNotifier {
910
StreamSubscription<GyroscopeEvent>? _gyroscopeSubscription;
@@ -22,6 +23,9 @@ class GyroscopeProvider extends ChangeNotifier {
2223
double _yMin = 0, _yMax = 0;
2324
double _zMin = 0, _zMax = 0;
2425

26+
bool _isRecording = false;
27+
List<List<dynamic>> _recordedData = [];
28+
2529
double get xValue => _gyroscopeEvent.x;
2630
double get yValue => _gyroscopeEvent.y;
2731
double get zValue => _gyroscopeEvent.z;
@@ -34,6 +38,7 @@ class GyroscopeProvider extends ChangeNotifier {
3438
double get zMax => _zMax;
3539

3640
bool get isListening => _gyroscopeSubscription != null;
41+
bool get isRecording => _isRecording;
3742

3843
void initializeSensors() {
3944
if (_gyroscopeSubscription != null) return;
@@ -61,6 +66,20 @@ class GyroscopeProvider extends ChangeNotifier {
6166
final y = _gyroscopeEvent.y;
6267
final z = _gyroscopeEvent.z;
6368

69+
if (_isRecording) {
70+
final now = DateTime.now();
71+
final dateFormat = DateFormat('yyyy-MM-dd HH:mm:ss.SSS');
72+
_recordedData.add([
73+
now.millisecondsSinceEpoch.toString(),
74+
dateFormat.format(now),
75+
x.toStringAsFixed(6),
76+
y.toStringAsFixed(6),
77+
z.toStringAsFixed(6),
78+
0,
79+
0
80+
]);
81+
}
82+
6483
_xData.add(x);
6584
_yData.add(y);
6685
_zData.add(z);
@@ -88,6 +107,28 @@ class GyroscopeProvider extends ChangeNotifier {
88107
notifyListeners();
89108
}
90109

110+
void startRecording() {
111+
_isRecording = true;
112+
_recordedData = [
113+
[
114+
'Timestamp',
115+
'DateTime',
116+
'ReadingsX',
117+
'ReadingsY',
118+
'ReadingsZ',
119+
'Latitude',
120+
'Longitude'
121+
]
122+
];
123+
notifyListeners();
124+
}
125+
126+
List<List<dynamic>> stopRecording() {
127+
_isRecording = false;
128+
notifyListeners();
129+
return _recordedData;
130+
}
131+
91132
List<FlSpot> getAxisData(String axis) {
92133
switch (axis) {
93134
case 'x':

lib/view/compass_screen.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,17 @@ class _CompassScreenContentState extends State<CompassScreenContent> {
180180
mainAxisAlignment: MainAxisAlignment.center,
181181
mainAxisSize: MainAxisSize.min,
182182
children: [
183-
Radio<String>(
184-
value: axis,
183+
RadioGroup(
185184
groupValue: compassProvider.selectedAxis,
186185
onChanged: (String? value) {
187186
if (value != null) {
188187
compassProvider.onAxisSelected(value);
189188
}
190189
},
191-
activeColor: radioButtonActiveColor,
190+
child: Radio<String>(
191+
value: axis,
192+
activeColor: radioButtonActiveColor,
193+
),
192194
),
193195
Text(
194196
label,

lib/view/gyroscope_screen.dart

Lines changed: 150 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import 'package:pslab/view/widgets/gyroscope_card.dart';
77
import 'package:pslab/view/widgets/common_scaffold_widget.dart';
88
import 'package:pslab/l10n/app_localizations.dart';
99
import 'package:pslab/providers/locator.dart';
10+
import 'package:pslab/others/csv_service.dart';
11+
import 'package:pslab/view/logged_data_screen.dart';
1012
import '../theme/colors.dart';
13+
import '../constants.dart';
1114
import 'gyroscope_config_screen.dart';
1215

1316
class GyroscopeScreen extends StatefulWidget {
@@ -21,6 +24,27 @@ class _GyroscopeScreenState extends State<GyroscopeScreen> {
2124
AppLocalizations appLocalizations = getIt.get<AppLocalizations>();
2225
bool _showGuide = false;
2326
static const imagePath = 'assets/images/gyroscope_axes_orientation.png';
27+
final CsvService _csvService = CsvService();
28+
late GyroscopeProvider _provider;
29+
30+
@override
31+
void initState() {
32+
super.initState();
33+
_provider = GyroscopeProvider();
34+
WidgetsBinding.instance.addPostFrameCallback((_) {
35+
if (mounted) {
36+
_provider.initializeSensors();
37+
}
38+
});
39+
}
40+
41+
@override
42+
void dispose() {
43+
_provider.disposeSensors();
44+
_provider.dispose();
45+
super.dispose();
46+
}
47+
2448
void _showInstrumentGuide() {
2549
setState(() {
2650
_showGuide = true;
@@ -72,7 +96,7 @@ class _GyroscopeScreenState extends State<GyroscopeScreen> {
7296
if (value != null) {
7397
switch (value) {
7498
case 'show_logged_data':
75-
// TODO
99+
_navigateToLoggedData();
76100
break;
77101
case 'gyroscope_config':
78102
_navigateToConfig();
@@ -82,6 +106,19 @@ class _GyroscopeScreenState extends State<GyroscopeScreen> {
82106
});
83107
}
84108

109+
Future<void> _navigateToLoggedData() async {
110+
await Navigator.push(
111+
context,
112+
MaterialPageRoute(
113+
builder: (context) => LoggedDataScreen(
114+
instrumentName: 'gyroscope',
115+
appBarName: 'Gyroscope',
116+
instrumentIcon: instrumentIcons[10],
117+
),
118+
),
119+
);
120+
}
121+
85122
void _navigateToConfig() {
86123
Navigator.push(
87124
context,
@@ -93,40 +130,122 @@ class _GyroscopeScreenState extends State<GyroscopeScreen> {
93130
));
94131
}
95132

133+
Future<void> _toggleRecording() async {
134+
if (_provider.isRecording) {
135+
final data = _provider.stopRecording();
136+
await _showSaveFileDialog(data);
137+
} else {
138+
_provider.startRecording();
139+
ScaffoldMessenger.of(context).showSnackBar(
140+
SnackBar(
141+
content: Text(
142+
'${appLocalizations.recordingStarted}...',
143+
style: TextStyle(color: snackBarContentColor),
144+
),
145+
backgroundColor: snackBarBackgroundColor,
146+
),
147+
);
148+
}
149+
}
150+
151+
Future<void> _showSaveFileDialog(List<List<dynamic>> data) async {
152+
final TextEditingController filenameController = TextEditingController();
153+
final String defaultFilename = '';
154+
filenameController.text = defaultFilename;
155+
156+
final String? fileName = await showDialog<String>(
157+
context: context,
158+
builder: (context) {
159+
return AlertDialog(
160+
title: Text(appLocalizations.saveRecording),
161+
content: TextField(
162+
controller: filenameController,
163+
decoration: InputDecoration(
164+
hintText: appLocalizations.enterFileName,
165+
labelText: appLocalizations.fileName,
166+
),
167+
),
168+
actions: [
169+
TextButton(
170+
onPressed: () => Navigator.pop(context),
171+
child: Text(appLocalizations.cancel.toUpperCase()),
172+
),
173+
ElevatedButton(
174+
onPressed: () {
175+
Navigator.pop(context, filenameController.text);
176+
},
177+
child: Text(appLocalizations.save),
178+
),
179+
],
180+
);
181+
},
182+
);
183+
184+
if (fileName != null) {
185+
_csvService.writeMetaData('gyroscope', data);
186+
final file = await _csvService.saveCsvFile('gyroscope', fileName, data);
187+
if (mounted) {
188+
if (file != null) {
189+
ScaffoldMessenger.of(context).showSnackBar(
190+
SnackBar(
191+
content: Text(
192+
'${appLocalizations.fileSaved}: ${file.path.split('/').last}',
193+
style: TextStyle(color: snackBarContentColor),
194+
),
195+
backgroundColor: snackBarBackgroundColor,
196+
),
197+
);
198+
} else {
199+
ScaffoldMessenger.of(context).showSnackBar(
200+
SnackBar(
201+
content: Text(
202+
appLocalizations.failedToSave,
203+
style: TextStyle(color: snackBarContentColor),
204+
),
205+
backgroundColor: snackBarBackgroundColor,
206+
),
207+
);
208+
}
209+
}
210+
}
211+
}
212+
96213
@override
97214
Widget build(BuildContext context) {
98-
return MultiProvider(
99-
providers: [
100-
ChangeNotifierProvider<GyroscopeProvider>(
101-
create: (_) => GyroscopeProvider()..initializeSensors(),
102-
),
103-
],
215+
return ChangeNotifierProvider<GyroscopeProvider>.value(
216+
value: _provider,
104217
child: Stack(children: [
105-
CommonScaffold(
106-
title: appLocalizations.gyroscopeTitle,
107-
onGuidePressed: _showInstrumentGuide,
108-
onOptionsPressed: _showOptionsMenu,
109-
body: SafeArea(
110-
child: Column(
111-
children: [
112-
Expanded(
113-
child: GyroscopeCard(
114-
color: xOrientationChartLineColor,
115-
axis: appLocalizations.xAxis),
218+
Consumer<GyroscopeProvider>(
219+
builder: (context, provider, child) {
220+
return CommonScaffold(
221+
title: appLocalizations.gyroscopeTitle,
222+
onGuidePressed: _showInstrumentGuide,
223+
onOptionsPressed: _showOptionsMenu,
224+
onRecordPressed: _toggleRecording,
225+
isRecording: provider.isRecording,
226+
body: SafeArea(
227+
child: Column(
228+
children: [
229+
Expanded(
230+
child: GyroscopeCard(
231+
color: xOrientationChartLineColor,
232+
axis: appLocalizations.xAxis),
233+
),
234+
Expanded(
235+
child: GyroscopeCard(
236+
color: yOrientationChartLineColor,
237+
axis: appLocalizations.yAxis),
238+
),
239+
Expanded(
240+
child: GyroscopeCard(
241+
color: zOrientationChartLineColor,
242+
axis: appLocalizations.zAxis),
243+
),
244+
],
116245
),
117-
Expanded(
118-
child: GyroscopeCard(
119-
color: yOrientationChartLineColor,
120-
axis: appLocalizations.yAxis),
121-
),
122-
Expanded(
123-
child: GyroscopeCard(
124-
color: zOrientationChartLineColor,
125-
axis: appLocalizations.zAxis),
126-
),
127-
],
128-
),
129-
),
246+
),
247+
);
248+
},
130249
),
131250
if (_showGuide)
132251
InstrumentOverviewDrawer(

0 commit comments

Comments
 (0)