feat: update app icons and refactor home top professionals section to display dynamic agent profiles.
This commit is contained in:
@@ -97,7 +97,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
||||
final currentMessages =
|
||||
List<ChatMessage>.from(state.messages[convId] ?? []);
|
||||
|
||||
// Avoid duplicates
|
||||
// Avoid duplicates (broadcast may arrive after ack for sender's own message)
|
||||
if (currentMessages.any((m) => m.id == message.id)) return;
|
||||
|
||||
currentMessages.insert(0, message);
|
||||
@@ -105,12 +105,22 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
||||
Map<String, List<ChatMessage>>.from(state.messages)
|
||||
..[convId] = currentMessages;
|
||||
|
||||
// Show friendly preview for non-text messages (matching web)
|
||||
String previewText = message.content;
|
||||
if (message.messageType == MessageType.image) {
|
||||
previewText = 'Sent an image';
|
||||
} else if (message.messageType == MessageType.file) {
|
||||
previewText = 'Sent a file';
|
||||
} else if (_isGifUrl(message.content)) {
|
||||
previewText = 'GIF';
|
||||
}
|
||||
|
||||
// Update conversation's last message and unread count
|
||||
final updatedConversations = state.conversations.map((c) {
|
||||
if (c.id == convId) {
|
||||
final isActive = state.activeConversationId == convId;
|
||||
return c.copyWith(
|
||||
lastMessageText: message.content,
|
||||
lastMessageText: previewText,
|
||||
lastMessageAt: message.createdAt,
|
||||
unreadCount: isActive ? c.unreadCount : c.unreadCount + 1,
|
||||
);
|
||||
@@ -155,6 +165,59 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
||||
}).toList();
|
||||
state = state.copyWith(conversations: updatedConversations);
|
||||
}));
|
||||
|
||||
// Reconnection: re-join active conversation room and catch up missed messages
|
||||
_subscriptions.add(_socket.onConnectionChange.listen((connected) {
|
||||
if (!mounted || !connected) return;
|
||||
final activeConvId = state.activeConversationId;
|
||||
if (activeConvId != null) {
|
||||
_rejoinAndCatchUp(activeConvId);
|
||||
}
|
||||
// Refresh conversation list to catch any missed updates
|
||||
loadConversations();
|
||||
}));
|
||||
}
|
||||
|
||||
/// Re-join socket room and fetch missed messages after reconnection (matching web)
|
||||
Future<void> _rejoinAndCatchUp(String conversationId, {int attempt = 1}) async {
|
||||
try {
|
||||
await _socket.joinConversation(conversationId);
|
||||
} catch (_) {
|
||||
if (attempt < 3 && mounted && state.activeConversationId == conversationId) {
|
||||
await Future.delayed(Duration(seconds: attempt));
|
||||
return _rejoinAndCatchUp(conversationId, attempt: attempt + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch recent messages to catch any missed during disconnect
|
||||
if (!mounted || state.activeConversationId != conversationId) return;
|
||||
try {
|
||||
final result = await _repository.getMessages(conversationId, page: 1);
|
||||
final recentMessages = result.messages.reversed.toList();
|
||||
final currentMessages = List<ChatMessage>.from(state.messages[conversationId] ?? []);
|
||||
final existingIds = currentMessages.map((m) => m.id).toSet();
|
||||
final newMessages = recentMessages.where((m) => !existingIds.contains(m.id)).toList();
|
||||
|
||||
if (newMessages.isNotEmpty && mounted) {
|
||||
currentMessages.insertAll(0, newMessages);
|
||||
// Sort newest first
|
||||
currentMessages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||
final updatedMessages = Map<String, List<ChatMessage>>.from(state.messages)
|
||||
..[conversationId] = currentMessages;
|
||||
state = state.copyWith(messages: updatedMessages);
|
||||
}
|
||||
} catch (e) {
|
||||
_log.e('Failed to catch up messages after reconnect', error: e);
|
||||
}
|
||||
}
|
||||
|
||||
static bool _isGifUrl(String text) {
|
||||
final lower = text.trim().toLowerCase();
|
||||
return lower.endsWith('.gif') ||
|
||||
lower.contains('giphy.com/') ||
|
||||
lower.contains('giphy.gif') ||
|
||||
lower.contains('tenor.com/');
|
||||
}
|
||||
|
||||
/// Update online status for a user across all conversations (matching web)
|
||||
@@ -320,12 +383,22 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
||||
Map<String, List<ChatMessage>>.from(state.messages)
|
||||
..[conversationId] = messagesAfterSend;
|
||||
|
||||
// Update conversation's last message
|
||||
// Update conversation's last message with friendly preview
|
||||
final sent = realMessage;
|
||||
String sentPreview = sent.content;
|
||||
if (sent.messageType == MessageType.image) {
|
||||
sentPreview = 'Sent an image';
|
||||
} else if (sent.messageType == MessageType.file) {
|
||||
sentPreview = 'Sent a file';
|
||||
} else if (_isGifUrl(sent.content)) {
|
||||
sentPreview = 'GIF';
|
||||
}
|
||||
|
||||
final updatedConversations = state.conversations.map((c) {
|
||||
if (c.id == conversationId) {
|
||||
return c.copyWith(
|
||||
lastMessageText: realMessage!.content,
|
||||
lastMessageAt: realMessage.createdAt,
|
||||
lastMessageText: sentPreview,
|
||||
lastMessageAt: sent.createdAt,
|
||||
);
|
||||
}
|
||||
return c;
|
||||
|
||||
Reference in New Issue
Block a user