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

@@ -31,17 +31,22 @@ class MeshMapNode {
}
class MeshMapNodesService {
static const String _nodesEndpoint = 'https://api.meshcore.nz/api/v1/map/nodes';
static const String _nodesEndpoint =
'https://api.meshcore.nz/api/v1/map/nodes';
static const Duration _cacheTtl = Duration(minutes: 2);
static const Duration traceCacheTtl = Duration(minutes: 10);
static List<MeshMapNode>? _cachedNodes;
static DateTime? _cachedAt;
static Future<List<MeshMapNode>> fetchNodes({bool forceRefresh = false}) async {
static Future<List<MeshMapNode>> fetchNodes({
bool forceRefresh = false,
Duration cacheTtl = _cacheTtl,
}) async {
final now = DateTime.now();
if (!forceRefresh &&
_cachedNodes != null &&
_cachedAt != null &&
now.difference(_cachedAt!) < _cacheTtl) {
now.difference(_cachedAt!) < cacheTtl) {
return _cachedNodes!;
}
@@ -58,7 +63,9 @@ class MeshMapNodesService {
final nodes = nodesRaw
.whereType<Map<String, dynamic>>()
.map(MeshMapNode.fromJson)
.where((n) => n.publicKey.isNotEmpty && n.latitude != 0 && n.longitude != 0)
.where(
(n) => n.publicKey.isNotEmpty && n.latitude != 0 && n.longitude != 0,
)
.toList();
_cachedNodes = nodes;

View File

@@ -2,15 +2,21 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/message.dart';
import '../models/message_contact_location.dart';
import 'package:latlong2/latlong.dart';
/// Service for persisting messages to local storage
class MessageStorageService {
static const String _messagesKey = 'stored_messages';
static const String _messageContactLocationsKey =
'stored_message_contact_locations';
static const int _maxStoredMessages = 1000; // Store up to 1000 messages
/// Save messages to persistent storage
Future<void> saveMessages(List<Message> messages) async {
Future<void> saveMessages(
List<Message> messages, {
Map<String, MessageContactLocation> messageContactLocations = const {},
}) async {
try {
final prefs = await SharedPreferences.getInstance();
@@ -24,6 +30,19 @@ class MessageStorageService {
final jsonString = jsonEncode(limitedList);
await prefs.setString(_messagesKey, jsonString);
final retainedMessageIds = limitedList
.map((entry) => entry['id'] as String)
.toSet();
final locationJson = <String, dynamic>{};
for (final entry in messageContactLocations.entries) {
if (retainedMessageIds.contains(entry.key)) {
locationJson[entry.key] = entry.value.toJson();
}
}
await prefs.setString(
_messageContactLocationsKey,
jsonEncode(locationJson),
);
debugPrint(
'✅ [MessageStorage] Saved ${limitedList.length} messages to storage',
@@ -33,6 +52,36 @@ class MessageStorageService {
}
}
Future<Map<String, MessageContactLocation>> loadMessageContactLocations()
async {
try {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString(_messageContactLocationsKey);
if (jsonString == null || jsonString.isEmpty) {
return const {};
}
final decoded = jsonDecode(jsonString);
if (decoded is! Map<String, dynamic>) {
return const {};
}
final result = <String, MessageContactLocation>{};
for (final entry in decoded.entries) {
final value = entry.value;
if (value is! Map<String, dynamic>) continue;
final snapshot = MessageContactLocation.fromJson(value);
if (snapshot != null) {
result[entry.key] = snapshot;
}
}
return result;
} catch (e) {
debugPrint('❌ [MessageStorage] Error loading contact locations: $e');
return const {};
}
}
/// Load messages from persistent storage
Future<List<Message>> loadMessages() async {
try {
@@ -66,6 +115,7 @@ class MessageStorageService {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_messagesKey);
await prefs.remove(_messageContactLocationsKey);
debugPrint('✅ [MessageStorage] Cleared all stored messages');
} catch (e) {
debugPrint('❌ [MessageStorage] Error clearing messages: $e');