mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 08:20:36 +00:00
Throttle message notifications during sync
This commit is contained in:
@@ -2567,8 +2567,11 @@ class AppProvider with ChangeNotifier {
|
||||
debugPrint(
|
||||
'🔄 [AppProvider] Performing initial message sync (fallback for missed pushes)',
|
||||
);
|
||||
final initialMessageCount = await connectionProvider.syncAllMessages(
|
||||
force: true,
|
||||
final initialMessageCount =
|
||||
await messagesProvider.withReceivedNotificationsSuppressed(
|
||||
() => connectionProvider.syncAllMessages(
|
||||
force: true,
|
||||
),
|
||||
);
|
||||
debugPrint(
|
||||
'📥 [AppProvider] Initial sync retrieved $initialMessageCount message(s)',
|
||||
@@ -2627,8 +2630,11 @@ class AppProvider with ChangeNotifier {
|
||||
);
|
||||
await refreshChannelLocationSharingState();
|
||||
|
||||
final messageCount = await connectionProvider.syncAllMessages(
|
||||
force: true,
|
||||
final messageCount =
|
||||
await messagesProvider.withReceivedNotificationsSuppressed(
|
||||
() => connectionProvider.syncAllMessages(
|
||||
force: true,
|
||||
),
|
||||
);
|
||||
debugPrint(
|
||||
'📥 [AppProvider] Reconnect sync retrieved $messageCount message(s)',
|
||||
|
||||
@@ -36,6 +36,7 @@ class MessagesProvider with ChangeNotifier {
|
||||
bool _isInitialized = false;
|
||||
bool _isPersisting = false;
|
||||
bool _persistRequested = false;
|
||||
bool _suppressReceivedNotifications = false;
|
||||
AppLocalizations? _localizations;
|
||||
final Map<String, MessageContactLocation> _messageContactLocations = {};
|
||||
final Map<String, MessageReceptionDetails> _messageReceptionDetails = {};
|
||||
@@ -850,11 +851,13 @@ class MessagesProvider with ChangeNotifier {
|
||||
_sarMarkers[marker.id] = marker;
|
||||
|
||||
// Trigger urgent notification for received SAR messages (not sent by user)
|
||||
if (!finalMessage.isSentMessage) {
|
||||
if (!finalMessage.isSentMessage && !_suppressReceivedNotifications) {
|
||||
_triggerSarNotification(finalMessage, marker);
|
||||
}
|
||||
}
|
||||
} else if (!finalMessage.isSentMessage && !finalMessage.isSystemMessage) {
|
||||
} else if (!finalMessage.isSentMessage &&
|
||||
!finalMessage.isSystemMessage &&
|
||||
!_suppressReceivedNotifications) {
|
||||
// Trigger notification for regular messages (not SAR, not sent by user, not system)
|
||||
_triggerMessageNotification(finalMessage);
|
||||
}
|
||||
@@ -865,6 +868,18 @@ class MessagesProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<T> withReceivedNotificationsSuppressed<T>(
|
||||
Future<T> Function() action,
|
||||
) async {
|
||||
final previous = _suppressReceivedNotifications;
|
||||
_suppressReceivedNotifications = true;
|
||||
try {
|
||||
return await action();
|
||||
} finally {
|
||||
_suppressReceivedNotifications = previous;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a message is a duplicate
|
||||
///
|
||||
/// Messages are considered duplicates if they have:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@@ -29,6 +31,13 @@ class NotificationService {
|
||||
bool _muteForegroundNotifications = true;
|
||||
AppLifecycleState _lifecycleState = AppLifecycleState.resumed;
|
||||
String? _launchPayload;
|
||||
Timer? _messageNotificationTimer;
|
||||
int _pendingMessageNotificationCount = 0;
|
||||
String? _pendingMessageSenderName;
|
||||
String? _pendingMessageText;
|
||||
bool _pendingMessageIsChannel = false;
|
||||
String? _pendingMessageChannelName;
|
||||
AppLocalizations? _pendingMessageLocalizations;
|
||||
|
||||
// Notification IDs
|
||||
static const int _sarNotificationId = 1000;
|
||||
@@ -36,6 +45,8 @@ class NotificationService {
|
||||
static const int _updateNotificationId = 3000;
|
||||
static const int _batteryNotificationId = 4000;
|
||||
static const int _discoveryNotificationId = 5000;
|
||||
static const Duration _messageNotificationCoalesceWindow =
|
||||
Duration(seconds: 2);
|
||||
|
||||
// Notification channels
|
||||
static const String _urgentChannelId = 'sar_urgent';
|
||||
@@ -533,17 +544,53 @@ class NotificationService {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Generate unique notification ID based on timestamp
|
||||
final notificationId =
|
||||
_messageNotificationId +
|
||||
(DateTime.now().millisecondsSinceEpoch % 1000);
|
||||
_pendingMessageNotificationCount++;
|
||||
_pendingMessageSenderName = senderName;
|
||||
_pendingMessageText = messageText;
|
||||
_pendingMessageIsChannel = isChannelMessage;
|
||||
_pendingMessageChannelName = channelName;
|
||||
_pendingMessageLocalizations = localizations;
|
||||
|
||||
_messageNotificationTimer?.cancel();
|
||||
_messageNotificationTimer = Timer(_messageNotificationCoalesceWindow, () {
|
||||
unawaited(_flushMessageNotification());
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _flushMessageNotification() async {
|
||||
final count = _pendingMessageNotificationCount;
|
||||
final senderName = _pendingMessageSenderName;
|
||||
final messageText = _pendingMessageText;
|
||||
final isChannelMessage = _pendingMessageIsChannel;
|
||||
final channelName = _pendingMessageChannelName;
|
||||
final localizations = _pendingMessageLocalizations;
|
||||
|
||||
_pendingMessageNotificationCount = 0;
|
||||
_pendingMessageSenderName = null;
|
||||
_pendingMessageText = null;
|
||||
_pendingMessageIsChannel = false;
|
||||
_pendingMessageChannelName = null;
|
||||
_pendingMessageLocalizations = null;
|
||||
|
||||
if (count == 0 || senderName == null || messageText == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isInitialized ||
|
||||
!_permissionGranted ||
|
||||
!_messageNotificationsEnabled ||
|
||||
_shouldSuppressForegroundNotifications()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Build notification title and body
|
||||
final resolvedChannelName = channelName?.trim().isNotEmpty == true
|
||||
? channelName!.trim()
|
||||
: (localizations?.publicChannel ?? 'Public');
|
||||
final title = isChannelMessage
|
||||
final title = count > 1
|
||||
? (localizations?.messages ?? 'Messages')
|
||||
: isChannelMessage
|
||||
? (localizations != null
|
||||
? '${localizations.channel}: $resolvedChannelName'
|
||||
: 'Channel: $resolvedChannelName')
|
||||
@@ -551,7 +598,9 @@ class NotificationService {
|
||||
? '${localizations.newMessage} ${localizations.from} $senderName'
|
||||
: 'New message from $senderName');
|
||||
|
||||
final body = messageText.length > 200
|
||||
final body = count > 1
|
||||
? 'You have $count new messages'
|
||||
: messageText.length > 200
|
||||
? '${messageText.substring(0, 200)}...'
|
||||
: messageText;
|
||||
|
||||
@@ -570,7 +619,7 @@ class NotificationService {
|
||||
styleInformation: BigTextStyleInformation(
|
||||
body,
|
||||
contentTitle: title,
|
||||
summaryText: senderName,
|
||||
summaryText: count > 1 ? body : senderName,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -594,7 +643,7 @@ class NotificationService {
|
||||
|
||||
// Show notification
|
||||
await _notificationsPlugin.show(
|
||||
id: notificationId,
|
||||
id: _messageNotificationId,
|
||||
title: title,
|
||||
body: body,
|
||||
notificationDetails: notificationDetails,
|
||||
@@ -602,6 +651,7 @@ class NotificationService {
|
||||
);
|
||||
|
||||
debugPrint('✅ [NotificationService] Showed message notification');
|
||||
debugPrint(' Count: $count');
|
||||
debugPrint(' Sender: $senderName');
|
||||
debugPrint(' Type: ${isChannelMessage ? "Channel" : "Direct"}');
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user