feat: Implement socket-first message sending with REST fallback, enhance chat room re-joining on socket reconnect, and update 'Categories' to 'Specialization' in the hero section.

This commit is contained in:
pradeepkumar
2026-03-16 17:49:25 +05:30
parent d86c862ed7
commit 26d9197548
3 changed files with 33 additions and 16 deletions

View File

@@ -31,9 +31,9 @@ class _HeroSectionState extends ConsumerState<HeroSection> {
String? _selectedLocation;
String _selectedLocationName = 'Location';
String? _selectedCategory;
String _selectedCategoryName = 'Categories';
String _selectedCategoryName = 'Specialization';
/// Cached filter fields fetched on-demand for Location/Categories pickers.
/// Cached filter fields fetched on-demand for Location/Specialization pickers.
List<FilterableField>? _cachedFilterFields;
@override
@@ -371,22 +371,22 @@ class _HeroSectionState extends ConsumerState<HeroSection> {
),
),
const SizedBox(height: 18),
// Categories — opens picker
// Specialization — opens picker
GestureDetector(
onTap: () => _showFilterPicker(
title: 'Select Category',
title: 'Select Specialization',
fieldSlug: 'specialization',
currentValue: _selectedCategory,
onSelect: (value, label) {
setState(() {
_selectedCategory = value;
_selectedCategoryName = label ?? 'Categories';
_selectedCategoryName = label ?? 'Specialization';
});
},
onClear: () {
setState(() {
_selectedCategory = null;
_selectedCategoryName = 'Categories';
_selectedCategoryName = 'Specialization';
});
},
),

View File

@@ -291,7 +291,20 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
);
try {
final realMessage = await _repository.sendMessage(
// Send via socket so the backend broadcasts new_message to the other user.
// The REST endpoint does NOT emit socket events, so using REST here
// would prevent real-time delivery to the other participant.
ChatMessage? realMessage;
if (_socket.isConnected) {
realMessage = await _socket.sendMessage(conversationId, {
'content': content,
'messageType': 'TEXT',
});
}
// Fallback to REST if socket send failed or not connected
realMessage ??= await _repository.sendMessage(
conversationId,
content: content,
);
@@ -311,7 +324,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
final updatedConversations = state.conversations.map((c) {
if (c.id == conversationId) {
return c.copyWith(
lastMessageText: realMessage.content,
lastMessageText: realMessage!.content,
lastMessageAt: realMessage.createdAt,
);
}

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -28,6 +30,7 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
int _previousMessageCount = 0;
final SocketService _socket = SocketService();
StreamSubscription<bool>? _connectionSub;
@override
void initState() {
@@ -37,17 +40,17 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
notifier.setActiveConversation(widget.conversationId);
notifier.loadMessages(widget.conversationId);
notifier.markAsRead(widget.conversationId);
// Join socket room for real-time updates (socket is connected at auth time)
// Join socket room for real-time updates
if (_socket.isConnected) {
_socket.joinConversation(widget.conversationId);
} else {
// Wait for socket connection then join
_socket.onConnectionChange.first.then((connected) {
if (connected && mounted) {
_socket.joinConversation(widget.conversationId);
}
});
}
// Listen for ALL connection changes (initial connect + reconnects)
// so we re-join the room after any reconnection
_connectionSub = _socket.onConnectionChange.listen((connected) {
if (connected && mounted) {
_socket.joinConversation(widget.conversationId);
}
});
});
_scrollController.addListener(_onScroll);
_messageController.addListener(_onTextChanged);
@@ -55,6 +58,7 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
@override
void dispose() {
_connectionSub?.cancel();
// Stop typing and leave room before disposing
if (_isComposing) {
_socket.stopTyping(widget.conversationId);