Update log display handling

This commit is contained in:
Janez T
2026-03-14 10:01:17 +01:00
parent e7a481f97b
commit 06632ee32d
6 changed files with 110 additions and 32 deletions

View File

@@ -5,24 +5,22 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.001473">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000235">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.569758">
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.385323">
</testcase>
<testcase classname="fastlane.lanes" name="2: build_app" time="95.271262">
<testcase classname="fastlane.lanes" name="2: build_app" time="93.530304">
</testcase>
<testcase classname="fastlane.lanes" name="3: upload_to_app_store" time="91.795184">
<failure message="/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/actions/actions_helper.rb:67:in &apos;Fastlane::Actions.execute_action&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:255:in &apos;block in Fastlane::Runner#execute_action&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:229:in &apos;Dir.chdir&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:229:in &apos;Fastlane::Runner#execute_action&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:157:in &apos;Fastlane::Runner#trigger_action_by_name&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/fast_file.rb:159:in &apos;Fastlane::FastFile#method_missing&apos;&#10;Fastfile:23:in &apos;block (2 levels) in Fastlane::FastFile#parsing_binding&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/lane.rb:41:in &apos;Fastlane::Lane#call&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:49:in &apos;block in Fastlane::Runner#execute&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:45:in &apos;Dir.chdir&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/runner.rb:45:in &apos;Fastlane::Runner#execute&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/lane_manager.rb:46:in &apos;Fastlane::LaneManager.cruise_lane&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/command_line_handler.rb:34:in &apos;Fastlane::CommandLineHandler.handle&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/commands_generator.rb:110:in &apos;block (2 levels) in Fastlane::CommandsGenerator#run&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/commander-4.6.0/lib/commander/command.rb:187:in &apos;Commander::Command#call&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/commander-4.6.0/lib/commander/command.rb:157:in &apos;Commander::Command#run&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/commander-4.6.0/lib/commander/runner.rb:444:in &apos;Commander::Runner#run_active_command&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb:124:in &apos;Commander::Runner#run!&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/commander-4.6.0/lib/commander/delegates.rb:18:in &apos;Commander::Delegates#run!&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/commands_generator.rb:363:in &apos;Fastlane::CommandsGenerator#run&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/commands_generator.rb:43:in &apos;Fastlane::CommandsGenerator.start&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/fastlane/lib/fastlane/cli_tools_distributor.rb:132:in &apos;Fastlane::CLIToolsDistributor.take_off&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/gems/fastlane-2.231.1/bin/fastlane:23:in &apos;&lt;top (required)&gt;&apos;&#10;/opt/homebrew/Cellar/ruby/4.0.1/lib/ruby/4.0.0/rubygems.rb:303:in &apos;Kernel#load&apos;&#10;/opt/homebrew/Cellar/ruby/4.0.1/lib/ruby/4.0.0/rubygems.rb:303:in &apos;Gem.activate_and_load_bin_path&apos;&#10;/opt/homebrew/Cellar/fastlane/2.231.1/libexec/bin/fastlane:25:in &apos;&lt;main&gt;&apos;&#10;&#10;Invalid username and password combination. Used &apos;hey@dz0n.dev&apos; as the username." />
<testcase classname="fastlane.lanes" name="3: upload_to_app_store" time="210.562484">
</testcase>

View File

@@ -549,6 +549,15 @@ class MessagesProvider with ChangeNotifier {
}
}
final incomingPathBytes = receptionDetailsSnapshot?.pathBytes;
if (incomingPathBytes != null &&
incomingPathBytes.isNotEmpty &&
finalMessage.pathBytes == null) {
finalMessage = finalMessage.copyWith(
pathBytes: Uint8List.fromList(incomingPathBytes),
);
}
// Debug: Check if message is SAR
if (message.text.startsWith('S:')) {
debugPrint(
@@ -582,6 +591,15 @@ class MessagesProvider with ChangeNotifier {
}
if (receptionDetailsSnapshot != null) {
_messageReceptionDetails[existingId] = receptionDetailsSnapshot;
final existingMessage = _messages[duplicateIndex];
final duplicatePathBytes = receptionDetailsSnapshot.pathBytes;
if (existingMessage.pathBytes == null &&
duplicatePathBytes != null &&
duplicatePathBytes.isNotEmpty) {
_messages[duplicateIndex] = existingMessage.copyWith(
pathBytes: Uint8List.fromList(duplicatePathBytes),
);
}
}
_persistMessages();
return; // Skip duplicate
@@ -692,7 +710,7 @@ class MessagesProvider with ChangeNotifier {
incomingSenderName != null &&
existingSenderName == incomingSenderName) {
if (!existing.isSentMessage && !message.isSentMessage) {
return true;
return withinChannelRepeatWindow;
}
if (!withinChannelRepeatWindow) {
@@ -715,7 +733,8 @@ class MessagesProvider with ChangeNotifier {
return false;
}
return true;
// System messages and other types: never deduplicate by scope alone.
return false;
}
/// Add multiple messages
@@ -725,7 +744,33 @@ class MessagesProvider with ChangeNotifier {
for (final message in messages) {
// Always enhance message with SAR parser to detect SAR markers
final enhancedMessage = SarMessageParser.enhanceMessage(message);
var enhancedMessage = SarMessageParser.enhanceMessage(message);
// Check if it's a drawing message (D:...) and not already marked
if (DrawingMessageParser.isDrawingMessage(enhancedMessage.text) &&
!enhancedMessage.isDrawing) {
final drawing = DrawingMessageParser.parseDrawingMessage(
enhancedMessage.text,
senderName: enhancedMessage.senderName,
messageId: enhancedMessage.id,
);
enhancedMessage = enhancedMessage.copyWith(
isDrawing: true,
drawingId: drawing?.id,
);
}
// Check if it's a voice message and not already marked
if (!enhancedMessage.isVoice) {
final envelope = VoiceEnvelope.tryParseText(enhancedMessage.text);
if (envelope != null) {
enhancedMessage = enhancedMessage.copyWith(
isVoice: true,
voiceId: envelope.sessionId,
);
}
}
enhancedMessage = _resolveSenderNameIfNeeded(enhancedMessage);
// Check for duplicates
if (_findDuplicateMessageIndex(enhancedMessage) != -1) {
@@ -1028,6 +1073,7 @@ class MessagesProvider with ChangeNotifier {
for (final messageId in messageIdsToRemove) {
_timeoutTimers[messageId]?.cancel();
_timeoutTimers.remove(messageId);
_clearChannelSendWarning(messageId);
_messageContactMap.remove(messageId);
_groupedMessageMapping.remove(messageId);
_messageContactLocations.remove(messageId);
@@ -1245,11 +1291,7 @@ class MessagesProvider with ChangeNotifier {
/// Clear all messages
void clearMessages() {
for (final timer in _channelEchoWarningTimers.values) {
timer.cancel();
}
_channelEchoWarningTimers.clear();
_channelEchoWarningMessageIds.clear();
_cancelAllTimers();
_messages.clear();
_sarMarkers.clear();
_removedSarMarkerIds.clear();
@@ -1257,6 +1299,14 @@ class MessagesProvider with ChangeNotifier {
_messageReceptionDetails.clear();
_messageTransferDetails.clear();
_messageRouteMetadata.clear();
_pendingSentMessages.clear();
_messageContactMap.clear();
_groupedMessageMapping.clear();
_ackTagToRecipients.clear();
_messageAckHistory.clear();
_ackHistoryLookup.clear();
_completedAckHistory.clear();
_retryManager.clearAll();
_persistMessages();
unawaited(_storageService.saveRemovedSarMarkerIds(_removedSarMarkerIds));
notifyListeners();
@@ -1272,11 +1322,7 @@ class MessagesProvider with ChangeNotifier {
/// Clear all data
void clearAll() {
for (final timer in _channelEchoWarningTimers.values) {
timer.cancel();
}
_channelEchoWarningTimers.clear();
_channelEchoWarningMessageIds.clear();
_cancelAllTimers();
_messages.clear();
_sarMarkers.clear();
_removedSarMarkerIds.clear();
@@ -1284,6 +1330,14 @@ class MessagesProvider with ChangeNotifier {
_messageReceptionDetails.clear();
_messageTransferDetails.clear();
_messageRouteMetadata.clear();
_pendingSentMessages.clear();
_messageContactMap.clear();
_groupedMessageMapping.clear();
_ackTagToRecipients.clear();
_messageAckHistory.clear();
_ackHistoryLookup.clear();
_completedAckHistory.clear();
_retryManager.clearAll();
_persistMessages();
unawaited(_storageService.saveRemovedSarMarkerIds(_removedSarMarkerIds));
notifyListeners();
@@ -1964,7 +2018,7 @@ class MessagesProvider with ChangeNotifier {
debugPrint(' Message index in list: $index');
if (index != -1) {
final updatedMessage = message.copyWith(
final updatedMessage = _messages[index].copyWith(
deliveryStatus: MessageDeliveryStatus.delivered,
roundTripTimeMs: roundTripTimeMs,
deliveredAt: DateTime.now(),
@@ -2323,6 +2377,7 @@ class MessagesProvider with ChangeNotifier {
senderPublicKeyPrefix: message.senderPublicKeyPrefix,
channelIdx: message.channelIdx,
pathLen: message.pathLen,
pathBytes: message.pathBytes,
textType: message.textType,
senderTimestamp: message.senderTimestamp,
text: message.text,
@@ -2410,7 +2465,19 @@ class MessagesProvider with ChangeNotifier {
@override
void dispose() {
// Cancel all pending timeout timers
_cancelAllTimers();
_completedAckHistory.clear();
_messageAckHistory.clear();
_ackHistoryLookup.clear();
// Clear retry manager
_retryManager.clearAll();
super.dispose();
}
/// Cancel all pending timers (timeout + echo warning).
void _cancelAllTimers() {
for (final timer in _timeoutTimers.values) {
timer.cancel();
}
@@ -2420,14 +2487,6 @@ class MessagesProvider with ChangeNotifier {
}
_channelEchoWarningTimers.clear();
_channelEchoWarningMessageIds.clear();
_completedAckHistory.clear();
_messageAckHistory.clear();
_ackHistoryLookup.clear();
// Clear retry manager
_retryManager.clearAll();
super.dispose();
}
void _rememberCompletedAck(int ackCode) {

View File

@@ -329,6 +329,8 @@ class MessageStorageService {
Message message, {
MessageReceptionDetails? receptionDetails,
}) {
final persistedPathBytes =
message.pathBytes ?? _pathBytesFromSnapshot(receptionDetails);
return {
'id': message.id,
'messageType': message.messageType.name,
@@ -337,6 +339,7 @@ class MessageStorageService {
: null,
'channelIdx': message.channelIdx,
'pathLen': message.pathLen,
'pathBytes': persistedPathBytes?.toList(),
'textType': message.textType.value,
'senderTimestamp': message.senderTimestamp,
'text': message.text,
@@ -465,6 +468,14 @@ class MessageStorageService {
: null,
channelIdx: json['channelIdx'] as int?,
pathLen: json['pathLen'] as int,
pathBytes: json['pathBytes'] is List
? Uint8List.fromList(
(json['pathBytes'] as List<dynamic>)
.whereType<num>()
.map((b) => b.toInt())
.toList(),
)
: null,
textType: MessageTextType.fromValue(json['textType'] as int),
senderTimestamp: json['senderTimestamp'] as int,
text: json['text'] as String,
@@ -562,4 +573,12 @@ class MessageStorageService {
return null;
}
}
Uint8List? _pathBytesFromSnapshot(MessageReceptionDetails? receptionDetails) {
final pathBytes = receptionDetails?.pathBytes;
if (pathBytes == null || pathBytes.isEmpty) {
return null;
}
return Uint8List.fromList(pathBytes);
}
}

View File

@@ -795,8 +795,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "461f010"
resolved-ref: "461f010a2f1fcd343357c152228891e295d391be"
ref: "27e65f4"
resolved-ref: "27e65f48b1b5dc3dbcafc0167c4c5755770116ba"
url: "https://github.com/dz0ny/meshcore_client.git"
source: git
version: "0.1.0"

View File

@@ -44,7 +44,7 @@ dependencies:
meshcore_client:
git:
url: https://github.com/dz0ny/meshcore_client.git
ref: "461f010"
ref: "27e65f4"
# Codec2 ultra-low-bitrate speech codec (FFI plugin)
codec2_flutter:

View File

@@ -43,9 +43,11 @@ void main() {
await prefs.remove('stored_message_reception_details');
final restoredDetails = await storage.loadMessageReceptionDetails();
final restoredMessages = await storage.loadMessages();
expect(restoredDetails.keys, contains(message.id));
expect(restoredDetails[message.id]?.pathBytes, [0xAA, 0xBB, 0xCC]);
expect(restoredMessages.single.pathBytes, [0xAA, 0xBB, 0xCC]);
},
);