Skip to content

Commit 35c9476

Browse files
# This is a combination of 7 commits.
# This is the 1st commit message: Implemented LUX meter # This is the commit message #2: added const # This is the commit message fossasia#3: Improved responsiveness and made reusable widgets # This is the commit message fossasia#4: renamed file # This is the commit message fossasia#5: Updated view as per PSLab # This is the commit message fossasia#6: Implemented sound meter # This is the commit message fossasia#7: feat: implemented LUX meter (fossasia#2733) fix: handled theming for instrument screens (fossasia#2732) chore(deps): bump org.jetbrains.kotlin.android in /android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 1.8.22 to 2.1.21. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](JetBrains/kotlin@v1.8.22...v2.1.21) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-version: 2.1.21 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Adjusted view Changes
1 parent b126c1f commit 35c9476

20 files changed

Lines changed: 1227 additions & 74 deletions

android/settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pluginManagement {
1919
plugins {
2020
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
2121
id "com.android.application" version "8.3.1" apply false
22-
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
22+
id "org.jetbrains.kotlin.android" version "2.1.21" apply false
2323
}
2424

2525
include ":app"

lib/constants.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,29 @@ String maxValue = 'Max: ';
144144
String gyroscopeTitle = "Gyroscope";
145145
String gyroscopeAxisLabel = 'rad/s';
146146
String noData = 'No data available';
147+
String xyPlot = 'XY Plot';
148+
String enablePlot = 'Enable XY Plot';
149+
String trigger = 'Trigger';
150+
String timeBase = 'Timebase';
151+
String timeBaseAndTrigger = 'Timebase & Trigger';
152+
String offsets = 'Offsets';
153+
String dataAnalysis = 'Data Analysis';
154+
String fourierAnalysis = 'Fourier Analysis';
155+
String channels = 'Channels';
156+
String pslabMic = 'PSLab MIC';
157+
String inBuiltMic = 'In-Built MIC';
158+
String ch3Range = 'CH3 (+/- 3.3V)';
159+
String rangeValue = '+/-16V';
160+
String range = 'Range';
161+
String ch2 = 'CH2';
162+
String ch1 = 'CH1';
163+
String luxMeterTitle = 'Lux Meter';
164+
String builtIn = 'Built-In';
165+
String lx = 'Lx';
166+
String maxScaleError = 'Max Scale';
167+
String lightSensorError = 'Light sensor error:';
168+
String lightSensorInitialError = 'Failed to initialize light sensor:';
169+
String soundMeterError = 'Sound sensor error:';
170+
String soundMeterInitialError = 'Sound sensor initialization error:';
171+
String db = 'dB';
172+
String soundMeterTitle = 'Sound Meter';

lib/main.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import 'package:pslab/view/connect_device_screen.dart';
77
import 'package:pslab/view/faq_screen.dart';
88
import 'package:pslab/view/gyroscope_screen.dart';
99
import 'package:pslab/view/instruments_screen.dart';
10+
import 'package:pslab/view/luxmeter_screen.dart';
1011
import 'package:pslab/view/oscilloscope_screen.dart';
1112
import 'package:pslab/view/settings_screen.dart';
1213
import 'package:pslab/view/about_us_screen.dart';
1314
import 'package:pslab/view/software_licenses_screen.dart';
1415
import 'package:pslab/others/theme.dart';
16+
import 'package:pslab/view/soundmeter_screen.dart';
1517
import 'constants.dart';
1618

1719
void main() {
@@ -52,6 +54,8 @@ class MyApp extends StatelessWidget {
5254
'/softwareLicenses': (context) => const SoftwareLicensesScreen(),
5355
'/accelerometer': (context) => const AccelerometerScreen(),
5456
'/gyroscope': (context) => const GyroscopeScreen(),
57+
'/luxmeter': (context) => const LuxMeterScreen(),
58+
'/soundmeter': (context) => const SoundMeterScreen(),
5559
},
5660
);
5761
}

lib/others/theme.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,34 @@ class AppTheme {
66
useMaterial3: true,
77
scaffoldBackgroundColor: Colors.white,
88
colorSchemeSeed: Colors.white,
9+
checkboxTheme: const CheckboxThemeData(
10+
side: BorderSide(color: Colors.black, width: 2),
11+
),
12+
radioTheme: RadioThemeData(
13+
fillColor: WidgetStateProperty.resolveWith<Color>((states) {
14+
if (states.contains(WidgetState.selected)) {
15+
return const Color(0xFFCE525F);
16+
}
17+
return Colors.black;
18+
}),
19+
),
920
);
21+
1022
static final darkTheme = ThemeData(
1123
brightness: Brightness.dark,
1224
useMaterial3: true,
1325
scaffoldBackgroundColor: Colors.black,
1426
colorSchemeSeed: Colors.black,
27+
checkboxTheme: const CheckboxThemeData(
28+
side: BorderSide(color: Colors.black, width: 2),
29+
),
30+
radioTheme: RadioThemeData(
31+
fillColor: WidgetStateProperty.resolveWith<Color>((states) {
32+
if (states.contains(WidgetState.selected)) {
33+
return const Color(0xFFCE525F);
34+
}
35+
return Colors.black;
36+
}),
37+
),
1538
);
1639
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import 'dart:async';
2+
import 'dart:math';
3+
import 'package:fl_chart/fl_chart.dart';
4+
import 'package:flutter/material.dart';
5+
import 'package:pslab/others/logger_service.dart';
6+
import 'package:light/light.dart';
7+
import 'package:flutter/foundation.dart';
8+
import 'package:pslab/constants.dart';
9+
10+
class LuxMeterStateProvider extends ChangeNotifier {
11+
double _currentLux = 0.0;
12+
StreamSubscription? _lightSubscription;
13+
Timer? _timeTimer;
14+
final List<double> _luxData = [];
15+
final List<double> _timeData = [];
16+
final List<FlSpot> luxChartData = [];
17+
Light? _light;
18+
double _startTime = 0;
19+
double _currentTime = 0;
20+
final int _maxLength = 50;
21+
double _luxMin = 0;
22+
double _luxMax = 0;
23+
double _luxSum = 0;
24+
int _dataCount = 0;
25+
void initializeSensors() {
26+
try {
27+
_light = Light();
28+
_startTime = DateTime.now().millisecondsSinceEpoch / 1000.0;
29+
_timeTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
30+
_currentTime =
31+
(DateTime.now().millisecondsSinceEpoch / 1000.0) - _startTime;
32+
_updateData();
33+
notifyListeners();
34+
});
35+
_lightSubscription = _light!.lightSensorStream.listen(
36+
(int luxValue) {
37+
_currentLux = luxValue.toDouble();
38+
notifyListeners();
39+
},
40+
onError: (error) {
41+
logger.e(
42+
"$lightSensorError $error",
43+
);
44+
},
45+
cancelOnError: true,
46+
);
47+
} catch (e) {
48+
logger.e("$lightSensorInitialError $e");
49+
}
50+
}
51+
52+
void disposeSensors() {
53+
_lightSubscription?.cancel();
54+
_timeTimer?.cancel();
55+
}
56+
57+
@override
58+
void dispose() {
59+
disposeSensors();
60+
super.dispose();
61+
}
62+
63+
void _updateData() {
64+
final lux = _currentLux;
65+
final time = _currentTime;
66+
_luxData.add(lux);
67+
_timeData.add(time);
68+
_luxSum += lux;
69+
_dataCount++;
70+
if (_luxData.length > _maxLength) {
71+
final removedValue = _luxData.removeAt(0);
72+
_timeData.removeAt(0);
73+
_luxSum -= removedValue;
74+
_dataCount--;
75+
}
76+
if (_luxData.isNotEmpty) {
77+
_luxMin = _luxData.reduce(min);
78+
_luxMax = _luxData.reduce(max);
79+
}
80+
luxChartData.clear();
81+
for (int i = 0; i < _luxData.length; i++) {
82+
luxChartData.add(FlSpot(_timeData[i], _luxData[i]));
83+
}
84+
notifyListeners();
85+
}
86+
87+
double getCurrentLux() => _currentLux;
88+
double getMinLux() => _luxMin;
89+
double getMaxLux() => _luxMax;
90+
double getAverageLux() => _dataCount > 0 ? _luxSum / _dataCount : 0.0;
91+
List<FlSpot> getLuxChartData() => luxChartData;
92+
int getDataLength() => luxChartData.length;
93+
double getCurrentTime() => _currentTime;
94+
double getMaxTime() => _timeData.isNotEmpty ? _timeData.last : 0;
95+
double getMinTime() => _timeData.isNotEmpty ? _timeData.first : 0;
96+
double getTimeInterval() {
97+
if (_currentTime <= 10) return 2;
98+
if (_currentTime <= 30) return 5;
99+
return 10;
100+
}
101+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import 'dart:async';
2+
import 'dart:math';
3+
import 'package:fl_chart/fl_chart.dart';
4+
import 'package:flutter/material.dart';
5+
import 'package:pslab/others/logger_service.dart';
6+
import 'package:noise_meter/noise_meter.dart';
7+
import 'package:flutter/foundation.dart';
8+
import 'package:pslab/constants.dart';
9+
10+
class SoundMeterStateProvider extends ChangeNotifier {
11+
double _currentDb = 0.0;
12+
StreamSubscription<NoiseReading>? _noiseSubscription;
13+
Timer? _timeTimer;
14+
final List<double> _dbData = [];
15+
final List<double> _timeData = [];
16+
final List<FlSpot> dbChartData = [];
17+
NoiseMeter? _noiseMeter;
18+
double _startTime = 0;
19+
double _currentTime = 0;
20+
final int _maxLength = 50;
21+
double _dbMin = 0;
22+
double _dbMax = 0;
23+
double _dbSum = 0;
24+
int _dataCount = 0;
25+
26+
void initializeSensors() {
27+
try {
28+
_noiseMeter = NoiseMeter();
29+
_startTime = DateTime.now().millisecondsSinceEpoch / 1000.0;
30+
_timeTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
31+
_currentTime =
32+
(DateTime.now().millisecondsSinceEpoch / 1000.0) - _startTime;
33+
_updateData();
34+
notifyListeners();
35+
});
36+
_noiseSubscription = _noiseMeter!.noise.listen(
37+
(NoiseReading noiseReading) {
38+
_currentDb = noiseReading.meanDecibel;
39+
notifyListeners();
40+
},
41+
onError: (error) {
42+
logger.e(
43+
"$soundMeterError $error",
44+
);
45+
},
46+
cancelOnError: true,
47+
);
48+
} catch (e) {
49+
logger.e("$soundMeterInitialError $e");
50+
}
51+
}
52+
53+
void disposeSensors() {
54+
_noiseSubscription?.cancel();
55+
_timeTimer?.cancel();
56+
}
57+
58+
@override
59+
void dispose() {
60+
disposeSensors();
61+
super.dispose();
62+
}
63+
64+
void _updateData() {
65+
final db = _currentDb;
66+
final time = _currentTime;
67+
_dbData.add(db);
68+
_timeData.add(time);
69+
_dbSum += db;
70+
_dataCount++;
71+
if (_dbData.length > _maxLength) {
72+
final removedValue = _dbData.removeAt(0);
73+
_timeData.removeAt(0);
74+
_dbSum -= removedValue;
75+
_dataCount--;
76+
}
77+
if (_dbData.isNotEmpty) {
78+
_dbMin = _dbData.reduce(min);
79+
_dbMax = _dbData.reduce(max);
80+
}
81+
dbChartData.clear();
82+
for (int i = 0; i < _dbData.length; i++) {
83+
dbChartData.add(FlSpot(_timeData[i], _dbData[i]));
84+
}
85+
notifyListeners();
86+
}
87+
88+
double getCurrentDb() => _currentDb;
89+
double getMinDb() => _dbMin;
90+
double getMaxDb() => _dbMax;
91+
double getAverageDb() => _dataCount > 0 ? _dbSum / _dataCount : 0.0;
92+
List<FlSpot> getDbChartData() => dbChartData;
93+
int getDataLength() => dbChartData.length;
94+
double getCurrentTime() => _currentTime;
95+
double getMaxTime() => _timeData.isNotEmpty ? _timeData.last : 0;
96+
double getMinTime() => _timeData.isNotEmpty ? _timeData.first : 0;
97+
double getTimeInterval() {
98+
if (_currentTime <= 10) return 2;
99+
if (_currentTime <= 30) return 5;
100+
return 10;
101+
}
102+
}

lib/view/instruments_screen.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'package:pslab/view/widgets/main_scaffold_widget.dart';
77

88
class InstrumentsScreen extends StatefulWidget {
99
const InstrumentsScreen({super.key});
10-
1110
@override
1211
State<StatefulWidget> createState() => _InstrumentsScreenState();
1312
}
@@ -38,6 +37,18 @@ class _InstrumentsScreenState extends State<InstrumentsScreen> {
3837
);
3938
}
4039
break;
40+
case 6:
41+
if (Navigator.canPop(context) &&
42+
ModalRoute.of(context)?.settings.name == '/luxmeter') {
43+
Navigator.popUntil(context, ModalRoute.withName('/luxmeter'));
44+
} else {
45+
Navigator.pushNamedAndRemoveUntil(
46+
context,
47+
'/luxmeter',
48+
(route) => route.isFirst,
49+
);
50+
}
51+
break;
4152
case 10:
4253
if (Navigator.canPop(context) &&
4354
ModalRoute.of(context)?.settings.name == '/gyroscope') {
@@ -50,6 +61,18 @@ class _InstrumentsScreenState extends State<InstrumentsScreen> {
5061
);
5162
}
5263
break;
64+
case 15:
65+
if (Navigator.canPop(context) &&
66+
ModalRoute.of(context)?.settings.name == '/soundmeter') {
67+
Navigator.popUntil(context, ModalRoute.withName('/soundmeter'));
68+
} else {
69+
Navigator.pushNamedAndRemoveUntil(
70+
context,
71+
'/soundmeter',
72+
(route) => route.isFirst,
73+
);
74+
}
75+
break;
5376
default:
5477
break;
5578
}

0 commit comments

Comments
 (0)