Skip to content

Commit bcb5817

Browse files
feat: added configuration screen for luxmeter and stored settings (#2769)
1 parent 92134e4 commit bcb5817

10 files changed

+657
-13
lines changed

lib/constants.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ String degreeSymbol = '°';
232232
String enterAngleRange = 'Enter angle (0 - 360)';
233233
String errorCannotBeEmpty = 'Cannot be empty';
234234
String servoValidNumberRange = 'Please enter a valid number between 0 and 360';
235-
String ok = 'Ok';
235+
String ok = 'OK';
236236
String roboticArm = 'Robotic Arm';
237237
String play = 'Play';
238238
String pause = 'Pause';
@@ -368,6 +368,24 @@ String shareAppMenu = 'Share App';
368368
String privacyPolicyMenu = 'Privacy Policy';
369369
String shopLink = 'https://pslab.io/shop/';
370370
String shopError = 'Could not open the shop link';
371+
String showLuxmeterConfig = 'Lux Meter Configurations';
372+
String luxmeterConfigurations = 'Lux Meter Configurations';
373+
String updatePeriod = 'Update Period';
374+
String updatePeriodHint =
375+
'Please provide time interval at which data will be updated (100 ms to 1000 ms)';
376+
String highLimit = 'High Limit';
377+
String highLimitHint =
378+
'Please provide the maximum limit of lux value to be recorded (10 Lx to 10000 Lx)';
379+
String sensorGain = 'Sensor Gain';
380+
String sensorGainHint = 'Please set gain of the sensor';
381+
String locationData = 'Include Location Data';
382+
String locationDataHint = 'Include the location data in the logged file';
383+
String activeSensor = 'Active Sensor';
384+
String ms = 'ms';
385+
String inBuiltSensor = 'In-built Sensor';
386+
String updatePeriodErrorMessage =
387+
'Entered update period is not within the limits!';
388+
String highLimitErrorMessage = 'Entered High limit is not within the limits!';
371389
String baroMeterBulletPoint1 =
372390
'The Barometer can be used to measure Atmospheric pressure. This instrument is compatible with either the built in pressure sensor on any android device or the BMP-180 pressure sensor';
373391
String baroMeterBulletPoint2 =

lib/models/luxmeter_config.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
class LuxMeterConfig {
2+
final int updatePeriod;
3+
final int highLimit;
4+
final String activeSensor;
5+
final int sensorGain;
6+
final bool includeLocationData;
7+
8+
const LuxMeterConfig({
9+
this.updatePeriod = 1000,
10+
this.highLimit = 2000,
11+
this.activeSensor = 'In-built Sensor',
12+
this.sensorGain = 1,
13+
this.includeLocationData = true,
14+
});
15+
16+
LuxMeterConfig copyWith({
17+
int? updatePeriod,
18+
int? highLimit,
19+
String? activeSensor,
20+
int? sensorGain,
21+
bool? includeLocationData,
22+
}) {
23+
return LuxMeterConfig(
24+
updatePeriod: updatePeriod ?? this.updatePeriod,
25+
highLimit: highLimit ?? this.highLimit,
26+
activeSensor: activeSensor ?? this.activeSensor,
27+
sensorGain: sensorGain ?? this.sensorGain,
28+
includeLocationData: includeLocationData ?? this.includeLocationData,
29+
);
30+
}
31+
32+
Map<String, dynamic> toJson() {
33+
return {
34+
'updatePeriod': updatePeriod,
35+
'highLimit': highLimit,
36+
'activeSensor': activeSensor,
37+
'sensorGain': sensorGain,
38+
'includeLocationData': includeLocationData,
39+
};
40+
}
41+
42+
factory LuxMeterConfig.fromJson(Map<String, dynamic> json) {
43+
return LuxMeterConfig(
44+
updatePeriod: json['updatePeriod'] ?? 1000,
45+
highLimit: json['highLimit'] ?? 2000,
46+
activeSensor: json['activeSensor'] ?? 'In-built Sensor',
47+
sensorGain: json['sensorGain'] ?? 1,
48+
includeLocationData: json['includeLocationData'] ?? true,
49+
);
50+
}
51+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'dart:convert';
3+
import 'package:shared_preferences/shared_preferences.dart';
4+
import 'package:pslab/models/luxmeter_config.dart';
5+
6+
class LuxMeterConfigProvider extends ChangeNotifier {
7+
LuxMeterConfig _config = const LuxMeterConfig();
8+
9+
LuxMeterConfig get config => _config;
10+
11+
LuxMeterConfigProvider() {
12+
_loadConfigFromPrefs();
13+
}
14+
15+
Future<void> _loadConfigFromPrefs() async {
16+
final prefs = await SharedPreferences.getInstance();
17+
final jsonString = prefs.getString('lux_config');
18+
if (jsonString != null) {
19+
final Map<String, dynamic> jsonMap = json.decode(jsonString);
20+
_config = LuxMeterConfig.fromJson(jsonMap);
21+
notifyListeners();
22+
}
23+
}
24+
25+
Future<void> _saveConfigToPrefs() async {
26+
final prefs = await SharedPreferences.getInstance();
27+
await prefs.setString('lux_config', json.encode(_config.toJson()));
28+
}
29+
30+
void updateConfig(LuxMeterConfig newConfig) {
31+
_config = newConfig;
32+
notifyListeners();
33+
_saveConfigToPrefs();
34+
}
35+
36+
void updateUpdatePeriod(int updatePeriod) {
37+
_config = _config.copyWith(updatePeriod: updatePeriod);
38+
notifyListeners();
39+
_saveConfigToPrefs();
40+
}
41+
42+
void updateHighLimit(int highLimit) {
43+
_config = _config.copyWith(highLimit: highLimit);
44+
notifyListeners();
45+
_saveConfigToPrefs();
46+
}
47+
48+
void updateActiveSensor(String activeSensor) {
49+
_config = _config.copyWith(activeSensor: activeSensor);
50+
notifyListeners();
51+
_saveConfigToPrefs();
52+
}
53+
54+
void updateSensorGain(int sensorGain) {
55+
_config = _config.copyWith(sensorGain: sensorGain);
56+
notifyListeners();
57+
_saveConfigToPrefs();
58+
}
59+
60+
void updateIncludeLocationData(bool includeLocationData) {
61+
_config = _config.copyWith(includeLocationData: includeLocationData);
62+
notifyListeners();
63+
_saveConfigToPrefs();
64+
}
65+
66+
void resetToDefaults() {
67+
_config = const LuxMeterConfig();
68+
notifyListeners();
69+
_saveConfigToPrefs();
70+
}
71+
}

lib/providers/luxmeter_state_provider.dart

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

910
class LuxMeterStateProvider extends ChangeNotifier {
1011
double _currentLux = 0.0;
@@ -23,8 +24,23 @@ class LuxMeterStateProvider extends ChangeNotifier {
2324
int _dataCount = 0;
2425
bool _sensorAvailable = false;
2526

27+
LuxMeterConfigProvider? _configProvider;
28+
2629
Function(String)? onSensorError;
2730

31+
void setConfigProvider(LuxMeterConfigProvider configProvider) {
32+
_configProvider = configProvider;
33+
_configProvider?.addListener(_onConfigChanged);
34+
}
35+
36+
void _onConfigChanged() {
37+
if (_configProvider != null) {
38+
// TODO
39+
}
40+
}
41+
42+
LuxMeterConfigProvider? get configProvider => _configProvider;
43+
2844
void initializeSensors({Function(String)? onError}) {
2945
onSensorError = onError;
3046

@@ -79,6 +95,7 @@ class LuxMeterStateProvider extends ChangeNotifier {
7995

8096
@override
8197
void dispose() {
98+
_configProvider?.removeListener(_onConfigChanged);
8299
disposeSensors();
83100
super.dispose();
84101
}

lib/theme/colors.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Color snackBarContentColor = Colors.white;
4545
Color guideDrawerBackgroundColor = Colors.white;
4646
Color guideDrawerHeadingColor = Colors.black87;
4747
Color guideDrawerHighlightColor = Colors.black54;
48+
Color hintTextColor = Colors.grey;
4849
List<Color> knobLabelColors = [
4950
Color(0xFFD32F2F), // CH1
5051
Color(0xFFD32F2F), // CAP

lib/view/luxmeter_config_screen.dart

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
3+
import 'package:provider/provider.dart';
4+
import 'package:pslab/constants.dart';
5+
import 'package:pslab/providers/luxmeter_config_provider.dart';
6+
import 'package:pslab/view/widgets/config_widgets.dart';
7+
8+
import '../theme/colors.dart';
9+
10+
class LuxMeterConfigScreen extends StatefulWidget {
11+
const LuxMeterConfigScreen({super.key});
12+
13+
@override
14+
State<LuxMeterConfigScreen> createState() => _LuxMeterConfigScreenState();
15+
}
16+
17+
class _LuxMeterConfigScreenState extends State<LuxMeterConfigScreen> {
18+
final TextEditingController _updatePeriodController = TextEditingController();
19+
final TextEditingController _highLimitController = TextEditingController();
20+
final TextEditingController _sensorGainController = TextEditingController();
21+
22+
@override
23+
void initState() {
24+
super.initState();
25+
WidgetsBinding.instance.addPostFrameCallback((_) {
26+
final provider =
27+
Provider.of<LuxMeterConfigProvider>(context, listen: false);
28+
_updatePeriodController.text = provider.config.updatePeriod.toString();
29+
_highLimitController.text = provider.config.highLimit.toString();
30+
_sensorGainController.text = provider.config.sensorGain.toString();
31+
});
32+
}
33+
34+
@override
35+
void dispose() {
36+
_updatePeriodController.dispose();
37+
_highLimitController.dispose();
38+
_sensorGainController.dispose();
39+
super.dispose();
40+
}
41+
42+
@override
43+
Widget build(BuildContext context) {
44+
return Scaffold(
45+
backgroundColor: Theme.of(context).colorScheme.surface,
46+
resizeToAvoidBottomInset: true,
47+
appBar: AppBar(
48+
systemOverlayStyle: SystemUiOverlayStyle(statusBarColor: appBarColor),
49+
leading: Builder(builder: (context) {
50+
return IconButton(
51+
onPressed: () {
52+
if (Navigator.canPop(context) &&
53+
ModalRoute.of(context)?.settings.name == '/luxmeter') {
54+
Navigator.popUntil(context, ModalRoute.withName('/luxmeter'));
55+
} else {
56+
Navigator.pushNamedAndRemoveUntil(
57+
context,
58+
'/luxmeter',
59+
(route) => route.isFirst,
60+
);
61+
}
62+
},
63+
icon: Icon(
64+
Icons.arrow_back,
65+
color: appBarContentColor,
66+
),
67+
);
68+
}),
69+
backgroundColor: primaryRed,
70+
title: Text(
71+
luxmeterConfigurations,
72+
style: TextStyle(
73+
color: appBarContentColor,
74+
fontSize: 15,
75+
),
76+
),
77+
),
78+
body: SafeArea(
79+
child: Padding(
80+
padding: const EdgeInsets.symmetric(horizontal: 16.0),
81+
child: Consumer<LuxMeterConfigProvider>(
82+
builder: (context, provider, child) {
83+
return SingleChildScrollView(
84+
child: Column(
85+
crossAxisAlignment: CrossAxisAlignment.start,
86+
children: [
87+
ConfigInputItem(
88+
title: updatePeriod,
89+
value: '${provider.config.updatePeriod} $ms',
90+
controller: _updatePeriodController,
91+
onChanged: (value) {
92+
final intValue = int.tryParse(value);
93+
if (intValue != null &&
94+
intValue >= 100 &&
95+
intValue <= 1000) {
96+
provider.updateUpdatePeriod(intValue);
97+
} else {
98+
ScaffoldMessenger.of(context).showSnackBar(
99+
SnackBar(
100+
content: Text(
101+
updatePeriodErrorMessage,
102+
style: TextStyle(color: snackBarContentColor),
103+
),
104+
backgroundColor: snackBarBackgroundColor),
105+
);
106+
}
107+
},
108+
hint: updatePeriodHint,
109+
),
110+
ConfigInputItem(
111+
title: highLimit,
112+
value: '${provider.config.highLimit} $lx',
113+
controller: _highLimitController,
114+
onChanged: (value) {
115+
final intValue = int.tryParse(value);
116+
if (intValue != null &&
117+
intValue >= 10 &&
118+
intValue <= 10000) {
119+
provider.updateHighLimit(intValue);
120+
} else {
121+
ScaffoldMessenger.of(context).showSnackBar(
122+
SnackBar(
123+
content: Text(
124+
highLimitErrorMessage,
125+
style: TextStyle(color: snackBarContentColor),
126+
),
127+
backgroundColor: snackBarBackgroundColor),
128+
);
129+
}
130+
},
131+
hint: highLimitHint,
132+
),
133+
ConfigDropdownItem(
134+
title: activeSensor,
135+
selectedValue: provider.config.activeSensor,
136+
options: [
137+
ConfigOption(
138+
value: 'In-built Sensor',
139+
displayName: inBuiltSensor),
140+
ConfigOption(value: 'BH1750', displayName: 'BH1750'),
141+
ConfigOption(value: 'TSL2561', displayName: 'TSL2561'),
142+
],
143+
onChanged: (value) {
144+
provider.updateActiveSensor(value);
145+
},
146+
),
147+
ConfigInputItem(
148+
title: sensorGain,
149+
value: provider.config.sensorGain.toString(),
150+
controller: _sensorGainController,
151+
onChanged: (value) {
152+
final intValue = int.tryParse(value);
153+
if (intValue != null) {
154+
provider.updateSensorGain(intValue);
155+
}
156+
},
157+
hint: sensorGainHint,
158+
),
159+
ConfigCheckboxItem(
160+
title: locationData,
161+
subtitle: locationDataHint,
162+
value: provider.config.includeLocationData,
163+
onChanged: (value) {
164+
provider.updateIncludeLocationData(value);
165+
},
166+
),
167+
],
168+
),
169+
);
170+
},
171+
),
172+
),
173+
),
174+
);
175+
}
176+
}

0 commit comments

Comments
 (0)