mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 08:20:36 +00:00
fix: Merge self replay and refresh self telemetry
This commit is contained in:
@@ -666,7 +666,23 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
final matchingSentReplayIndex = _findMatchingSentReplayIndex(finalMessage);
|
||||
if (matchingSentReplayIndex != -1) {
|
||||
_clearChannelSendWarning(_messages[matchingSentReplayIndex].id);
|
||||
final existingId = _messages[matchingSentReplayIndex].id;
|
||||
_clearChannelSendWarning(existingId);
|
||||
if (contactLocationSnapshot != null) {
|
||||
_messageContactLocations[existingId] = contactLocationSnapshot;
|
||||
}
|
||||
_messageReceptionDetails[existingId] =
|
||||
MessageReceptionDetails.mergeDuplicate(
|
||||
existing: _messageReceptionDetails[existingId],
|
||||
incoming: receptionDetailsSnapshot,
|
||||
);
|
||||
final existingMessage = _messages[matchingSentReplayIndex];
|
||||
_messages[matchingSentReplayIndex] = existingMessage.copyWith(
|
||||
pathLen: finalMessage.pathLen > 0 ? finalMessage.pathLen : existingMessage.pathLen,
|
||||
pathBytes: finalMessage.pathBytes ?? existingMessage.pathBytes,
|
||||
);
|
||||
_persistMessages();
|
||||
return;
|
||||
}
|
||||
|
||||
_messages.add(finalMessage);
|
||||
@@ -1214,9 +1230,7 @@ class MessagesProvider with ChangeNotifier {
|
||||
for (final message in messages) {
|
||||
final occurrenceCount = _messageOccurrenceCount(message);
|
||||
final existingIndex = entries.indexWhere(
|
||||
(entry) =>
|
||||
entry.message.text == message.text &&
|
||||
_matchesDuplicateScope(entry.message, message),
|
||||
(entry) => _shouldCollapseDisplayMessage(entry.message, message),
|
||||
);
|
||||
|
||||
if (existingIndex == -1) {
|
||||
@@ -1234,6 +1248,15 @@ class MessagesProvider with ChangeNotifier {
|
||||
return entries;
|
||||
}
|
||||
|
||||
bool _shouldCollapseDisplayMessage(Message existing, Message message) {
|
||||
if (existing.isSentMessage || message.isSentMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return existing.text == message.text &&
|
||||
_matchesDuplicateScope(existing, message);
|
||||
}
|
||||
|
||||
int _messageOccurrenceCount(Message message) =>
|
||||
_messageReceptionDetails[message.id]?.receivedCopies ?? 1;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ enum SensorRefreshState { idle, refreshing, success, timeout, unavailable }
|
||||
|
||||
class SensorsProvider with ChangeNotifier {
|
||||
static const Duration _successStateRetention = Duration(minutes: 1);
|
||||
static const int selfAutoRefreshMinutes = 1;
|
||||
static const Duration selfAutoRefreshInterval = Duration(seconds: 30);
|
||||
static const String _watchedSensorsKey = 'watched_sensor_keys';
|
||||
static const String _visibleSensorMetricsKey = 'visible_sensor_metrics';
|
||||
static const String _fieldSpanKey = 'sensor_field_spans';
|
||||
@@ -374,18 +374,18 @@ class SensorsProvider with ChangeNotifier {
|
||||
return List<String>.unmodifiable(dueKeys);
|
||||
}
|
||||
|
||||
bool _isRefreshDue(
|
||||
bool _isRefreshDueForInterval(
|
||||
String publicKeyHex, {
|
||||
required int minutes,
|
||||
required Duration interval,
|
||||
required DateTime refreshTime,
|
||||
}) {
|
||||
if (minutes <= 0) {
|
||||
if (interval <= Duration.zero) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final lastRefreshAt = _lastRefreshAttemptAt[publicKeyHex];
|
||||
return lastRefreshAt == null ||
|
||||
refreshTime.difference(lastRefreshAt) >= Duration(minutes: minutes);
|
||||
refreshTime.difference(lastRefreshAt) >= interval;
|
||||
}
|
||||
|
||||
Future<void> toggleMetric(
|
||||
@@ -769,9 +769,9 @@ class SensorsProvider with ChangeNotifier {
|
||||
final self = selfContact(contactsProvider, connectionProvider);
|
||||
if (self != null &&
|
||||
!dueKeys.contains(self.publicKeyHex) &&
|
||||
_isRefreshDue(
|
||||
_isRefreshDueForInterval(
|
||||
self.publicKeyHex,
|
||||
minutes: selfAutoRefreshMinutes,
|
||||
interval: selfAutoRefreshInterval,
|
||||
refreshTime: refreshTime,
|
||||
)) {
|
||||
dueKeys.insert(0, self.publicKeyHex);
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
|
||||
import '../models/contact.dart';
|
||||
import '../providers/connection_provider.dart';
|
||||
import '../providers/contacts_provider.dart';
|
||||
import '../providers/map_provider.dart';
|
||||
import '../providers/sensors_provider.dart';
|
||||
import '../widgets/sensors/bthome_met_history_sheet.dart';
|
||||
import '../widgets/sensors/sensor_telemetry_card.dart';
|
||||
@@ -21,7 +22,10 @@ class SensorsTab extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SensorsTabState extends State<SensorsTab> {
|
||||
static const Duration _autoRefreshTickInterval = Duration(seconds: 30);
|
||||
Timer? _minuteTicker;
|
||||
final Map<String, DateTime> _lastCenteredTelemetryAtBySensor =
|
||||
<String, DateTime>{};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -61,22 +65,8 @@ class _SensorsTabState extends State<SensorsTab> {
|
||||
return;
|
||||
}
|
||||
|
||||
final now = DateTime.now();
|
||||
final nextMinute = DateTime(
|
||||
now.year,
|
||||
now.month,
|
||||
now.day,
|
||||
now.hour,
|
||||
now.minute + 1,
|
||||
);
|
||||
final delay = nextMinute.difference(now);
|
||||
|
||||
_minuteTicker = Timer(delay, () {
|
||||
if (!mounted) return;
|
||||
_minuteTicker = Timer.periodic(_autoRefreshTickInterval, (_) {
|
||||
unawaited(_handleMinuteTick());
|
||||
_minuteTicker = Timer.periodic(const Duration(minutes: 1), (_) {
|
||||
unawaited(_handleMinuteTick());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -225,6 +215,65 @@ class _SensorsTabState extends State<SensorsTab> {
|
||||
);
|
||||
}
|
||||
|
||||
void _maybeCenterMapOnTelemetryUpdate(
|
||||
Iterable<String> sensorKeys, {
|
||||
required SensorsProvider sensorsProvider,
|
||||
required ContactsProvider contactsProvider,
|
||||
required ConnectionProvider connectionProvider,
|
||||
}) {
|
||||
if (!widget.isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
Contact? latestContact;
|
||||
DateTime? latestTimestamp;
|
||||
|
||||
for (final key in sensorKeys) {
|
||||
final contact = sensorsProvider.contactForDisplay(
|
||||
key,
|
||||
contactsProvider: contactsProvider,
|
||||
connectionProvider: connectionProvider,
|
||||
);
|
||||
final timestamp = contact?.telemetry?.timestamp;
|
||||
final location = contact?.displayLocation;
|
||||
if (contact == null || timestamp == null || location == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final previousTimestamp = _lastCenteredTelemetryAtBySensor[key];
|
||||
if (previousTimestamp != null && !timestamp.isAfter(previousTimestamp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (latestTimestamp == null || timestamp.isAfter(latestTimestamp)) {
|
||||
latestContact = contact;
|
||||
latestTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
if (latestContact == null || latestTimestamp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastCenteredTelemetryAtBySensor[latestContact.publicKeyHex] =
|
||||
latestTimestamp;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted || !widget.isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
final location = latestContact!.displayLocation;
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.read<MapProvider>().navigateToLocation(
|
||||
location: location,
|
||||
zoom: 15.0,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -247,6 +296,16 @@ class _SensorsTabState extends State<SensorsTab> {
|
||||
contactsProvider: contactsProvider,
|
||||
connectionProvider: connectionProvider,
|
||||
);
|
||||
final displayKeys = <String>[
|
||||
...?selfDisplayKey == null ? null : <String>[selfDisplayKey],
|
||||
...watchedKeys,
|
||||
];
|
||||
_maybeCenterMapOnTelemetryUpdate(
|
||||
displayKeys,
|
||||
sensorsProvider: sensorsProvider,
|
||||
contactsProvider: contactsProvider,
|
||||
connectionProvider: connectionProvider,
|
||||
);
|
||||
final hasAnyCards =
|
||||
selfDisplayKey != null || watchedKeys.isNotEmpty;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user