feat: Implement real-time messaging with socket listeners and enable starting chats from agent details.
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:real_estate_mobile/core/utils/image_url_resolver.dart';
|
||||
import 'package:real_estate_mobile/core/widgets/s3_image.dart';
|
||||
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||
import 'package:real_estate_mobile/features/messaging/data/models/messaging_models.dart';
|
||||
import 'package:real_estate_mobile/features/messaging/data/socket_service.dart';
|
||||
import 'package:real_estate_mobile/features/messaging/presentation/providers/messaging_provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@@ -26,6 +27,8 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||
bool _isComposing = false;
|
||||
int _previousMessageCount = 0;
|
||||
|
||||
final SocketService _socket = SocketService();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -34,6 +37,8 @@ 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.joinConversation(widget.conversationId);
|
||||
});
|
||||
_scrollController.addListener(_onScroll);
|
||||
_messageController.addListener(_onTextChanged);
|
||||
@@ -41,6 +46,11 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Stop typing and leave room before disposing
|
||||
if (_isComposing) {
|
||||
_socket.stopTyping(widget.conversationId);
|
||||
}
|
||||
_socket.leaveConversation(widget.conversationId);
|
||||
ref.read(messagingProvider.notifier).setActiveConversation(null);
|
||||
_messageController.dispose();
|
||||
_scrollController.dispose();
|
||||
@@ -61,6 +71,12 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||
final composing = _messageController.text.trim().isNotEmpty;
|
||||
if (composing != _isComposing) {
|
||||
setState(() => _isComposing = composing);
|
||||
// Emit typing indicator via socket
|
||||
if (composing) {
|
||||
_socket.startTyping(widget.conversationId);
|
||||
} else {
|
||||
_socket.stopTyping(widget.conversationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +97,7 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||
final text = _messageController.text.trim();
|
||||
if (text.isEmpty) return;
|
||||
|
||||
_socket.stopTyping(widget.conversationId);
|
||||
ref
|
||||
.read(messagingProvider.notifier)
|
||||
.sendMessage(widget.conversationId, text);
|
||||
@@ -998,15 +1015,17 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||
children: [
|
||||
// Name row with timestamp
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
senderName,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
Flexible(
|
||||
child: Text(
|
||||
senderName,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
|
||||
Reference in New Issue
Block a user