diff --git a/lib/core/widgets/app_shell.dart b/lib/core/widgets/app_shell.dart index 02c665a..7bd1f40 100644 --- a/lib/core/widgets/app_shell.dart +++ b/lib/core/widgets/app_shell.dart @@ -41,9 +41,17 @@ class _AppShellState extends State { ), Expanded( child: AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - switchInCurve: Curves.easeOut, + duration: const Duration(milliseconds: 150), switchOutCurve: Curves.easeIn, + switchInCurve: Curves.easeOut, + layoutBuilder: (currentChild, previousChildren) { + return Stack( + children: [ + ...previousChildren, + if (currentChild != null) currentChild, + ], + ); + }, transitionBuilder: (child, animation) { return FadeTransition( opacity: animation, @@ -51,7 +59,7 @@ class _AppShellState extends State { ); }, child: KeyedSubtree( - key: ValueKey(widget.child.runtimeType), + key: ValueKey(GoRouterState.of(context).uri.toString()), child: widget.child, ), ), diff --git a/lib/features/agents/presentation/providers/agent_detail_provider.dart b/lib/features/agents/presentation/providers/agent_detail_provider.dart index ce8166f..14674bb 100644 --- a/lib/features/agents/presentation/providers/agent_detail_provider.dart +++ b/lib/features/agents/presentation/providers/agent_detail_provider.dart @@ -1,7 +1,10 @@ +import 'dart:async'; + import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:real_estate_mobile/features/agents/data/agents_repository.dart'; import 'package:real_estate_mobile/features/agents/data/models/agent_profile.dart'; import 'package:real_estate_mobile/features/agents/presentation/providers/agents_provider.dart'; +import 'package:real_estate_mobile/features/messaging/data/socket_service.dart'; class AgentDetailState { final AgentProfile? agent; @@ -375,10 +378,22 @@ class SpecializationCard { class AgentDetailNotifier extends StateNotifier { final AgentsRepository _repo; final String agentId; + StreamSubscription? _connectionResponseSub; AgentDetailNotifier(this._repo, this.agentId) : super(const AgentDetailState()) { _load(); + // Listen for real-time connection response (accepted/rejected) + _connectionResponseSub = + SocketService().onConnectionResponse.listen((_) { + if (mounted) loadConnectionStatus(); + }); + } + + @override + void dispose() { + _connectionResponseSub?.cancel(); + super.dispose(); } Future _load() async { diff --git a/lib/features/agents/presentation/providers/agent_network_provider.dart b/lib/features/agents/presentation/providers/agent_network_provider.dart index c92f344..376fcba 100644 --- a/lib/features/agents/presentation/providers/agent_network_provider.dart +++ b/lib/features/agents/presentation/providers/agent_network_provider.dart @@ -1,5 +1,8 @@ +import 'dart:async'; + import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:real_estate_mobile/features/agents/data/agents_repository.dart'; +import 'package:real_estate_mobile/features/messaging/data/socket_service.dart'; class AgentNetworkState { final List> pendingRequests; @@ -36,9 +39,21 @@ class AgentNetworkState { class AgentNetworkNotifier extends StateNotifier { final AgentsRepository _repo; + StreamSubscription? _connectionRequestSub; AgentNetworkNotifier(this._repo) : super(const AgentNetworkState()) { loadData(); + // Listen for real-time connection request events + _connectionRequestSub = + SocketService().onConnectionRequest.listen((_) { + if (mounted) loadData(); + }); + } + + @override + void dispose() { + _connectionRequestSub?.cancel(); + super.dispose(); } Future loadData() async { diff --git a/lib/features/messaging/data/socket_service.dart b/lib/features/messaging/data/socket_service.dart index ec9bec0..2fb45f5 100644 --- a/lib/features/messaging/data/socket_service.dart +++ b/lib/features/messaging/data/socket_service.dart @@ -32,6 +32,8 @@ class SocketService { final _supportMessageController = StreamController.broadcast(); final _supportTypingStartController = StreamController>.broadcast(); final _supportTypingStopController = StreamController>.broadcast(); + final _connectionRequestController = StreamController>.broadcast(); + final _connectionResponseController = StreamController>.broadcast(); Stream get onNewMessage => _messageController.stream; Stream> get onTypingStart => _typingStartController.stream; @@ -42,6 +44,8 @@ class SocketService { Stream get onSupportMessage => _supportMessageController.stream; Stream> get onSupportTypingStart => _supportTypingStartController.stream; Stream> get onSupportTypingStop => _supportTypingStopController.stream; + Stream> get onConnectionRequest => _connectionRequestController.stream; + Stream> get onConnectionResponse => _connectionResponseController.stream; bool get isConnected => _isConnected; Future connect() async { @@ -153,6 +157,15 @@ class SocketService { _supportTypingStopController.add(Map.from(data as Map)); }); + // Connection request events (real-time updates) + _socket!.on('connection_request', (data) { + _connectionRequestController.add(Map.from(data as Map)); + }); + + _socket!.on('connection_response', (data) { + _connectionResponseController.add(Map.from(data as Map)); + }); + _socket!.connect(); } @@ -274,5 +287,7 @@ class SocketService { _supportMessageController.close(); _supportTypingStartController.close(); _supportTypingStopController.close(); + _connectionRequestController.close(); + _connectionResponseController.close(); } }