diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 9863ccf..c7e1106 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -489,7 +489,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -511,7 +511,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -530,7 +530,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -547,7 +547,7 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -679,7 +679,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -702,7 +702,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
- CURRENT_PROJECT_VERSION = 119;
+ CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 5f212e9..0c6e85f 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -43,7 +43,7 @@
CFBundleSignature
????
CFBundleVersion
- 119
+ 121
LSRequiresIPhoneOS
ITSAppUsesNonExemptEncryption
diff --git a/ios/fastlane/report.xml b/ios/fastlane/report.xml
index 68c15a4..8ec34ed 100644
--- a/ios/fastlane/report.xml
+++ b/ios/fastlane/report.xml
@@ -5,22 +5,22 @@
-
+
-
+
-
+
-
+
diff --git a/lib/widgets/sensors/sensor_telemetry_card.dart b/lib/widgets/sensors/sensor_telemetry_card.dart
index 1de7334..5b57ea5 100644
--- a/lib/widgets/sensors/sensor_telemetry_card.dart
+++ b/lib/widgets/sensors/sensor_telemetry_card.dart
@@ -211,8 +211,10 @@ List sensorMetricOptionsFor(
// Skip them from extraSensorData to avoid duplicates.
final coreFieldKeys = {
if (batteryMilliVolts != null || batteryPercentage != null)
- ...extraSensorData?.keys.where((k) =>
- k.startsWith('voltage_') || k.startsWith('analog_input_')) ?? [],
+ ...extraSensorData?.keys.where(
+ (k) => k.startsWith('voltage_') || k.startsWith('analog_input_'),
+ ) ??
+ [],
if (temperature != null)
...extraSensorData?.keys.where((k) => k.startsWith('temperature_')) ?? [],
if (humidity != null)
@@ -290,14 +292,14 @@ SensorMetricCardData? _buildOptionPreviewCardData(
);
case 'illuminance':
final lux = _previewAsDouble(value);
+ final irradiance = lux == null
+ ? null
+ : _previewFormatDaylightIrradiance(lux);
return SensorMetricCardData(
fieldKey: fieldKey,
icon: Icons.light_mode_outlined,
label: label,
- value: previewValue,
- secondaryValue: lux == null
- ? null
- : '~${_formatPreviewNumber(_previewApproxDaylightIrradiance(lux), maxFractionDigits: 1)} W/m2 daylight',
+ value: irradiance ?? previewValue,
accent: const Color(0xFFC17B1D),
channel: metricKey.channel,
);
@@ -674,6 +676,10 @@ double _previewApproxDaylightIrradiance(double lux) {
return lux / 120.0;
}
+String _previewFormatDaylightIrradiance(double lux) {
+ return '~${_formatPreviewNumber(_previewApproxDaylightIrradiance(lux), maxFractionDigits: 1)} W/m2';
+}
+
String _previewFormatCardinalDirection(double degrees) {
const points = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
final normalized = ((degrees % 360) + 360) % 360;
@@ -699,7 +705,7 @@ String? _sensorMetricPreviewValue(String rawKey, dynamic value) {
case 'illuminance':
final lux = _previewAsDouble(value);
if (lux == null) return null;
- return '${_formatPreviewNumber(lux, maxFractionDigits: 0)} lx';
+ return _previewFormatDaylightIrradiance(lux);
case 'presence':
final isPresent = _previewAsBool(value);
@@ -1439,9 +1445,7 @@ class SensorTelemetryCard extends StatelessWidget {
fieldKey: _extraFieldKey(rawKey),
icon: Icons.light_mode_outlined,
label: label,
- value: '${_formatNumber(lux, maxFractionDigits: 0)} lx',
- secondaryValue:
- '~${_formatNumber(_approxDaylightIrradiance(lux), maxFractionDigits: 1)} W/m2 daylight',
+ value: _formatDaylightIrradiance(lux),
accent: const Color(0xFFC17B1D),
channel: metricKey.channel,
);
@@ -1958,6 +1962,10 @@ class SensorTelemetryCard extends StatelessWidget {
return lux / 120.0;
}
+ String _formatDaylightIrradiance(double lux) {
+ return '~${_formatNumber(_approxDaylightIrradiance(lux), maxFractionDigits: 1)} W/m2';
+ }
+
String _formatCurrent(double amps) {
final absolute = amps.abs();
if (absolute < 1.0) {
diff --git a/pubspec.yaml b/pubspec.yaml
index a42b876..529885a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
-version: 2026.0317.1+33
+version: 2026.0318.1+34
environment:
sdk: ^3.9.2
diff --git a/test/widgets/contact_tile_test.dart b/test/widgets/contact_tile_test.dart
index b4774b3..5118c4e 100644
--- a/test/widgets/contact_tile_test.dart
+++ b/test/widgets/contact_tile_test.dart
@@ -164,18 +164,16 @@ void main() {
expect(find.text('CO2'), findsOneWidget);
expect(find.text('415 ppm'), findsOneWidget);
expect(find.text('Illuminance'), findsOneWidget);
- expect(find.text('~4.2 W/m2 daylight'), findsOneWidget);
+ expect(find.text('~4.2 W/m2'), findsOneWidget);
+ expect(find.textContaining('lx'), findsNothing);
expect(find.text('Current'), findsOneWidget);
expect(find.text('15 mA'), findsOneWidget);
expect(find.text('Power'), findsOneWidget);
expect(find.text('Distance'), findsOneWidget);
- expect(
- find.byKey(const ValueKey('sensor_metric_channel_battery')),
- findsOneWidget,
- );
+ expect(find.byKey(const ValueKey('sensor_metric_battery')), findsOneWidget);
expect(find.text('ch1'), findsWidgets);
expect(
- find.byKey(const ValueKey('sensor_metric_channel_extra:illuminance_2')),
+ find.byKey(const ValueKey('sensor_metric_extra:illuminance_2')),
findsOneWidget,
);
diff --git a/test/widgets/sensor_metric_selector_item_test.dart b/test/widgets/sensor_metric_selector_item_test.dart
index dfb816d..8e2fe77 100644
--- a/test/widgets/sensor_metric_selector_item_test.dart
+++ b/test/widgets/sensor_metric_selector_item_test.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
+import 'package:meshcore_sar_app/l10n/app_localizations.dart';
import 'package:meshcore_sar_app/screens/sensors_tab.dart';
import 'package:meshcore_sar_app/widgets/sensors/sensor_telemetry_card.dart';
@@ -7,6 +8,8 @@ void main() {
testWidgets('renders selector previews and channel badges', (tester) async {
await tester.pumpWidget(
MaterialApp(
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
+ supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
body: SensorMetricSelectorItem(
option: const SensorMetricOption(
@@ -14,12 +17,12 @@ void main() {
label: 'Illuminance (ch 2)',
defaultLabel: 'Illuminance',
channel: 2,
- valuePreview: '500 lx',
+ valuePreview: '~4.2 W/m2',
previewCardData: SensorMetricCardData(
fieldKey: 'extra:illuminance_2',
icon: Icons.light_mode_outlined,
label: 'Illuminance',
- value: '500 lx',
+ value: '~4.2 W/m2',
accent: Color(0xFFC17B1D),
channel: 2,
),
@@ -39,7 +42,8 @@ void main() {
);
expect(find.text('Show on sensor card'), findsOneWidget);
- expect(find.text('500 lx'), findsOneWidget);
+ expect(find.text('~4.2 W/m2'), findsOneWidget);
+ expect(find.textContaining('lx'), findsNothing);
expect(
find.byKey(const ValueKey('sensor_selector_channel_extra:illuminance_2')),
findsOneWidget,
@@ -50,6 +54,8 @@ void main() {
testWidgets('omits duplicate channel chip for channel 1', (tester) async {
await tester.pumpWidget(
MaterialApp(
+ localizationsDelegates: AppLocalizations.localizationsDelegates,
+ supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(
body: SensorMetricSelectorItem(
option: const SensorMetricOption(
diff --git a/test/widgets/sensor_telemetry_card_test.dart b/test/widgets/sensor_telemetry_card_test.dart
index 262ebe0..fb31c3b 100644
--- a/test/widgets/sensor_telemetry_card_test.dart
+++ b/test/widgets/sensor_telemetry_card_test.dart
@@ -63,12 +63,14 @@ void main() {
expect(find.text('Light'), findsOneWidget);
expect(find.text('Temperature'), findsNothing);
expect(find.text('Illuminance'), findsNothing);
+ expect(find.text('~4.2 W/m2'), findsOneWidget);
+ expect(find.textContaining('lx'), findsNothing);
expect(
- find.byKey(const ValueKey('sensor_metric_channel_temperature')),
+ find.byKey(const ValueKey('sensor_metric_temperature')),
findsOneWidget,
);
expect(
- find.byKey(const ValueKey('sensor_metric_channel_extra:illuminance_2')),
+ find.byKey(const ValueKey('sensor_metric_extra:illuminance_2')),
findsOneWidget,
);
});