mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
Remove 100ms BLE command delay
This commit is contained in:
@@ -406,6 +406,9 @@ class _ImageMessageBubbleState extends State<ImageMessageBubble> {
|
||||
|
||||
final payload = request.encodeBinary();
|
||||
try {
|
||||
debugPrint(
|
||||
'📷 [ImageMessageBubble] Outgoing image fetch request: session=${envelope.sessionId} want=${isPartialResume ? 'missing' : 'all'} target=${sender.advName} hops=${sender.outPathLen}',
|
||||
);
|
||||
await conn.sendRawVoicePacket(
|
||||
contactPath: sender.outPath,
|
||||
contactPathLen: sender.outPathLen,
|
||||
|
||||
@@ -22,6 +22,7 @@ import '../../utils/sar_message_parser.dart';
|
||||
import '../../utils/key_comparison.dart';
|
||||
import '../../utils/voice_message_parser.dart';
|
||||
import '../../utils/image_message_parser.dart';
|
||||
import '../../utils/message_airtime_estimator.dart';
|
||||
import '../../utils/tictactoe_message_parser.dart';
|
||||
import '../../utils/location_formats.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
@@ -2465,74 +2466,114 @@ class _MessageBubbleState extends State<MessageBubble> {
|
||||
// Show single message delivery status
|
||||
else if (!message.isChannelMessage ||
|
||||
message.deliveryStatus == MessageDeliveryStatus.failed)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Icon(
|
||||
getDeliveryStatusIcon(message.deliveryStatus),
|
||||
size: 12,
|
||||
color: getDeliveryStatusColor(message.deliveryStatus),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
message.getLocalizedDeliveryStatus(context),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.labelSmall
|
||||
?.copyWith(
|
||||
color: getDeliveryStatusColor(
|
||||
message.deliveryStatus,
|
||||
),
|
||||
fontStyle: FontStyle.italic,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final txEstimate = estimateMessageTransmitDuration(
|
||||
message,
|
||||
radioBw: connectionProvider.deviceInfo.radioBw,
|
||||
radioSf: connectionProvider.deviceInfo.radioSf,
|
||||
radioCr: connectionProvider.deviceInfo.radioCr,
|
||||
);
|
||||
final showSentDirectStats =
|
||||
message.isContactMessage &&
|
||||
message.deliveryStatus ==
|
||||
MessageDeliveryStatus.delivered &&
|
||||
_showReceivedStats &&
|
||||
message.roundTripTimeMs != null;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Icon(
|
||||
getDeliveryStatusIcon(message.deliveryStatus),
|
||||
size: 12,
|
||||
color: getDeliveryStatusColor(
|
||||
message.deliveryStatus,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Show retry button for failed messages
|
||||
if (message.deliveryStatus ==
|
||||
MessageDeliveryStatus.failed) ...[
|
||||
const SizedBox(width: 6),
|
||||
GestureDetector(
|
||||
onTap: () => _retryFailedMessage(context, message),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.orange.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(
|
||||
color: Colors.orange,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.refresh,
|
||||
size: 12,
|
||||
color: Colors.orange,
|
||||
const SizedBox(width: 3),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
message.getLocalizedDeliveryStatus(context),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall
|
||||
?.copyWith(
|
||||
color: getDeliveryStatusColor(
|
||||
message.deliveryStatus,
|
||||
),
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Retry',
|
||||
style: Theme.of(context).textTheme.labelSmall
|
||||
?.copyWith(
|
||||
color: Colors.orange,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
// Show retry button for failed messages
|
||||
if (message.deliveryStatus ==
|
||||
MessageDeliveryStatus.failed) ...[
|
||||
const SizedBox(width: 6),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
_retryFailedMessage(context, message),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.orange.withValues(
|
||||
alpha: 0.2,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
border: Border.all(
|
||||
color: Colors.orange,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.refresh,
|
||||
size: 12,
|
||||
color: Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'Retry',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall
|
||||
?.copyWith(
|
||||
color: Colors.orange,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
if (showSentDirectStats) ...[
|
||||
const SizedBox(height: 6),
|
||||
buildSentDirectSignalStatus(
|
||||
context,
|
||||
message,
|
||||
roundTripTimeMs: message.roundTripTimeMs!,
|
||||
txEstimate: txEstimate,
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
if (shouldShowSentChannelStats(
|
||||
message,
|
||||
|
||||
@@ -179,6 +179,85 @@ Widget buildReceivedSignalStatus(
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSentDirectSignalStatus(
|
||||
BuildContext context,
|
||||
Message message, {
|
||||
required int roundTripTimeMs,
|
||||
required Duration txEstimate,
|
||||
}) {
|
||||
final estimatedTransmitMs = sanitizeEstimatedTransmitMs(
|
||||
estimatedTransmitMs: txEstimate > Duration.zero
|
||||
? txEstimate.inMilliseconds
|
||||
: null,
|
||||
senderToReceiptMs: roundTripTimeMs,
|
||||
);
|
||||
final postTransmitDelayMs = estimatedTransmitMs != null
|
||||
? (roundTripTimeMs - estimatedTransmitMs).clamp(0, 86400000).toInt()
|
||||
: null;
|
||||
|
||||
return Wrap(
|
||||
spacing: 4,
|
||||
runSpacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.alt_route,
|
||||
label: hopDisplayLabel(message),
|
||||
color: Colors.indigo,
|
||||
),
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.schedule,
|
||||
label: _formatMs(roundTripTimeMs),
|
||||
color: Colors.deepPurple,
|
||||
),
|
||||
if (estimatedTransmitMs != null)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.timelapse,
|
||||
label: '~${_formatMs(estimatedTransmitMs)} tx',
|
||||
color: Colors.blue,
|
||||
),
|
||||
if (postTransmitDelayMs != null)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.hourglass_bottom,
|
||||
label: '+${_formatMs(postTransmitDelayMs)} lag',
|
||||
color: Colors.orange,
|
||||
),
|
||||
if (message.retryAttempt > 0)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.refresh,
|
||||
label: 'retry ${message.retryAttempt}/3',
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
if (message.suggestedTimeoutMs != null)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.timer_outlined,
|
||||
label: 'timeout ${_formatMs(message.suggestedTimeoutMs!)}',
|
||||
color: Colors.blueGrey,
|
||||
),
|
||||
if (message.usedFloodFallback)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.waves,
|
||||
label: 'flood fallback',
|
||||
color: Colors.teal,
|
||||
)
|
||||
else if (message.expectedAckTag != null)
|
||||
_techChip(
|
||||
context,
|
||||
icon: Icons.route,
|
||||
label: 'direct ACK',
|
||||
color: Colors.indigo,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _formatMs(int value) {
|
||||
if (value >= 60000) {
|
||||
final minutes = value ~/ 60000;
|
||||
|
||||
@@ -374,6 +374,9 @@ class _VoiceMessageBubbleState extends State<VoiceMessageBubble> {
|
||||
);
|
||||
|
||||
try {
|
||||
debugPrint(
|
||||
'🎙️ [VoiceMessageBubble] Outgoing voice fetch request: session=$sessionId want=${isPartialResume ? 'missing' : 'all'} target=${sender.advName} hops=${sender.outPathLen}',
|
||||
);
|
||||
await connectionProvider.sendRawVoicePacket(
|
||||
contactPath: sender.outPath,
|
||||
contactPathLen: sender.outPathLen,
|
||||
|
||||
Reference in New Issue
Block a user