Log contact data without revealing

This commit is contained in:
Janez T
2026-03-06 20:47:02 +01:00
parent ca8e8e6ecb
commit 0e1a56d765
12 changed files with 745 additions and 149 deletions

View File

@@ -607,14 +607,30 @@ class AppProvider with ChangeNotifier {
connectionProvider.onMessageReceived = (message) {
// Enrich message with sender name from contacts first
Message enrichedMessage = message;
Contact? senderContact;
if (message.senderPublicKeyPrefix != null && message.senderName == null) {
final contact = contactsProvider.findContactByKey(
message.senderPublicKeyPrefix!,
);
if (contact != null) {
senderContact = contact;
enrichedMessage = message.copyWith(senderName: contact.advName);
}
}
senderContact ??= message.senderPublicKeyPrefix != null
? contactsProvider.findContactByKey(message.senderPublicKeyPrefix!)
: null;
senderContact ??= enrichedMessage.senderName != null
? contactsProvider.contacts
.where((c) => c.advName == enrichedMessage.senderName)
.firstOrNull
: null;
final contactLocationSnapshot = senderContact != null
? contactsProvider.buildMessageContactLocationSnapshot(
senderContact,
capturedAt: enrichedMessage.receivedAt,
)
: null;
// Check if message is a drawing broadcast
if (DrawingMessageParser.isDrawingMessage(enrichedMessage.text)) {
@@ -645,6 +661,7 @@ class AppProvider with ChangeNotifier {
messagesProvider.addMessage(
updatedMessage,
contactLookup: (name) => '',
contactLocationSnapshot: contactLocationSnapshot,
);
// Broadcast drawing message to SSE clients if server is running
@@ -680,6 +697,7 @@ class AppProvider with ChangeNotifier {
return '';
}
},
contactLocationSnapshot: contactLocationSnapshot,
);
connectionProvider.broadcastMessageToSseClients(enrichedMessage);
return;
@@ -707,6 +725,7 @@ class AppProvider with ChangeNotifier {
return '';
}
},
contactLocationSnapshot: contactLocationSnapshot,
);
connectionProvider.broadcastMessageToSseClients(enrichedMessage);
return;
@@ -743,6 +762,7 @@ class AppProvider with ChangeNotifier {
return '';
}
},
contactLocationSnapshot: contactLocationSnapshot,
);
// Broadcast message to SSE clients if server is running

View File

@@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart';
import '../models/contact.dart';
import '../models/message_contact_location.dart';
import '../services/cayenne_lpp_parser.dart';
import '../services/contact_storage_service.dart';
import '../utils/key_comparison.dart';
@@ -214,6 +215,52 @@ class ContactsProvider with ChangeNotifier {
List<Contact> get chatContactsWithLocation =>
chatContacts.where((c) => c.displayLocation != null).toList();
MessageContactLocation? buildMessageContactLocationSnapshot(
Contact contact, {
DateTime? capturedAt,
}) {
final snapshotTime = capturedAt ?? DateTime.now();
final telemetryGps = _getValidGpsOrNull(contact.telemetry?.gpsLocation);
final telemetryTimestamp = contact.telemetry?.timestamp;
AdvertLocation? advertLocation;
for (final point in contact.advertHistory) {
if (!point.timestamp.isAfter(snapshotTime)) {
advertLocation = point;
break;
}
}
advertLocation ??= contact.advertHistory.isNotEmpty
? contact.advertHistory.first
: null;
if (telemetryGps != null) {
final shouldUseTelemetry =
telemetryTimestamp == null ||
advertLocation == null ||
!telemetryTimestamp.isBefore(advertLocation.timestamp);
if (shouldUseTelemetry) {
return MessageContactLocation(
location: telemetryGps,
source: 'telemetry',
capturedAt: snapshotTime,
sourceTimestamp: telemetryTimestamp,
);
}
}
if (advertLocation != null) {
return MessageContactLocation(
location: advertLocation.location,
source: 'advert',
capturedAt: snapshotTime,
sourceTimestamp: advertLocation.timestamp,
);
}
return null;
}
/// Sort contacts by last seen (most recent first)
int _sortByLastSeen(Contact a, Contact b) {
return b.lastSeenTime.compareTo(a.lastSeenTime);

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import '../models/message.dart';
import '../models/contact.dart';
import '../models/message_contact_location.dart';
import '../models/sar_marker.dart';
import '../models/map_drawing.dart';
import '../services/message_storage_service.dart';
@@ -20,6 +21,7 @@ class MessagesProvider with ChangeNotifier {
final NotificationService _notificationService = NotificationService();
bool _isInitialized = false;
AppLocalizations? _localizations;
final Map<String, MessageContactLocation> _messageContactLocations = {};
// Track pending sent messages by expected ACK/TAG
final Map<int, Message> _pendingSentMessages = {};
@@ -104,6 +106,9 @@ class MessagesProvider with ChangeNotifier {
String? get targetMessageId => _targetMessageId;
MessageContactLocation? getMessageContactLocation(String messageId) =>
_messageContactLocations[messageId];
/// Set localizations for notifications
void setLocalizations(AppLocalizations localizations) {
_localizations = localizations;
@@ -132,6 +137,11 @@ class MessagesProvider with ChangeNotifier {
try {
debugPrint('📦 [MessagesProvider] Loading persisted messages...');
final storedMessages = await _storageService.loadMessages();
final storedContactLocations = await _storageService
.loadMessageContactLocations();
_messageContactLocations
..clear()
..addAll(storedContactLocations);
// Add stored messages with enhancement to ensure SAR detection
for (final message in storedMessages) {
@@ -294,6 +304,7 @@ class MessagesProvider with ChangeNotifier {
void addMessage(
Message message, {
String Function(String name)? contactLookup,
MessageContactLocation? contactLocationSnapshot,
}) {
// Always enhance message with SAR parser to detect SAR markers
var enhancedMessage = SarMessageParser.enhanceMessage(message);
@@ -384,6 +395,9 @@ class MessagesProvider with ChangeNotifier {
}
_messages.add(finalMessage);
if (contactLocationSnapshot != null) {
_messageContactLocations[finalMessage.id] = contactLocationSnapshot;
}
// If it's a SAR marker message, extract and store the marker
if (finalMessage.isSarMarker) {
@@ -570,7 +584,10 @@ class MessagesProvider with ChangeNotifier {
/// Persist messages to storage (async, non-blocking)
Future<void> _persistMessages() async {
try {
await _storageService.saveMessages(_messages);
await _storageService.saveMessages(
_messages,
messageContactLocations: _messageContactLocations,
);
} catch (e) {
debugPrint('❌ [MessagesProvider] Error persisting messages: $e');
}
@@ -685,6 +702,7 @@ class MessagesProvider with ChangeNotifier {
}
_messageContactMap.remove(messageId);
_groupedMessageMapping.remove(messageId);
_messageContactLocations.remove(messageId);
debugPrint('🗑️ [MessagesProvider] Message $messageId deleted');
@@ -713,6 +731,7 @@ class MessagesProvider with ChangeNotifier {
void clearMessages() {
_messages.clear();
_sarMarkers.clear();
_messageContactLocations.clear();
_persistMessages();
notifyListeners();
}
@@ -727,6 +746,7 @@ class MessagesProvider with ChangeNotifier {
void clearAll() {
_messages.clear();
_sarMarkers.clear();
_messageContactLocations.clear();
_persistMessages();
notifyListeners();
}