mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-13 09:20:29 +00:00
fix: Tame rapid GPS updates #41
This commit is contained in:
@@ -341,7 +341,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Meters',
|
labelText: 'Meters',
|
||||||
helperText: 'Valid range: 1 to 1000 meters',
|
helperText: 'Valid range: 10 to 1000 meters',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -353,7 +353,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
final parsed = double.tryParse(controller.text.trim());
|
final parsed = double.tryParse(controller.text.trim());
|
||||||
if (parsed == null) return;
|
if (parsed == null) return;
|
||||||
Navigator.pop(context, parsed.clamp(1.0, 1000.0));
|
Navigator.pop(context, parsed.clamp(10.0, 1000.0));
|
||||||
},
|
},
|
||||||
child: const Text('Save'),
|
child: const Text('Save'),
|
||||||
),
|
),
|
||||||
@@ -382,7 +382,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Seconds',
|
labelText: 'Seconds',
|
||||||
helperText: 'Valid range: 5 to 60 seconds',
|
helperText: 'Valid range: 10 to 31 seconds',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -394,7 +394,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
final parsed = int.tryParse(controller.text.trim());
|
final parsed = int.tryParse(controller.text.trim());
|
||||||
if (parsed == null) return;
|
if (parsed == null) return;
|
||||||
Navigator.pop(context, parsed.clamp(5, 60));
|
Navigator.pop(context, parsed.clamp(10, 31));
|
||||||
},
|
},
|
||||||
child: const Text('Save'),
|
child: const Text('Save'),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -144,11 +144,11 @@ class AppConfigSnapshotService {
|
|||||||
}
|
}
|
||||||
if (section.fastLocationMovementThresholdMeters != null) {
|
if (section.fastLocationMovementThresholdMeters != null) {
|
||||||
locationTracking.fastLocationMovementThresholdMeters =
|
locationTracking.fastLocationMovementThresholdMeters =
|
||||||
section.fastLocationMovementThresholdMeters!;
|
section.fastLocationMovementThresholdMeters!.clamp(10.0, 1000.0);
|
||||||
}
|
}
|
||||||
if (section.fastLocationActiveCadenceSeconds != null) {
|
if (section.fastLocationActiveCadenceSeconds != null) {
|
||||||
locationTracking.fastLocationActiveCadenceSeconds =
|
locationTracking.fastLocationActiveCadenceSeconds =
|
||||||
section.fastLocationActiveCadenceSeconds!;
|
section.fastLocationActiveCadenceSeconds!.clamp(10, 31);
|
||||||
}
|
}
|
||||||
await locationTracking.saveSettings();
|
await locationTracking.saveSettings();
|
||||||
await appProvider.reloadProfileScopedSettings();
|
await appProvider.reloadProfileScopedSettings();
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ import 'profiles_feature_service.dart';
|
|||||||
/// - MeshCore mesh network integration
|
/// - MeshCore mesh network integration
|
||||||
/// - Real-time position updates via callbacks
|
/// - Real-time position updates via callbacks
|
||||||
class LocationTrackingService {
|
class LocationTrackingService {
|
||||||
|
static const double _defaultFastLocationMovementThresholdMeters = 10.0;
|
||||||
|
static const double _minFastLocationMovementThresholdMeters = 10.0;
|
||||||
|
static const int _defaultFastLocationActiveCadenceSeconds = 10;
|
||||||
|
static const int _minFastLocationActiveCadenceSeconds = 10;
|
||||||
|
static const int _maxFastLocationActiveCadenceSeconds = 31;
|
||||||
|
static const Duration _fastLocationMinimumUpdateInterval = Duration(
|
||||||
|
seconds: 31,
|
||||||
|
);
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Singleton Pattern
|
// Singleton Pattern
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -75,10 +83,12 @@ class LocationTrackingService {
|
|||||||
bool fastLocationUpdatesEnabled = false;
|
bool fastLocationUpdatesEnabled = false;
|
||||||
|
|
||||||
/// Distance threshold for fast GPS updates
|
/// Distance threshold for fast GPS updates
|
||||||
double fastLocationMovementThresholdMeters = 10.0;
|
double fastLocationMovementThresholdMeters =
|
||||||
|
_defaultFastLocationMovementThresholdMeters;
|
||||||
|
|
||||||
/// Cadence for active-use fast GPS updates
|
/// Cadence for active-use fast GPS updates
|
||||||
int fastLocationActiveCadenceSeconds = 10;
|
int fastLocationActiveCadenceSeconds =
|
||||||
|
_defaultFastLocationActiveCadenceSeconds;
|
||||||
|
|
||||||
/// Target channel index for fast GPS updates; null means disabled/unset.
|
/// Target channel index for fast GPS updates; null means disabled/unset.
|
||||||
int? fastLocationChannelIdx;
|
int? fastLocationChannelIdx;
|
||||||
@@ -522,12 +532,18 @@ class LocationTrackingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateFastLocationMovementThreshold(double meters) async {
|
Future<void> updateFastLocationMovementThreshold(double meters) async {
|
||||||
fastLocationMovementThresholdMeters = meters.clamp(1.0, 1000.0);
|
fastLocationMovementThresholdMeters = meters.clamp(
|
||||||
|
_minFastLocationMovementThresholdMeters,
|
||||||
|
1000.0,
|
||||||
|
);
|
||||||
await saveSettings();
|
await saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateFastLocationActiveCadenceSeconds(int seconds) async {
|
Future<void> updateFastLocationActiveCadenceSeconds(int seconds) async {
|
||||||
fastLocationActiveCadenceSeconds = seconds.clamp(5, 60);
|
fastLocationActiveCadenceSeconds = seconds.clamp(
|
||||||
|
_minFastLocationActiveCadenceSeconds,
|
||||||
|
_maxFastLocationActiveCadenceSeconds,
|
||||||
|
);
|
||||||
await saveSettings();
|
await saveSettings();
|
||||||
_refreshFastLocationTimer();
|
_refreshFastLocationTimer();
|
||||||
}
|
}
|
||||||
@@ -583,6 +599,11 @@ class LocationTrackingService {
|
|||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final previous = _lastFastLocationSentPosition;
|
final previous = _lastFastLocationSentPosition;
|
||||||
final previousTime = _lastFastLocationSentAt;
|
final previousTime = _lastFastLocationSentAt;
|
||||||
|
if (previousTime != null &&
|
||||||
|
now.difference(previousTime) < _fastLocationMinimumUpdateInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (previous != null && previousTime != null) {
|
if (previous != null && previousTime != null) {
|
||||||
final distance = Geolocator.distanceBetween(
|
final distance = Geolocator.distanceBetween(
|
||||||
previous.latitude,
|
previous.latitude,
|
||||||
@@ -673,12 +694,14 @@ class LocationTrackingService {
|
|||||||
prefs.getBool(_scopedKey(_prefKeyFastLocationEnabled)) ?? false;
|
prefs.getBool(_scopedKey(_prefKeyFastLocationEnabled)) ?? false;
|
||||||
fastLocationMovementThresholdMeters =
|
fastLocationMovementThresholdMeters =
|
||||||
(prefs.getDouble(_scopedKey(_prefKeyFastMovementThreshold)) ??
|
(prefs.getDouble(_scopedKey(_prefKeyFastMovementThreshold)) ??
|
||||||
gpsUpdateDistance)
|
_defaultFastLocationMovementThresholdMeters)
|
||||||
.clamp(1.0, 1000.0);
|
.clamp(_minFastLocationMovementThresholdMeters, 1000.0);
|
||||||
fastLocationActiveCadenceSeconds =
|
fastLocationActiveCadenceSeconds =
|
||||||
(prefs.getInt(_scopedKey(_prefKeyFastActiveCadence)) ?? 10).clamp(
|
(prefs.getInt(_scopedKey(_prefKeyFastActiveCadence)) ??
|
||||||
5,
|
_defaultFastLocationActiveCadenceSeconds)
|
||||||
60,
|
.clamp(
|
||||||
|
_minFastLocationActiveCadenceSeconds,
|
||||||
|
_maxFastLocationActiveCadenceSeconds,
|
||||||
);
|
);
|
||||||
fastLocationChannelIdx = prefs.getInt(_scopedKey(_prefKeyFastChannelIdx));
|
fastLocationChannelIdx = prefs.getInt(_scopedKey(_prefKeyFastChannelIdx));
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
# 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
|
# 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.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2026.0323.1+40
|
version: 2026.0323.2+41
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.9.2
|
sdk: ^3.9.2
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ void main() {
|
|||||||
service.fastLocationChannelIdx = null;
|
service.fastLocationChannelIdx = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('loads conservative fast location defaults', () async {
|
||||||
|
await service.loadSettings();
|
||||||
|
|
||||||
|
expect(service.fastLocationMovementThresholdMeters, 10.0);
|
||||||
|
expect(service.fastLocationActiveCadenceSeconds, 10);
|
||||||
|
});
|
||||||
|
|
||||||
test('persists and restores fast location channel idx', () async {
|
test('persists and restores fast location channel idx', () async {
|
||||||
await service.updateFastLocationChannelIdx(3);
|
await service.updateFastLocationChannelIdx(3);
|
||||||
|
|
||||||
@@ -37,4 +44,12 @@ void main() {
|
|||||||
|
|
||||||
expect(service.fastLocationChannelIdx, isNull);
|
expect(service.fastLocationChannelIdx, isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('clamps fast location settings to conservative limits', () async {
|
||||||
|
await service.updateFastLocationMovementThreshold(3);
|
||||||
|
await service.updateFastLocationActiveCadenceSeconds(45);
|
||||||
|
|
||||||
|
expect(service.fastLocationMovementThresholdMeters, 10.0);
|
||||||
|
expect(service.fastLocationActiveCadenceSeconds, 31);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user