mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-12 17:00:28 +00:00
Refactor code for improved readability and consistency across multiple files
- Updated formatting in `drawing_toolbar.dart` for better readability, including breaking long lines and ensuring consistent indentation. - Enhanced the `recipient_selector_sheet.dart` by adjusting line breaks and improving the layout of text styles. - Refactored `sar_update_sheet.dart` to improve readability, including restructuring widget layouts and ensuring consistent formatting. - Cleaned up imports and removed unnecessary lines in `widget_test.dart`.
This commit is contained in:
@@ -62,7 +62,7 @@ class ConnectionProvider with ChangeNotifier {
|
||||
DeviceInfo _deviceInfo = DeviceInfo();
|
||||
DeviceInfo get deviceInfo => _deviceInfo;
|
||||
|
||||
List<ScannedDevice> _scannedDevices = [];
|
||||
final List<ScannedDevice> _scannedDevices = [];
|
||||
List<ScannedDevice> get scannedDevices => _scannedDevices;
|
||||
|
||||
bool _isScanning = false;
|
||||
@@ -162,14 +162,18 @@ class ConnectionProvider with ChangeNotifier {
|
||||
debugPrint(
|
||||
' Updated deviceInfo.connectionState: ${_deviceInfo.connectionState}',
|
||||
);
|
||||
debugPrint(' Updated deviceInfo.isConnected: ${_deviceInfo.isConnected}');
|
||||
debugPrint(
|
||||
' Updated deviceInfo.isConnected: ${_deviceInfo.isConnected}',
|
||||
);
|
||||
debugPrint(' isReconnecting: ${_bleService.isReconnecting}');
|
||||
notifyListeners();
|
||||
debugPrint(' Notified listeners');
|
||||
};
|
||||
|
||||
_bleService.onReconnectionAttempt = (attemptNumber, maxAttempts) {
|
||||
debugPrint('🔄 [Provider] Reconnection attempt $attemptNumber/$maxAttempts');
|
||||
debugPrint(
|
||||
'🔄 [Provider] Reconnection attempt $attemptNumber/$maxAttempts',
|
||||
);
|
||||
// Notify UI to update reconnection status display
|
||||
notifyListeners();
|
||||
};
|
||||
@@ -198,7 +202,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
};
|
||||
|
||||
_bleService.onContactNotFound = (contactPublicKey) async {
|
||||
debugPrint('🔧 [Provider] Contact not found error detected - initiating auto-recovery');
|
||||
debugPrint(
|
||||
'🔧 [Provider] Contact not found error detected - initiating auto-recovery',
|
||||
);
|
||||
|
||||
if (contactPublicKey == null) {
|
||||
debugPrint(' ⚠️ No contact public key available for recovery');
|
||||
@@ -206,15 +212,22 @@ class ConnectionProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
// Generate operation ID from public key
|
||||
final operationId = contactPublicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':');
|
||||
final operationId = contactPublicKey
|
||||
.sublist(0, 6)
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
final pendingOp = _pendingSendOperations[operationId];
|
||||
|
||||
if (pendingOp == null || pendingOp.contact == null) {
|
||||
debugPrint(' ⚠️ No pending operation found for recovery: $operationId');
|
||||
debugPrint(
|
||||
' ⚠️ No pending operation found for recovery: $operationId',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint(' 📋 Found pending operation for: ${pendingOp.contact!.advName}');
|
||||
debugPrint(
|
||||
' 📋 Found pending operation for: ${pendingOp.contact!.advName}',
|
||||
);
|
||||
debugPrint(' 📤 Step 1: Adding contact to radio...');
|
||||
|
||||
try {
|
||||
@@ -266,7 +279,8 @@ class ConnectionProvider with ChangeNotifier {
|
||||
onMessageReceived?.call(enhancedMessage);
|
||||
|
||||
// Complete sync response completer (message received = continue syncing)
|
||||
if (_syncResponseCompleter != null && !_syncResponseCompleter!.isCompleted) {
|
||||
if (_syncResponseCompleter != null &&
|
||||
!_syncResponseCompleter!.isCompleted) {
|
||||
_syncResponseCompleter!.complete(true);
|
||||
}
|
||||
};
|
||||
@@ -295,7 +309,8 @@ class ConnectionProvider with ChangeNotifier {
|
||||
_noMoreMessages = true;
|
||||
|
||||
// Complete sync response completer (no more messages = stop syncing)
|
||||
if (_syncResponseCompleter != null && !_syncResponseCompleter!.isCompleted) {
|
||||
if (_syncResponseCompleter != null &&
|
||||
!_syncResponseCompleter!.isCompleted) {
|
||||
_syncResponseCompleter!.complete(false);
|
||||
}
|
||||
};
|
||||
@@ -397,7 +412,8 @@ class ConnectionProvider with ChangeNotifier {
|
||||
onMessageDelivered?.call(ackCode, roundTripTimeMs);
|
||||
};
|
||||
|
||||
_bleService.onMessageEchoDetected = (messageId, echoCount, snrRaw, rssiDbm) {
|
||||
_bleService
|
||||
.onMessageEchoDetected = (messageId, echoCount, snrRaw, rssiDbm) {
|
||||
debugPrint(
|
||||
'🔊 [Provider] Echo detected - Message: $messageId, Count: $echoCount',
|
||||
);
|
||||
@@ -588,7 +604,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
|
||||
/// Connect to a device
|
||||
Future<bool> connect(BluetoothDevice device) async {
|
||||
debugPrint('🔵 [Provider] connect() called for device: ${device.platformName}');
|
||||
debugPrint(
|
||||
'🔵 [Provider] connect() called for device: ${device.platformName}',
|
||||
);
|
||||
|
||||
_deviceInfo = _deviceInfo.copyWith(
|
||||
deviceId: device.remoteId.toString(),
|
||||
@@ -690,8 +708,12 @@ class ConnectionProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
try {
|
||||
debugPrint('📻 [Provider] Configuring default public channel (channel 0)');
|
||||
debugPrint(' Using secret: ${MeshCoreConstants.defaultPublicChannelSecret.map((b) => b.toRadixString(16).padLeft(2, '0')).join('')}');
|
||||
debugPrint(
|
||||
'📻 [Provider] Configuring default public channel (channel 0)',
|
||||
);
|
||||
debugPrint(
|
||||
' Using secret: ${MeshCoreConstants.defaultPublicChannelSecret.map((b) => b.toRadixString(16).padLeft(2, '0')).join('')}',
|
||||
);
|
||||
await _bleService.setChannel(
|
||||
channelIdx: 0,
|
||||
channelName: 'Public Channel',
|
||||
@@ -701,7 +723,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
} catch (e) {
|
||||
_error = 'Failed to configure public channel: $e';
|
||||
debugPrint('❌ [Provider] Public channel configuration failed: $e');
|
||||
debugPrint(' This may be normal if the channel is pre-configured in firmware');
|
||||
debugPrint(
|
||||
' This may be normal if the channel is pre-configured in firmware',
|
||||
);
|
||||
notifyListeners();
|
||||
rethrow; // Re-throw to notify caller of failure
|
||||
}
|
||||
@@ -752,9 +776,13 @@ class ConnectionProvider with ChangeNotifier {
|
||||
// Log path status and retry info
|
||||
if (contact != null) {
|
||||
if (retryAttempt > 0) {
|
||||
debugPrint('🔄 [ConnectionProvider] Sending message to ${contact.advName} (retry $retryAttempt/3)');
|
||||
debugPrint(
|
||||
'🔄 [ConnectionProvider] Sending message to ${contact.advName} (retry $retryAttempt/3)',
|
||||
);
|
||||
} else {
|
||||
debugPrint('📤 [ConnectionProvider] Sending message to ${contact.advName}');
|
||||
debugPrint(
|
||||
'📤 [ConnectionProvider] Sending message to ${contact.advName}',
|
||||
);
|
||||
}
|
||||
debugPrint(' Type: ${contact.type.displayName}');
|
||||
debugPrint(' Path status: ${contact.pathDescription}');
|
||||
@@ -764,12 +792,17 @@ class ConnectionProvider with ChangeNotifier {
|
||||
debugPrint(' ⚠️ No path available - will use flood mode');
|
||||
}
|
||||
} else if (retryAttempt > 0) {
|
||||
debugPrint('🔄 [ConnectionProvider] Sending message (retry $retryAttempt/3)');
|
||||
debugPrint(
|
||||
'🔄 [ConnectionProvider] Sending message (retry $retryAttempt/3)',
|
||||
);
|
||||
}
|
||||
|
||||
// Track pending operation for auto-recovery (if contact not found in radio)
|
||||
if (contact != null) {
|
||||
final operationId = contactPublicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':');
|
||||
final operationId = contactPublicKey
|
||||
.sublist(0, 6)
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
_pendingSendOperations[operationId] = _PendingSendOperation(
|
||||
contactPublicKey: contactPublicKey,
|
||||
text: text,
|
||||
@@ -777,7 +810,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
contact: contact,
|
||||
retryAttempt: retryAttempt,
|
||||
);
|
||||
debugPrint(' 📝 Tracked pending operation for auto-recovery: $operationId');
|
||||
debugPrint(
|
||||
' 📝 Tracked pending operation for auto-recovery: $operationId',
|
||||
);
|
||||
}
|
||||
|
||||
// IMPORTANT: Track pending message BEFORE sending to avoid race condition
|
||||
@@ -785,7 +820,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
// the callback will fire before we add the message ID to the queue.
|
||||
if (messageId != null) {
|
||||
_messageDeliveryTracker.trackPendingMessage(messageId);
|
||||
debugPrint(' Added message ID to pending queue BEFORE sending: $messageId');
|
||||
debugPrint(
|
||||
' Added message ID to pending queue BEFORE sending: $messageId',
|
||||
);
|
||||
}
|
||||
|
||||
// Send the message with retry attempt info
|
||||
@@ -798,7 +835,10 @@ class ConnectionProvider with ChangeNotifier {
|
||||
// Clear pending operation after successful send (no error)
|
||||
// If ERR_CODE_NOT_FOUND occurs, the operation will be recovered automatically
|
||||
if (contact != null) {
|
||||
final operationId = contactPublicKey.sublist(0, 6).map((b) => b.toRadixString(16).padLeft(2, '0')).join(':');
|
||||
final operationId = contactPublicKey
|
||||
.sublist(0, 6)
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
// Use a small delay to allow error response to arrive before clearing
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
_pendingSendOperations.remove(operationId);
|
||||
@@ -838,7 +878,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
await _bleService.sendChannelMessage(channelIdx: channelIdx, text: text);
|
||||
|
||||
debugPrint('✅ [ConnectionProvider] BLE send completed');
|
||||
debugPrint(' Checking messageId: ${messageId != null ? "Present ($messageId)" : "NULL"}');
|
||||
debugPrint(
|
||||
' Checking messageId: ${messageId != null ? "Present ($messageId)" : "NULL"}',
|
||||
);
|
||||
|
||||
// Channel messages are ephemeral (not persisted) - mark as "sent" immediately
|
||||
// They don't have ACK/TAG mechanism like direct messages
|
||||
@@ -1347,7 +1389,9 @@ class ConnectionProvider with ChangeNotifier {
|
||||
},
|
||||
);
|
||||
|
||||
debugPrint(' After iteration ${i + 1}: hasMore=$hasMore, _noMoreMessages=$_noMoreMessages');
|
||||
debugPrint(
|
||||
' After iteration ${i + 1}: hasMore=$hasMore, _noMoreMessages=$_noMoreMessages',
|
||||
);
|
||||
|
||||
if (!hasMore) {
|
||||
debugPrint(' ✅ No more messages available, stopping sync');
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../models/contact.dart';
|
||||
import '../services/cayenne_lpp_parser.dart';
|
||||
@@ -23,11 +22,14 @@ class ContactsProvider with ChangeNotifier {
|
||||
if (_isInitialized) return;
|
||||
|
||||
try {
|
||||
debugPrint('📦 [ContactsProvider] Early loading persisted contacts (no filtering)...');
|
||||
debugPrint(
|
||||
'📦 [ContactsProvider] Early loading persisted contacts (no filtering)...',
|
||||
);
|
||||
final storedContacts = await _storageService.loadContacts();
|
||||
|
||||
// Add stored contacts (excluding any with all-zeros public key)
|
||||
const publicChannelKey = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const publicChannelKey =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
for (final contact in storedContacts) {
|
||||
// Skip any contacts with all-zeros public key (shouldn't happen, but safety check)
|
||||
if (contact.publicKeyHex == publicChannelKey) {
|
||||
@@ -37,7 +39,9 @@ class ContactsProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
debugPrint('✅ [ContactsProvider] Early loaded ${storedContacts.length} persisted contacts');
|
||||
debugPrint(
|
||||
'✅ [ContactsProvider] Early loaded ${storedContacts.length} persisted contacts',
|
||||
);
|
||||
|
||||
// Ensure public channel exists after loading
|
||||
_ensurePublicChannelExists();
|
||||
@@ -68,7 +72,8 @@ class ContactsProvider with ChangeNotifier {
|
||||
);
|
||||
|
||||
// Add stored contacts (excluding any with all-zeros public key)
|
||||
const publicChannelKey = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const publicChannelKey =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
for (final contact in storedContacts) {
|
||||
// Skip any contacts with all-zeros public key (shouldn't happen, but safety check)
|
||||
if (contact.publicKeyHex == publicChannelKey) {
|
||||
@@ -78,7 +83,9 @@ class ContactsProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
debugPrint('✅ [ContactsProvider] Loaded ${storedContacts.length} persisted contacts');
|
||||
debugPrint(
|
||||
'✅ [ContactsProvider] Loaded ${storedContacts.length} persisted contacts',
|
||||
);
|
||||
|
||||
// Ensure public channel exists after loading
|
||||
_ensurePublicChannelExists();
|
||||
@@ -93,10 +100,14 @@ class ContactsProvider with ChangeNotifier {
|
||||
|
||||
/// Remove self-contact from loaded contacts (called after BLE connection established)
|
||||
void _removeSelfContact(Uint8List devicePublicKey) {
|
||||
final selfKeyHex = devicePublicKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join('');
|
||||
final selfKeyHex = devicePublicKey
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join('');
|
||||
if (_contacts.containsKey(selfKeyHex)) {
|
||||
final selfContact = _contacts[selfKeyHex]!;
|
||||
debugPrint('🗑️ [ContactsProvider] Removing self-contact: ${selfContact.advName}');
|
||||
debugPrint(
|
||||
'🗑️ [ContactsProvider] Removing self-contact: ${selfContact.advName}',
|
||||
);
|
||||
_contacts.remove(selfKeyHex);
|
||||
_persistContacts();
|
||||
notifyListeners();
|
||||
@@ -106,11 +117,14 @@ class ContactsProvider with ChangeNotifier {
|
||||
/// Ensure public channel always exists in the list
|
||||
void _ensurePublicChannelExists() {
|
||||
// Public channel has all-zeros public key (32 bytes = 64 hex chars)
|
||||
const publicChannelKey = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const publicChannelKey =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
if (!_contacts.containsKey(publicChannelKey)) {
|
||||
// Create a pseudo-contact for the public channel (ephemeral broadcast)
|
||||
_contacts[publicChannelKey] = Contact(
|
||||
publicKey: Uint8List.fromList(List.filled(32, 0)), // Zero key for public
|
||||
publicKey: Uint8List.fromList(
|
||||
List.filled(32, 0),
|
||||
), // Zero key for public
|
||||
type: ContactType.channel, // Channel type (not room!)
|
||||
flags: 0,
|
||||
outPathLen: 0,
|
||||
@@ -128,7 +142,8 @@ class ContactsProvider with ChangeNotifier {
|
||||
Future<void> _persistContacts() async {
|
||||
try {
|
||||
// Don't persist the public channel pseudo-contact (all zeros key)
|
||||
const publicChannelKey = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const publicChannelKey =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000';
|
||||
final contactsToSave = _contacts.entries
|
||||
.where((entry) => entry.key != publicChannelKey)
|
||||
.map((entry) => entry.value)
|
||||
@@ -159,7 +174,8 @@ class ContactsProvider with ChangeNotifier {
|
||||
/// Get both rooms and channels (destinations for SAR markers)
|
||||
List<Contact> get roomsAndChannels {
|
||||
_ensurePublicChannelExists();
|
||||
return contacts.where((c) => c.isRoom || c.isChannel).toList()..sort(_sortByLastSeen);
|
||||
return contacts.where((c) => c.isRoom || c.isChannel).toList()
|
||||
..sort(_sortByLastSeen);
|
||||
}
|
||||
|
||||
/// Get contacts with location (for map display)
|
||||
@@ -179,8 +195,11 @@ class ContactsProvider with ChangeNotifier {
|
||||
/// Excludes contacts that match the device's own public key
|
||||
void addOrUpdateContact(Contact contact, {Uint8List? devicePublicKey}) {
|
||||
// Don't add contacts that match our device's public key
|
||||
if (devicePublicKey != null && _publicKeysMatch(contact.publicKey, devicePublicKey)) {
|
||||
debugPrint('ℹ️ [ContactsProvider] Ignoring contact with device\'s own public key: ${contact.advName}');
|
||||
if (devicePublicKey != null &&
|
||||
_publicKeysMatch(contact.publicKey, devicePublicKey)) {
|
||||
debugPrint(
|
||||
'ℹ️ [ContactsProvider] Ignoring contact with device\'s own public key: ${contact.advName}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,8 +211,13 @@ class ContactsProvider with ChangeNotifier {
|
||||
// New contact - add initial location to history if available
|
||||
updatedContact = contact.copyWith(isNew: true);
|
||||
if (contact.advertLocation != null) {
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(contact.lastAdvert * 1000);
|
||||
updatedContact = updatedContact.addAdvertLocation(contact.advertLocation!, timestamp);
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||
contact.lastAdvert * 1000,
|
||||
);
|
||||
updatedContact = updatedContact.addAdvertLocation(
|
||||
contact.advertLocation!,
|
||||
timestamp,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Existing contact - preserve history and isNew status
|
||||
@@ -207,8 +231,13 @@ class ContactsProvider with ChangeNotifier {
|
||||
|
||||
// Add new location to history if location has changed
|
||||
if (contact.advertLocation != null) {
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(contact.lastAdvert * 1000);
|
||||
updatedContact = updatedContact.addAdvertLocation(contact.advertLocation!, timestamp);
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(
|
||||
contact.lastAdvert * 1000,
|
||||
);
|
||||
updatedContact = updatedContact.addAdvertLocation(
|
||||
contact.advertLocation!,
|
||||
timestamp,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,15 +261,20 @@ class ContactsProvider with ChangeNotifier {
|
||||
int excluded = 0;
|
||||
for (final contact in contacts) {
|
||||
// Don't add contacts that match our device's public key
|
||||
if (devicePublicKey != null && _publicKeysMatch(contact.publicKey, devicePublicKey)) {
|
||||
debugPrint('ℹ️ [ContactsProvider] Ignoring contact with device\'s own public key: ${contact.advName}');
|
||||
if (devicePublicKey != null &&
|
||||
_publicKeysMatch(contact.publicKey, devicePublicKey)) {
|
||||
debugPrint(
|
||||
'ℹ️ [ContactsProvider] Ignoring contact with device\'s own public key: ${contact.advName}',
|
||||
);
|
||||
excluded++;
|
||||
continue;
|
||||
}
|
||||
_contacts[contact.publicKeyHex] = contact;
|
||||
}
|
||||
if (excluded > 0) {
|
||||
debugPrint('ℹ️ [ContactsProvider] Excluded $excluded contact(s) matching device public key');
|
||||
debugPrint(
|
||||
'ℹ️ [ContactsProvider] Excluded $excluded contact(s) matching device public key',
|
||||
);
|
||||
}
|
||||
_persistContacts();
|
||||
notifyListeners();
|
||||
@@ -249,7 +283,9 @@ class ContactsProvider with ChangeNotifier {
|
||||
/// Update contact telemetry
|
||||
void updateTelemetry(Uint8List publicKeyPrefix, Uint8List lppData) {
|
||||
debugPrint('📊 [ContactsProvider] updateTelemetry() called');
|
||||
debugPrint(' Public key prefix (hex): ${publicKeyPrefix.map((b) => b.toRadixString(16).padLeft(2, '0')).join(':')}');
|
||||
debugPrint(
|
||||
' Public key prefix (hex): ${publicKeyPrefix.map((b) => b.toRadixString(16).padLeft(2, '0')).join(':')}',
|
||||
);
|
||||
debugPrint(' LPP data size: ${lppData.length} bytes');
|
||||
|
||||
// Find contact by public key prefix
|
||||
@@ -303,8 +339,9 @@ class ContactsProvider with ChangeNotifier {
|
||||
|
||||
/// Find contact by public key
|
||||
Contact? findContactByKey(Uint8List publicKey) {
|
||||
final keyHex =
|
||||
publicKey.map((b) => b.toRadixString(16).padLeft(2, '0')).join('');
|
||||
final keyHex = publicKey
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join('');
|
||||
return _contacts[keyHex];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@@ -7,11 +6,7 @@ import '../models/map_drawing.dart';
|
||||
import '../utils/drawing_message_parser.dart';
|
||||
|
||||
/// Drawing mode state
|
||||
enum DrawingMode {
|
||||
none,
|
||||
line,
|
||||
rectangle,
|
||||
}
|
||||
enum DrawingMode { none, line, rectangle }
|
||||
|
||||
/// Provider for managing map drawings
|
||||
class DrawingProvider with ChangeNotifier {
|
||||
@@ -123,7 +118,8 @@ class DrawingProvider with ChangeNotifier {
|
||||
|
||||
/// Update rectangle end point (for preview)
|
||||
void updateRectangleEndPoint(LatLng endPoint) {
|
||||
if (_drawingMode != DrawingMode.rectangle || _rectangleStartPoint == null) return;
|
||||
if (_drawingMode != DrawingMode.rectangle || _rectangleStartPoint == null)
|
||||
return;
|
||||
|
||||
// Create preview rectangle
|
||||
_currentDrawing = RectangleDrawing(
|
||||
@@ -270,7 +266,8 @@ class DrawingProvider with ChangeNotifier {
|
||||
createdAt: DateTime.now(),
|
||||
points: _currentLinePoints,
|
||||
);
|
||||
} else if (_drawingMode == DrawingMode.rectangle && _currentDrawing != null) {
|
||||
} else if (_drawingMode == DrawingMode.rectangle &&
|
||||
_currentDrawing != null) {
|
||||
return _currentDrawing;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../models/message.dart';
|
||||
import '../models/contact.dart';
|
||||
@@ -41,7 +40,8 @@ class MessagesProvider with ChangeNotifier {
|
||||
required String messageId,
|
||||
required Contact contact,
|
||||
int retryAttempt,
|
||||
})? sendMessageCallback;
|
||||
})?
|
||||
sendMessageCallback;
|
||||
|
||||
List<Message> get messages => List.unmodifiable(_messages);
|
||||
|
||||
@@ -93,10 +93,7 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
/// Get count of unread messages (excluding sent messages and system messages)
|
||||
int get unreadCount => _messages
|
||||
.where((m) =>
|
||||
!m.isRead &&
|
||||
!m.isSentMessage &&
|
||||
!m.isSystemMessage)
|
||||
.where((m) => !m.isRead && !m.isSentMessage && !m.isSystemMessage)
|
||||
.length;
|
||||
|
||||
/// Initialize and load persisted messages
|
||||
@@ -124,7 +121,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
debugPrint('✅ [MessagesProvider] Loaded ${storedMessages.length} persisted messages');
|
||||
debugPrint(
|
||||
'✅ [MessagesProvider] Loaded ${storedMessages.length} persisted messages',
|
||||
);
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('❌ [MessagesProvider] Error initializing: $e');
|
||||
@@ -135,7 +134,10 @@ class MessagesProvider with ChangeNotifier {
|
||||
/// Add a message
|
||||
/// If [contactLookup] function is provided, it will be used to match channel
|
||||
/// message senders with known contacts by name
|
||||
void addMessage(Message message, {String Function(String name)? contactLookup}) {
|
||||
void addMessage(
|
||||
Message message, {
|
||||
String Function(String name)? contactLookup,
|
||||
}) {
|
||||
// Always enhance message with SAR parser to detect SAR markers
|
||||
final enhancedMessage = SarMessageParser.enhanceMessage(message);
|
||||
|
||||
@@ -165,7 +167,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
// Debug: Check if message is SAR
|
||||
if (message.text.startsWith('S:')) {
|
||||
debugPrint('🔍 [MessagesProvider] Processing SAR message: ${message.text}');
|
||||
debugPrint(
|
||||
'🔍 [MessagesProvider] Processing SAR message: ${message.text}',
|
||||
);
|
||||
debugPrint(' isSarMarker: ${finalMessage.isSarMarker}');
|
||||
debugPrint(' sarMarkerType: ${finalMessage.sarMarkerType}');
|
||||
}
|
||||
@@ -176,8 +180,12 @@ class MessagesProvider with ChangeNotifier {
|
||||
// - Multiple paths in the network
|
||||
// - Syncing messages from device queue
|
||||
if (_isDuplicate(finalMessage)) {
|
||||
debugPrint('⚠️ [MessagesProvider] Duplicate message detected, skipping: ${finalMessage.id}');
|
||||
debugPrint(' Text: ${finalMessage.text.substring(0, finalMessage.text.length > 50 ? 50 : finalMessage.text.length)}...');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] Duplicate message detected, skipping: ${finalMessage.id}',
|
||||
);
|
||||
debugPrint(
|
||||
' Text: ${finalMessage.text.substring(0, finalMessage.text.length > 50 ? 50 : finalMessage.text.length)}...',
|
||||
);
|
||||
return; // Skip duplicate
|
||||
}
|
||||
|
||||
@@ -282,7 +290,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint('📥 [MessagesProvider] Added $addedCount messages, skipped $duplicateCount duplicates');
|
||||
debugPrint(
|
||||
'📥 [MessagesProvider] Added $addedCount messages, skipped $duplicateCount duplicates',
|
||||
);
|
||||
|
||||
// Persist to storage asynchronously
|
||||
_persistMessages();
|
||||
@@ -291,15 +301,22 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Trigger urgent notification for SAR marker
|
||||
Future<void> _triggerSarNotification(Message message, SarMarker marker) async {
|
||||
Future<void> _triggerSarNotification(
|
||||
Message message,
|
||||
SarMarker marker,
|
||||
) async {
|
||||
try {
|
||||
// Format coordinates
|
||||
final coords = '${marker.location.latitude.toStringAsFixed(5)}, ${marker.location.longitude.toStringAsFixed(5)}';
|
||||
final coords =
|
||||
'${marker.location.latitude.toStringAsFixed(5)}, ${marker.location.longitude.toStringAsFixed(5)}';
|
||||
|
||||
// Get sender name from message
|
||||
final senderName = message.senderName ?? message.senderKeyShort ?? 'Unknown';
|
||||
final senderName =
|
||||
message.senderName ?? message.senderKeyShort ?? 'Unknown';
|
||||
|
||||
debugPrint('🔔 [MessagesProvider] Triggering SAR notification for ${marker.type.displayName}');
|
||||
debugPrint(
|
||||
'🔔 [MessagesProvider] Triggering SAR notification for ${marker.type.displayName}',
|
||||
);
|
||||
debugPrint(' Sender: $senderName');
|
||||
debugPrint(' Coordinates: $coords');
|
||||
|
||||
@@ -319,7 +336,8 @@ class MessagesProvider with ChangeNotifier {
|
||||
Future<void> _triggerMessageNotification(Message message) async {
|
||||
try {
|
||||
// Get sender name from message
|
||||
final senderName = message.senderName ?? message.senderKeyShort ?? 'Unknown';
|
||||
final senderName =
|
||||
message.senderName ?? message.senderKeyShort ?? 'Unknown';
|
||||
|
||||
// Determine if it's a channel message
|
||||
final isChannelMessage = message.isChannelMessage;
|
||||
@@ -329,13 +347,17 @@ class MessagesProvider with ChangeNotifier {
|
||||
if (isChannelMessage) {
|
||||
// You could map channelIdx to channel name here if needed
|
||||
// For now, use "Public" for channel 0
|
||||
channelName = message.channelIdx == 0 ? 'Public' : 'Channel ${message.channelIdx}';
|
||||
channelName = message.channelIdx == 0
|
||||
? 'Public'
|
||||
: 'Channel ${message.channelIdx}';
|
||||
}
|
||||
|
||||
debugPrint('🔔 [MessagesProvider] Triggering message notification');
|
||||
debugPrint(' Sender: $senderName');
|
||||
debugPrint(' Type: ${isChannelMessage ? "Channel" : "Direct"}');
|
||||
debugPrint(' Message: ${message.text.substring(0, message.text.length > 50 ? 50 : message.text.length)}...');
|
||||
debugPrint(
|
||||
' Message: ${message.text.substring(0, message.text.length > 50 ? 50 : message.text.length)}...',
|
||||
);
|
||||
|
||||
await _notificationService.showMessageNotification(
|
||||
senderName: senderName,
|
||||
@@ -345,7 +367,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
localizations: _localizations,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('❌ [MessagesProvider] Error triggering message notification: $e');
|
||||
debugPrint(
|
||||
'❌ [MessagesProvider] Error triggering message notification: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,10 +385,12 @@ class MessagesProvider with ChangeNotifier {
|
||||
/// Get messages for a specific contact
|
||||
List<Message> getMessagesForContact(String senderKeyShort) {
|
||||
return _messages
|
||||
.where((m) =>
|
||||
m.isContactMessage &&
|
||||
m.senderKeyShort != null &&
|
||||
m.senderKeyShort!.startsWith(senderKeyShort))
|
||||
.where(
|
||||
(m) =>
|
||||
m.isContactMessage &&
|
||||
m.senderKeyShort != null &&
|
||||
m.senderKeyShort!.startsWith(senderKeyShort),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -417,7 +443,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
void markAllAsRead() {
|
||||
bool hasChanges = false;
|
||||
for (int i = 0; i < _messages.length; i++) {
|
||||
if (!_messages[i].isRead && !_messages[i].isSentMessage && !_messages[i].isSystemMessage) {
|
||||
if (!_messages[i].isRead &&
|
||||
!_messages[i].isSentMessage &&
|
||||
!_messages[i].isSystemMessage) {
|
||||
_messages[i] = _messages[i].copyWith(isRead: true);
|
||||
hasChanges = true;
|
||||
}
|
||||
@@ -552,14 +580,18 @@ class MessagesProvider with ChangeNotifier {
|
||||
debugPrint(' Message ID: ${message.id}');
|
||||
debugPrint(' Message type: ${message.messageType}');
|
||||
debugPrint(' Initial status: ${message.deliveryStatus}');
|
||||
debugPrint(' Message text preview: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...');
|
||||
debugPrint(
|
||||
' Message text preview: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...',
|
||||
);
|
||||
|
||||
// Always enhance message with SAR parser to detect SAR markers
|
||||
final enhancedMessage = SarMessageParser.enhanceMessage(message);
|
||||
|
||||
// Check for duplicates (shouldn't happen for sent messages, but be safe)
|
||||
if (_isDuplicate(enhancedMessage)) {
|
||||
debugPrint('⚠️ [MessagesProvider] Duplicate sent message detected, skipping: ${enhancedMessage.id}');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] Duplicate sent message detected, skipping: ${enhancedMessage.id}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -597,12 +629,20 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Update message status to sent with ACK tag
|
||||
void markMessageSent(String messageId, int expectedAckTag, int suggestedTimeoutMs) {
|
||||
void markMessageSent(
|
||||
String messageId,
|
||||
int expectedAckTag,
|
||||
int suggestedTimeoutMs,
|
||||
) {
|
||||
debugPrint('📤 [MessagesProvider] markMessageSent called');
|
||||
debugPrint(' Message ID: $messageId');
|
||||
debugPrint(' Expected ACK tag: $expectedAckTag (0x${expectedAckTag.toRadixString(16).padLeft(8, '0')})');
|
||||
debugPrint(
|
||||
' Expected ACK tag: $expectedAckTag (0x${expectedAckTag.toRadixString(16).padLeft(8, '0')})',
|
||||
);
|
||||
debugPrint(' Timeout: ${suggestedTimeoutMs}ms');
|
||||
debugPrint(' Current pending ACKs before adding: ${_pendingSentMessages.keys.toList()}');
|
||||
debugPrint(
|
||||
' Current pending ACKs before adding: ${_pendingSentMessages.keys.toList()}',
|
||||
);
|
||||
|
||||
final index = _messages.indexWhere((m) => m.id == messageId);
|
||||
debugPrint(' Message index in list: $index');
|
||||
@@ -611,7 +651,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
final message = _messages[index];
|
||||
debugPrint(' Current status: ${message.deliveryStatus}');
|
||||
debugPrint(' Message type: ${message.messageType}');
|
||||
debugPrint(' Message text preview: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...');
|
||||
debugPrint(
|
||||
' Message text preview: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...',
|
||||
);
|
||||
|
||||
final updatedMessage = message.copyWith(
|
||||
deliveryStatus: MessageDeliveryStatus.sent,
|
||||
@@ -624,24 +666,34 @@ class MessagesProvider with ChangeNotifier {
|
||||
if (expectedAckTag > 0 && suggestedTimeoutMs > 0) {
|
||||
// Track by ACK tag for matching with delivery confirmation
|
||||
_pendingSentMessages[expectedAckTag] = updatedMessage;
|
||||
debugPrint(' ✅ Added to pending messages map with ACK: $expectedAckTag');
|
||||
debugPrint(
|
||||
' ✅ Added to pending messages map with ACK: $expectedAckTag',
|
||||
);
|
||||
debugPrint(' Total pending messages: ${_pendingSentMessages.length}');
|
||||
debugPrint(' Pending ACKs after adding: ${_pendingSentMessages.keys.toList()}');
|
||||
debugPrint(
|
||||
' Pending ACKs after adding: ${_pendingSentMessages.keys.toList()}',
|
||||
);
|
||||
|
||||
// Start timeout timer
|
||||
_timeoutTimers[expectedAckTag] = Timer(
|
||||
Duration(milliseconds: suggestedTimeoutMs),
|
||||
() {
|
||||
debugPrint('⏱️ [MessagesProvider] Timeout for message $messageId (ACK $expectedAckTag)');
|
||||
debugPrint(
|
||||
'⏱️ [MessagesProvider] Timeout for message $messageId (ACK $expectedAckTag)',
|
||||
);
|
||||
if (_pendingSentMessages.containsKey(expectedAckTag)) {
|
||||
markMessageFailed(messageId);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
debugPrint('⏱️ [MessagesProvider] Started ${suggestedTimeoutMs}ms timeout timer for message $messageId (ACK $expectedAckTag)');
|
||||
debugPrint(
|
||||
'⏱️ [MessagesProvider] Started ${suggestedTimeoutMs}ms timeout timer for message $messageId (ACK $expectedAckTag)',
|
||||
);
|
||||
} else {
|
||||
debugPrint(' ℹ️ Channel message (no ACK tracking) - marked as sent immediately');
|
||||
debugPrint(
|
||||
' ℹ️ Channel message (no ACK tracking) - marked as sent immediately',
|
||||
);
|
||||
}
|
||||
|
||||
debugPrint(' Calling notifyListeners() to update UI with "sent" status');
|
||||
@@ -661,7 +713,12 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Handle echo detection for public channel messages
|
||||
void handleMessageEcho(String messageId, int echoCount, int snrRaw, int rssiDbm) {
|
||||
void handleMessageEcho(
|
||||
String messageId,
|
||||
int echoCount,
|
||||
int snrRaw,
|
||||
int rssiDbm,
|
||||
) {
|
||||
debugPrint('🔊 [MessagesProvider] handleMessageEcho called');
|
||||
debugPrint(' Message ID: $messageId');
|
||||
debugPrint(' Echo count: $echoCount');
|
||||
@@ -672,7 +729,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
final index = _messages.indexWhere((m) => m.id == messageId);
|
||||
if (index != -1) {
|
||||
final message = _messages[index];
|
||||
debugPrint(' ✅ Found message: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...');
|
||||
debugPrint(
|
||||
' ✅ Found message: ${message.text.substring(0, message.text.length > 30 ? 30 : message.text.length)}...',
|
||||
);
|
||||
|
||||
// Update echo count
|
||||
final updatedMessage = message.copyWith(
|
||||
@@ -692,8 +751,12 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
/// Update message status to delivered with RTT
|
||||
void markMessageDelivered(int ackCode, int roundTripTimeMs) {
|
||||
debugPrint('🔍 [MessagesProvider] markMessageDelivered called with ACK: $ackCode, RTT: ${roundTripTimeMs}ms');
|
||||
debugPrint(' Current pending messages: ${_pendingSentMessages.keys.toList()}');
|
||||
debugPrint(
|
||||
'🔍 [MessagesProvider] markMessageDelivered called with ACK: $ackCode, RTT: ${roundTripTimeMs}ms',
|
||||
);
|
||||
debugPrint(
|
||||
' Current pending messages: ${_pendingSentMessages.keys.toList()}',
|
||||
);
|
||||
debugPrint(' Total messages in list: ${_messages.length}');
|
||||
debugPrint(' Looking for ACK: $ackCode');
|
||||
|
||||
@@ -722,7 +785,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
// Clear retry tracking on successful delivery
|
||||
_retryManager.clearRetry(message.id);
|
||||
|
||||
debugPrint('✅ [MessagesProvider] Message ${message.id} delivered in ${roundTripTimeMs}ms (ACK $ackCode)');
|
||||
debugPrint(
|
||||
'✅ [MessagesProvider] Message ${message.id} delivered in ${roundTripTimeMs}ms (ACK $ackCode)',
|
||||
);
|
||||
debugPrint(' Updated status to: ${updatedMessage.deliveryStatus}');
|
||||
debugPrint(' Calling notifyListeners() to update UI');
|
||||
|
||||
@@ -731,33 +796,58 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
debugPrint(' ✅ notifyListeners() called successfully');
|
||||
} else {
|
||||
debugPrint('⚠️ [MessagesProvider] Message not found in messages list (index=-1)');
|
||||
debugPrint(' This should never happen - message was in pending map but not in messages list');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] Message not found in messages list (index=-1)',
|
||||
);
|
||||
debugPrint(
|
||||
' This should never happen - message was in pending map but not in messages list',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
debugPrint('⚠️ [MessagesProvider] No pending message found for ACK code: $ackCode');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] No pending message found for ACK code: $ackCode',
|
||||
);
|
||||
debugPrint(' Pending ACK codes: ${_pendingSentMessages.keys.toList()}');
|
||||
debugPrint(' This means either:');
|
||||
debugPrint(' 1. markMessageSent() was never called for this message (ACK tag not stored)');
|
||||
debugPrint(' 2. The ACK code from PUSH_CODE_SEND_CONFIRMED doesn\'t match the expected ACK tag from RESP_CODE_SENT');
|
||||
debugPrint(
|
||||
' 1. markMessageSent() was never called for this message (ACK tag not stored)',
|
||||
);
|
||||
debugPrint(
|
||||
' 2. The ACK code from PUSH_CODE_SEND_CONFIRMED doesn\'t match the expected ACK tag from RESP_CODE_SENT',
|
||||
);
|
||||
debugPrint(' 3. The message was already delivered or timed out');
|
||||
debugPrint(' Searching all messages for debugging...');
|
||||
|
||||
// Debug: Search for any message with this ACK tag
|
||||
final matchingMessages = _messages.where((m) => m.expectedAckTag == ackCode).toList();
|
||||
final matchingMessages = _messages
|
||||
.where((m) => m.expectedAckTag == ackCode)
|
||||
.toList();
|
||||
if (matchingMessages.isNotEmpty) {
|
||||
debugPrint(' ⚠️ Found ${matchingMessages.length} message(s) with matching ACK tag but NOT in pending map:');
|
||||
debugPrint(
|
||||
' ⚠️ Found ${matchingMessages.length} message(s) with matching ACK tag but NOT in pending map:',
|
||||
);
|
||||
for (final m in matchingMessages) {
|
||||
debugPrint(' - Message ID: ${m.id}, Status: ${m.deliveryStatus}, ACK: ${m.expectedAckTag}');
|
||||
debugPrint(
|
||||
' - Message ID: ${m.id}, Status: ${m.deliveryStatus}, ACK: ${m.expectedAckTag}',
|
||||
);
|
||||
}
|
||||
debugPrint(' This indicates the message was sent but never added to _pendingSentMessages map');
|
||||
debugPrint(' Likely cause: markMessageSent() was not called with correct message ID');
|
||||
debugPrint(
|
||||
' This indicates the message was sent but never added to _pendingSentMessages map',
|
||||
);
|
||||
debugPrint(
|
||||
' Likely cause: markMessageSent() was not called with correct message ID',
|
||||
);
|
||||
} else {
|
||||
debugPrint(' No messages found with ACK tag $ackCode');
|
||||
debugPrint(' Recent sent messages:');
|
||||
final sentMessages = _messages.where((m) => m.isSentMessage).take(5).toList();
|
||||
final sentMessages = _messages
|
||||
.where((m) => m.isSentMessage)
|
||||
.take(5)
|
||||
.toList();
|
||||
for (final m in sentMessages) {
|
||||
debugPrint(' - ID: ${m.id}, Status: ${m.deliveryStatus}, ACK: ${m.expectedAckTag}');
|
||||
debugPrint(
|
||||
' - ID: ${m.id}, Status: ${m.deliveryStatus}, ACK: ${m.expectedAckTag}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,7 +857,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
void markMessageFailed(String messageId) {
|
||||
final index = _messages.indexWhere((m) => m.id == messageId);
|
||||
if (index == -1) {
|
||||
debugPrint('⚠️ [MessagesProvider] markMessageFailed: Message not found: $messageId');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] markMessageFailed: Message not found: $messageId',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -783,7 +875,8 @@ class MessagesProvider with ChangeNotifier {
|
||||
if (contact != null && _retryManager.canRetry(message, contact)) {
|
||||
// RETRY: Contact has path and retry attempts < 3
|
||||
_scheduleRetry(messageId, message, contact);
|
||||
} else if (contact != null && _retryManager.shouldUseFloodFallback(message, contact)) {
|
||||
} else if (contact != null &&
|
||||
_retryManager.shouldUseFloodFallback(message, contact)) {
|
||||
// FLOOD FALLBACK: After 3 retries failed, try flood once
|
||||
_sendWithFloodMode(messageId, message, contact);
|
||||
} else {
|
||||
@@ -797,7 +890,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
final nextAttempt = message.retryAttempt + 1;
|
||||
final timeout = _retryManager.getTimeoutForAttempt(message.retryAttempt);
|
||||
|
||||
debugPrint('🔄 [MessagesProvider] Scheduling retry $nextAttempt/3 for message $messageId');
|
||||
debugPrint(
|
||||
'🔄 [MessagesProvider] Scheduling retry $nextAttempt/3 for message $messageId',
|
||||
);
|
||||
debugPrint(' Timeout: ${timeout}ms');
|
||||
|
||||
// Update message with new retry attempt
|
||||
@@ -823,7 +918,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
|
||||
// Schedule actual retry after delay
|
||||
Timer(Duration(milliseconds: timeout), () async {
|
||||
debugPrint('⏰ [MessagesProvider] Executing retry $nextAttempt for message $messageId');
|
||||
debugPrint(
|
||||
'⏰ [MessagesProvider] Executing retry $nextAttempt for message $messageId',
|
||||
);
|
||||
if (sendMessageCallback != null) {
|
||||
await sendMessageCallback!(
|
||||
contactPublicKey: contact.publicKey,
|
||||
@@ -833,7 +930,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
retryAttempt: nextAttempt,
|
||||
);
|
||||
} else {
|
||||
debugPrint('⚠️ [MessagesProvider] sendMessageCallback not set, cannot retry');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] sendMessageCallback not set, cannot retry',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -842,8 +941,14 @@ class MessagesProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
/// Send message with flood mode as last resort
|
||||
Future<void> _sendWithFloodMode(String messageId, Message message, Contact contact) async {
|
||||
debugPrint('🌊 [MessagesProvider] Trying flood mode for message $messageId');
|
||||
Future<void> _sendWithFloodMode(
|
||||
String messageId,
|
||||
Message message,
|
||||
Contact contact,
|
||||
) async {
|
||||
debugPrint(
|
||||
'🌊 [MessagesProvider] Trying flood mode for message $messageId',
|
||||
);
|
||||
|
||||
final index = _messages.indexWhere((m) => m.id == messageId);
|
||||
if (index != -1) {
|
||||
@@ -871,7 +976,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
retryAttempt: 0, // Reset attempt for flood
|
||||
);
|
||||
} else {
|
||||
debugPrint('⚠️ [MessagesProvider] sendMessageCallback not set, cannot send flood');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] sendMessageCallback not set, cannot send flood',
|
||||
);
|
||||
}
|
||||
|
||||
_persistMessages();
|
||||
@@ -907,7 +1014,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
Future<void> resendMessage(String messageId) async {
|
||||
final index = _messages.indexWhere((m) => m.id == messageId);
|
||||
if (index == -1) {
|
||||
debugPrint('⚠️ [MessagesProvider] resendMessage: Message not found: $messageId');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] resendMessage: Message not found: $messageId',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -915,7 +1024,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
final contact = _messageContactMap[messageId];
|
||||
|
||||
if (contact == null) {
|
||||
debugPrint('⚠️ [MessagesProvider] Cannot resend: Contact not found for message $messageId');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] Cannot resend: Contact not found for message $messageId',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -944,7 +1055,9 @@ class MessagesProvider with ChangeNotifier {
|
||||
retryAttempt: 0,
|
||||
);
|
||||
} else {
|
||||
debugPrint('⚠️ [MessagesProvider] sendMessageCallback not set, cannot resend');
|
||||
debugPrint(
|
||||
'⚠️ [MessagesProvider] sendMessageCallback not set, cannot resend',
|
||||
);
|
||||
}
|
||||
|
||||
_persistMessages();
|
||||
|
||||
Reference in New Issue
Block a user