diff --git a/lib/modules/cx_module/chat/call/services/webrtc_service.dart b/lib/modules/cx_module/chat/call/services/webrtc_service.dart index 13d85dd7..4900b441 100644 --- a/lib/modules/cx_module/chat/call/services/webrtc_service.dart +++ b/lib/modules/cx_module/chat/call/services/webrtc_service.dart @@ -186,15 +186,15 @@ class WebRTCService { // Setup peer connection event handlers _setupPeerConnectionListeners(); - // CRITICAL FIX: Enable speakerphone by default for audio calls - // This ensures audio plays through the loudspeaker instead of the quiet earpiece - log('🔊 [WebRTC] Enabling speakerphone by default for audio call...', name: 'WebRTCService'); + // CRITICAL FIX: Keep speakerphone OFF by default for audio calls + // User can manually enable it if needed via the speaker button + log('🔇 [WebRTC] Keeping speakerphone OFF by default for audio call...', name: 'WebRTCService'); try { - await Helper.setSpeakerphoneOn(true); - log('✅ [WebRTC] Speakerphone enabled', name: 'WebRTCService'); + await Helper.setSpeakerphoneOn(false); + log('✅ [WebRTC] Speakerphone disabled (earpiece mode)', name: 'WebRTCService'); } catch (e) { - log('⚠️ [WebRTC] Failed to enable speakerphone: $e', name: 'WebRTCService'); - // Continue anyway - user can manually enable it + log('⚠️ [WebRTC] Failed to disable speakerphone: $e', name: 'WebRTCService'); + // Continue anyway - not critical } if (kDebugMode) { diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index 8d5011e8..bbed956c 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -1,5 +1,3 @@ - - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -44,7 +42,13 @@ class _ChatWidgetState extends State { void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { - Provider.of(context, listen: false).reset(); + // CRITICAL FIX: Don't reset if already initialized with same request + // This prevents closing SignalR connection when navigating between pages + final chatProvider = Provider.of(context, listen: false); + if (chatProvider.referenceID != widget.requestId) { + // Only reset if it's a different request + chatProvider.reset(); + } getChatToken(); }); } diff --git a/lib/modules/cx_module/chat/services/call_manager.dart b/lib/modules/cx_module/chat/services/call_manager.dart index dc435886..be82d583 100644 --- a/lib/modules/cx_module/chat/services/call_manager.dart +++ b/lib/modules/cx_module/chat/services/call_manager.dart @@ -85,6 +85,11 @@ class CallManager extends ChangeNotifier { try { log('🔧 [CallManager] Initializing...', name: 'CallManager'); + // CRITICAL FIX: Cache credentials for background call handling + _cachedUserId = userId; + _cachedAuthToken = authToken; + _cachedEmployeeNumber = employeeNumber; + // CRITICAL FIX: Don't re-initialize if already initialized with same USER credentials // conversationId can change (different chats) - that's OK, just update it // Only re-initialize if USER changes (userId, authToken, employeeNumber) @@ -380,46 +385,60 @@ class CallManager extends ChangeNotifier { log(' Video: $isVideoCall', name: 'CallManager'); // CRITICAL FIX: Auto-initialize CallManager if not already initialized + // This handles the case when app is in background and context is null if (_userId == null || _authToken == null) { log('⚠️ [INCOMING] CallManager not initialized - attempting auto-initialization...', name: 'CallManager'); - // Try to get credentials from ChatProvider - try { - final chatProvider = Provider.of(navigatorKey.currentContext!, listen: false); - final chatLoginResponse = chatProvider.chatLoginResponse; - final sender = chatProvider.sender; // Get sender for employee number - - if (chatLoginResponse != null) { - log('🔧 [INCOMING] Found credentials in ChatProvider', name: 'CallManager'); - log(' User ID: ${chatLoginResponse.userId}', name: 'CallManager'); - log(' Employee Number: ${sender?.employeeNumber ?? "NOT AVAILABLE"}', name: 'CallManager'); - - await initialize( - userId: chatLoginResponse.userId.toString(), - authToken: chatLoginResponse.token ?? '', - conversationId: extraData?['conversationId'] as String?, - moduleId: extraData?['moduleId'] as String?, - referenceId: extraData?['referenceId'] as String?, - employeeNumber: sender?.employeeNumber, // Get from sender participant - ); - - log('✅ [INCOMING] Auto-initialization successful', name: 'CallManager'); - } else { - log('❌ [INCOMING] No credentials available in ChatProvider', name: 'CallManager'); - // Show error to user - final context = navigatorKey.currentContext; - if (context != null) { - CallErrorHandler.showGenericError(context, 'Unable to receive call. Please login to chat first.'); + // CRITICAL FIX: Try cached credentials first (for background calls) + if (_cachedUserId != null && _cachedAuthToken != null && _cachedEmployeeNumber != null) { + log('🔧 [INCOMING] Using cached credentials (app in background)', name: 'CallManager'); + log(' Cached User ID: $_cachedUserId', name: 'CallManager'); + log(' Cached Employee Number: $_cachedEmployeeNumber', name: 'CallManager'); + + await initialize( + userId: _cachedUserId!, + authToken: _cachedAuthToken!, + conversationId: extraData?['conversationId'] as String?, + moduleId: extraData?['moduleId'] as String?, + referenceId: extraData?['referenceId'] as String?, + employeeNumber: _cachedEmployeeNumber, + ); + + log('✅ [INCOMING] Auto-initialization successful (from cache)', name: 'CallManager'); + } + // Try to get credentials from ChatProvider (app in foreground) + else if (navigatorKey.currentContext != null) { + try { + final chatProvider = Provider.of(navigatorKey.currentContext!, listen: false); + final chatLoginResponse = chatProvider.chatLoginResponse; + final sender = chatProvider.sender; // Get sender for employee number + + if (chatLoginResponse != null) { + log('🔧 [INCOMING] Found credentials in ChatProvider', name: 'CallManager'); + log(' User ID: ${chatLoginResponse.userId}', name: 'CallManager'); + log(' Employee Number: ${sender?.employeeNumber ?? "NOT AVAILABLE"}', name: 'CallManager'); + + await initialize( + userId: chatLoginResponse.userId.toString(), + authToken: chatLoginResponse.token ?? '', + conversationId: extraData?['conversationId'] as String?, + moduleId: extraData?['moduleId'] as String?, + referenceId: extraData?['referenceId'] as String?, + employeeNumber: sender?.employeeNumber, // Get from sender participant + ); + + log('✅ [INCOMING] Auto-initialization successful (from ChatProvider)', name: 'CallManager'); + } else { + log('❌ [INCOMING] No credentials available', name: 'CallManager'); + return; } + } catch (e) { + log('❌ [INCOMING] Auto-initialization failed: $e', name: 'CallManager'); return; } - } catch (e) { - log('❌ [INCOMING] Auto-initialization failed: $e', name: 'CallManager'); - // Show error to user - final context = navigatorKey.currentContext; - if (context != null) { - CallErrorHandler.showGenericError(context, 'Unable to receive call. Please open chat first.'); - } + } else { + log('❌ [INCOMING] No cached credentials and no context available', name: 'CallManager'); + log(' This means user never logged into chat in this session', name: 'CallManager'); return; } } @@ -871,10 +890,10 @@ class CallManager extends ChangeNotifier { log('🎵 [WEBRTC] Initializing for audio call', name: 'CallManager'); await _webrtcService!.initializeForAudioCall(); - // CRITICAL FIX: Speaker is enabled by default in WebRTC service + // CRITICAL FIX: Speaker is OFF by default in WebRTC service (earpiece mode) // Update the CallManager state to reflect this - _isSpeakerOn = true; - log('✅ [WEBRTC] Speaker state synchronized: ON', name: 'CallManager'); + _isSpeakerOn = false; + log('✅ [WEBRTC] Speaker state synchronized: OFF (earpiece mode)', name: 'CallManager'); notifyListeners(); } else { log('📹 [WEBRTC] Initializing for video call', name: 'CallManager');