You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/modules/cx_module/chat/chat_provider.dart

768 lines
27 KiB
Dart

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:just_audio/just_audio.dart' as JustAudio;
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/main.dart';
import 'package:test_sa/modules/cx_module/chat/call/audio_call_page.dart';
import 'package:test_sa/modules/cx_module/chat/call/video_call_page.dart';
import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart';
import 'package:uuid/uuid.dart';
import 'package:flutter/material.dart' as Material;
import 'package:flutter/material.dart';
import 'api_client.dart';
import 'chat_api_client.dart';
import 'model/chat_attachment_model.dart';
import 'model/chat_participant_model.dart';
import 'model/get_search_user_chat_model.dart';
import 'model/get_single_user_chat_list_model.dart';
import 'model/unread_message_model.dart';
import 'model/user_chat_history_model.dart';
import 'model/call_session.dart';
import 'call/call_debug_helper.dart';
import 'call/incoming_call_dialog.dart';
import 'call/services/webrtc_service.dart';
import 'call/services/callkit_service.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'call/call_error_handler.dart';
import 'call/services/call_notification_service.dart';
import 'services/call_manager.dart';
import 'services/signalr_service.dart';
import 'package:test_sa/core/di/service_locator.dart';
class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
bool isTyping = false;
bool chatLoginTokenLoading = false;
ChatLoginResponse? chatLoginResponse;
bool chatParticipantLoading = false;
ChatParticipantModel? chatParticipantModel;
bool userChatHistoryLoading = false;
List<SingleUserChatModel>? userChatHistory;
bool messageIsSending = false;
List<SingleUserChatModel> chatResponseList = [];
Participants? sender;
Participants? recipient;
late String receiverID;
late int moduleID;
int? referenceID;
// SignalR Service - Retrieved from GetIt (Dependency Injection)
// DO NOT instantiate directly - always use getIt<SignalRService>()
SignalRService get _signalRService => getIt<SignalRService>();
// FIXED: Make chatHubConnection a regular property that can be set
HubConnection? _chatHubConnection;
// Getter for backward compatibility
HubConnection? get chatHubConnection => _chatHubConnection ?? _signalRService.hubConnection;
// Setter for backward compatibility
set chatHubConnection(HubConnection? connection) {
_chatHubConnection = connection;
}
// === CALL STATE - DELEGATED TO CallManager ===
// These getters delegate to CallManager for backwards compatibility
CallStatus get callStatus => CallManager().callStatus;
CallSession? get currentCall => CallManager().currentCall;
Duration get callDuration => CallManager().callDuration;
bool get isMuted => CallManager().isMuted;
bool get isSpeakerOn => CallManager().isSpeakerOn;
bool get isCameraOn => CallManager().isCameraOn;
bool get isPeerMuted => CallManager().isPeerMuted;
bool get isPeerCameraOn => CallManager().isPeerCameraOn;
bool get isCallInProgress => CallManager().isCallInProgress;
WebRTCService? get webrtcService => CallManager().webrtcService;
// For backwards compatibility with UI components
bool get areCallHandlersRegistered => true; // Always true since CallManager handles it
// Private state for legacy ringtone support
final JustAudio.AudioPlayer _ringingPlayer = JustAudio.AudioPlayer();
bool _isRingingPlaying = false;
/// Update call status with detailed logging
void _updateCallStatus(CallStatus newStatus, {String? reason}) {
// Call status is now managed by CallManager
log(' [CALL STATUS] Call status is now managed by CallManager', name: 'ChatProvider');
notifyListeners();
}
/// OPTIMIZATION: Improved connection disposal to prevent memory leaks
/// This properly handles errors and ensures connection is always cleaned up
Future<void> _disposeConnection() async {
try {
if (chatHubConnection != null) {
await chatHubConnection!.stop();
if (kDebugMode) {
print('🔌 SignalR connection closed successfully');
}
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error closing SignalR connection: $e');
}
// Don't rethrow - we still want to clean up
} finally {
chatHubConnection = null;
}
}
/// Reset provider state and properly dispose SignalR connection
Future<void> reset() async {
// OPTIMIZATION: Use async/await for proper cleanup
await _disposeConnection();
chatLoginTokenLoading = false;
chatParticipantLoading = false;
userChatHistoryLoading = false;
chatLoginResponse = null;
chatParticipantModel = null;
userChatHistory = null;
sender = null;
recipient = null;
ChatApiClient().chatLoginResponse = null;
}
/// OPTIMIZATION: Override dispose to ensure SignalR connection cleanup
/// This prevents connection leaks when provider is removed from widget tree
@override
void dispose() {
_disposeConnection().then((_) {
if (kDebugMode) {
print('✅ ChatProvider disposed');
}
}).catchError((error) {
if (kDebugMode) {
print('⚠️ Error during ChatProvider disposal: $error');
}
});
super.dispose();
}
// Future<void> getUserAutoLoginToken(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async {
// reset();
// chatLoginTokenLoading = true;
// notifyListeners();
// chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId);
// chatLoginTokenLoading = false;
// chatParticipantLoading = true;
// notifyListeners();
// // loadParticipants(moduleId, requestId);
// if (chatLoginResponse != null) {
// await loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber);
// }
// }
Future<void> getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber, {bool isMounted = true}) async {
// OPTIMIZATION: Use async reset for proper cleanup
await reset();
receiverID = assigneeEmployeeNumber;
chatLoginTokenLoading = true;
if (isMounted) {
notifyListeners();
}
try {
log('i am called ...');
chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId, assigneeEmployeeNumber);
log('✅ Got chatLoginResponse');
chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber);
log('✅ Got chatParticipantModel: ${chatParticipantModel?.toJson()}');
// Log available participants for debugging
log('📋 Available participants: ${chatParticipantModel?.participants?.map((p) => '${p.employeeNumber} (${p.userName})').toList()}');
log('🔍 Looking for myId: $myId');
log('🔍 Looking for assigneeEmployeeNumber: $assigneeEmployeeNumber');
// Use case-insensitive matching and handle not found gracefully
try {
sender = chatParticipantModel?.participants?.firstWhere((participant) => participant.employeeNumber?.toLowerCase() == myId.toLowerCase());
log('✅ sender i got is ${sender?.toJson()}');
} catch (e) {
log('⚠️ Sender NOT FOUND for myId: $myId. Error: $e');
sender = null;
}
try {
recipient = chatParticipantModel?.participants?.firstWhere((participant) => participant.employeeNumber?.toLowerCase() == assigneeEmployeeNumber.toLowerCase());
log('✅ recipient i got is ${recipient?.toJson()}');
} catch (e) {
log('⚠️ Recipient NOT FOUND for assigneeEmployeeNumber: $assigneeEmployeeNumber. Error: $e');
recipient = null;
}
} catch (ex) {
if (kDebugMode) {
print('⚠️ Error in getUserAutoLoginTokenSilent: $ex');
}
log('❌ EXCEPTION in getUserAutoLoginTokenSilent: $ex');
}
chatLoginTokenLoading = false;
if (isMounted) {
notifyListeners();
}
}
// Future<void> getUserLoadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async {
// await loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber);
// }
// Future<void> loadParticipants(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async {
// userChatHistoryLoading = true;
// notifyListeners();
// try {
// chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber);
// } catch (ex) {
// userChatHistoryLoading = false;
// notifyListeners();
// return;
// }
//
// try {
// sender = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == myId);
// recipient = chatParticipantModel?.participants?.singleWhere((participant) => participant.employeeNumber == assigneeEmployeeNumber);
// } catch (e) {}
// }
Future<void> connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber, bool readOnly, {bool isMounted = true}) async {
userChatHistoryLoading = true;
if (isMounted) {
notifyListeners();
}
moduleID = moduleId;
referenceID = requestId;
// OPTIMIZATION: Wrap connection in try-catch to prevent leaks on error
if (!readOnly) {
try {
await buildHubConnection(chatParticipantModel!.id!.toString());
} catch (e) {
if (kDebugMode) {
print('⚠️ Failed to build hub connection: $e');
}
// Continue loading chat history even if hub connection fails
}
}
userChatHistory = null;
userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber);
chatResponseList = userChatHistory ?? [];
chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
userChatHistoryLoading = false;
if (isMounted) {
notifyListeners();
}
}
// Future<void> loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async {
// userChatHistoryLoading = true;
// notifyListeners();
// userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber);
// chatResponseList = userChatHistory ?? [];
// chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
// userChatHistoryLoading = false;
// notifyListeners();
// }
Future<bool> invokeSendMessage(Object object) async {
messageIsSending = true;
notifyListeners();
bool returnStatus = false;
try {
await chatHubConnection!.invoke("AddChatUserAsync", args: <Object>[object]);
returnStatus = true;
} catch (ex) {}
messageIsSending = false;
notifyListeners();
return returnStatus;
}
// Future<bool> sendTextMessage(String message) async {
// messageIsSending = true;
// notifyListeners();
// bool returnStatus = false;
//
// ChatResponse? chatResponse = await ChatApiClient().sendTextMessage(message, chatParticipantModel!.id!);
// if (chatResponse != null) {
// returnStatus = true;
// // chatResponseList.add(chatResponse);
// try {
// chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
// } catch (ex) {}
// }
// messageIsSending = false;
// notifyListeners();
// return returnStatus;
// }
// List<groups.GroupResponse>? uGroups = [], searchGroups = [];
// Future<void> getUserAutoLoginToken() async {
// userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken();
//
// if (userLoginResponse.StatusCode == 500) {
// disbaleChatForThisUser = true;
// notifyListeners();
// }
//
// if (userLoginResponse.response != null) {
// // AppState().setchatUserDetails = userLoginResponse;
// } else {
// // AppState().setchatUserDetails = userLoginResponse;
// userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr".showToast;
// disbaleChatForThisUser = true;
// notifyListeners();
// }
// }
/// OPTIMIZATION: Improved hub connection with error handling
/// Prevents connection leaks if initialization fails
Future<void> buildHubConnection(String conversationID) async {
try {
log('═══════════════════════════════════════════', name: 'ChatProvider');
log('🔌 [ChatProvider] buildHubConnection called', name: 'ChatProvider');
log('💬 Conversation ID: $conversationID', name: 'ChatProvider');
// Use SignalR service from DI
final signalRService = _signalRService;
log('🔍 [ChatProvider] SignalR service instance: ${signalRService.hashCode}', name: 'ChatProvider');
log(' Is connected: ${signalRService.isConnected}', name: 'ChatProvider');
log(' Connection state: ${signalRService.connectionState}', name: 'ChatProvider');
// Initialize SignalR if not already connected
if (!signalRService.isConnected) {
log('🔌 [ChatProvider] Initializing SignalR connection...', name: 'ChatProvider');
final connected = await signalRService.initialize(
userId: chatLoginResponse!.userId.toString(),
authToken: chatLoginResponse!.token ?? '',
conversationId: conversationID,
);
if (!connected) {
throw Exception('Failed to initialize SignalR connection');
}
log('✅ [ChatProvider] SignalR initialized', name: 'ChatProvider');
log(' Connection ID: ${signalRService.connectionId}', name: 'ChatProvider');
} else {
log('✅ [ChatProvider] SignalR already connected', name: 'ChatProvider');
log(' Connection ID: ${signalRService.connectionId}', name: 'ChatProvider');
// Just join the conversation if needed
if (conversationID.isNotEmpty) {
await signalRService.invoke("JoinConversation", args: [conversationID]);
log('✅ [ChatProvider] Joined conversation: $conversationID', name: 'ChatProvider');
}
}
// Use the connection from SignalRService
chatHubConnection = signalRService.hubConnection;
// Log user details
log('👤 User ID: ${chatLoginResponse!.userId}', name: 'ChatProvider');
log('📞 My Employee Number: ${sender?.employeeNumber ?? "NOT SET"}', name: 'ChatProvider');
log('═══════════════════════════════════════════', name: 'ChatProvider');
// Register chat event handlers
_registerChatEventHandlers();
} catch (e, stackTrace) {
log('❌ [ChatProvider] Error building SignalR connection: $e',
name: 'ChatProvider', error: e, stackTrace: stackTrace);
if (kDebugMode) {
print('⚠️ Error building SignalR connection: $e');
}
// Clean up on error
await _disposeConnection();
rethrow;
}
}
/// Register chat event handlers (separate from call handlers)
void _registerChatEventHandlers() {
if (chatHubConnection == null) {
log('⚠️ Cannot register event handlers - connection is null', name: 'ChatProvider');
return;
}
log('🔧 [EVENT HANDLERS] Registering chat event handlers...', name: 'ChatProvider');
// Register chat event handlers via SignalRService
_signalRService.on("ReceiveMessage", onMsgReceived1);
_signalRService.on("OnMessageReceivedAsync", onMsgReceived);
_signalRService.on("OnSubmitChatAsync", onSubmitChatAsync);
_signalRService.on("OnTypingAsync", OnTypingAsync);
_signalRService.on("OnStopTypingAsync", OnStopTypingAsync);
_signalRService.on("OnSeenChatUserAsync", onSeenUserChatAsync);
_signalRService.on("OnAckSeenAsync", onAckSeenAsync);
_signalRService.on("OnCallHistoryUpdated", _onCallHistoryUpdated);
log('✅ [EVENT HANDLERS] Chat event handlers registered successfully', name: 'ChatProvider');
}
// ==================== CALL INFRASTRUCTURE ====================
// All call operations now delegate to CallManager
/// Start a new audio or video call - delegates to CallManager
Future<void> startCall(Participants recipient, CallType callType) async {
log('📞 [ChatProvider] startCall() - delegating to CallManager', name: 'ChatProvider');
if (sender == null) {
log('❌ [ChatProvider] Cannot start call - sender is null', name: 'ChatProvider');
final context = navigatorKey.currentContext;
if (context != null) {
CallErrorHandler.showGenericError(context, 'Unable to start call. Please try again.');
}
return;
}
// CRITICAL: Ensure CallManager is properly initialized before starting call
log('🔧 [ChatProvider] Initializing CallManager before starting call...', name: 'ChatProvider');
log(' User ID: ${chatLoginResponse?.userId}', name: 'ChatProvider');
log(' Employee Number: ${sender?.employeeNumber}', name: 'ChatProvider');
log(' Conversation ID: ${chatParticipantModel?.id}', name: 'ChatProvider');
try {
await CallManager().initialize(
userId: chatLoginResponse!.userId.toString(),
authToken: chatLoginResponse!.token ?? '',
conversationId: chatParticipantModel?.id?.toString(),
moduleId: moduleID.toString(),
referenceId: referenceID?.toString(),
employeeNumber: sender!.employeeNumber,
);
log('✅ [ChatProvider] CallManager initialized successfully', name: 'ChatProvider');
} catch (e, stackTrace) {
log('❌ [ChatProvider] CallManager initialization failed: $e',
name: 'ChatProvider', error: e, stackTrace: stackTrace);
// CRITICAL: Do NOT proceed if initialization failed
final context = navigatorKey.currentContext;
if (context != null) {
CallErrorHandler.showGenericError(
context,
'Unable to initialize calling system. Please try again.'
);
}
return;
}
// Delegate to CallManager
log('📤 [ChatProvider] Delegating to CallManager.startCall()', name: 'ChatProvider');
log(' To: ${recipient.employeeNumber} (${recipient.userName})', name: 'ChatProvider');
log(' Type: ${callType.name}', name: 'ChatProvider');
await CallManager().startCall(
peerId: recipient.employeeNumber ?? '',
peerName: recipient.userName ?? 'Unknown',
callType: callType,
peerAvatar: recipient.image,
);
notifyListeners();
}
/// Toggle mute - delegates to CallManager
Future<void> toggleMute() async {
await CallManager().toggleMute();
notifyListeners();
}
/// Toggle speaker - delegates to CallManager
Future<void> toggleSpeaker() async {
await CallManager().toggleSpeaker();
notifyListeners();
}
/// Toggle camera - delegates to CallManager
Future<void> toggleCamera() async {
await CallManager().toggleCamera();
notifyListeners();
}
/// Switch camera - delegates to CallManager
Future<void> switchCamera() async {
await CallManager().switchCamera();
}
/// Hang up - delegates to CallManager
Future<void> hangUp() async {
await CallManager().hangUp();
notifyListeners();
}
/// Accept call - delegates to CallManager
Future<void> acceptCall() async {
await CallManager().acceptCall();
notifyListeners();
}
/// Decline call - delegates to CallManager
Future<void> declineCall(String reason) async {
await CallManager().declineCall(reason);
notifyListeners();
}
/// Register call event handlers - kept for backwards compatibility
void _registerCallHandlers() {
// Call handlers are now managed by CallManager
// This method is kept for backwards compatibility but does nothing
log(' [ChatProvider] Call handlers are managed by CallManager', name: 'ChatProvider');
}
/// Handle call history update
void _onCallHistoryUpdated(List<Object?>? args) async {
log('📞 [CALL HISTORY] OnCallHistoryUpdated received', name: 'ChatProvider');
try {
if (sender != null && recipient != null) {
userChatHistory = await ChatApiClient().loadChatHistory(
moduleID,
referenceID ?? 0,
sender!.employeeNumber ?? '',
recipient!.employeeNumber ?? '',
);
chatResponseList = userChatHistory ?? [];
chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
notifyListeners();
}
} catch (e, stackTrace) {
log('❌ [CALL HISTORY] Error reloading chat history: $e', name: 'ChatProvider', error: e, stackTrace: stackTrace);
}
}
// ==================== CHAT EVENT HANDLERS ====================
Future<void> onMsgReceived1(List<Object?>? parameters) async {
print("onMsgReceived1:$parameters");
}
Future<void> onMsgReceived(List<Object?>? parameters) async {
try {
if (parameters != null && parameters.isNotEmpty) {
var data = parameters[0] as Map<Object?, Object?>;
SingleUserChatModel chatResponse = SingleUserChatModel.fromJson(Map<String, dynamic>.from(data));
// Add message to chat history
chatResponseList.insert(0, chatResponse);
chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
notifyListeners();
if (kDebugMode) {
print('✅ Message received: ${chatResponse.contant}'); // Fixed: contant not message
}
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in onMsgReceived: $e');
}
}
}
Future<void> onSubmitChatAsync(List<Object?>? parameters) async {
try {
if (parameters != null && parameters.isNotEmpty) {
var data = parameters[0] as Map<Object?, Object?>;
SingleUserChatModel chatResponse = SingleUserChatModel.fromJson(Map<String, dynamic>.from(data));
// Update existing message or add new one
int existingIndex = chatResponseList.indexWhere((msg) => msg.userChatHistoryLineId == chatResponse.userChatHistoryLineId); // Fixed: use correct property
if (existingIndex != -1) {
chatResponseList[existingIndex] = chatResponse;
} else {
chatResponseList.insert(0, chatResponse);
}
chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!));
notifyListeners();
if (kDebugMode) {
print('✅ Chat submitted: ${chatResponse.contant}'); // Fixed: contant not message
}
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in onSubmitChatAsync: $e');
}
}
}
Future<void> OnTypingAsync(List<Object?>? parameters) async {
try {
isTyping = true;
notifyListeners();
if (kDebugMode) {
print('✍️ User is typing...');
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in OnTypingAsync: $e');
}
}
}
Future<void> OnStopTypingAsync(List<Object?>? parameters) async {
try {
isTyping = false;
notifyListeners();
if (kDebugMode) {
print('✅ User stopped typing');
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in OnStopTypingAsync: $e');
}
}
}
Future<void> onSeenUserChatAsync(List<Object?>? parameters) async {
try {
if (parameters != null && parameters.isNotEmpty) {
// Handle message seen status update
if (kDebugMode) {
print('👁️ Messages marked as seen');
}
notifyListeners();
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in onSeenUserChatAsync: $e');
}
}
}
Future<void> onAckSeenAsync(List<Object?>? parameters) async {
try {
if (parameters != null && parameters.isNotEmpty) {
// Handle message acknowledgment
if (kDebugMode) {
print('✅ Message acknowledgment received');
}
notifyListeners();
}
} catch (e) {
if (kDebugMode) {
print('⚠️ Error in onAckSeenAsync: $e');
}
}
}
// ==================== UTILITY METHODS ====================
/// Reset unread message count
Future<bool> resetCount({int? moduleId, int? referenceNo, String? userId}) async { // Fixed: userId is String? not int?
try {
if (chatLoginResponse != null && sender != null && recipient != null) {
await ChatApiClient().resetCountApi(
moduleId ?? moduleID, // Use parameter or fall back to stored value
referenceNo ?? referenceID ?? 0,
sender!.employeeNumber ?? '',
);
if (kDebugMode) {
print('✅ Reset unread count');
}
return true;
}
return false;
} catch (e) {
if (kDebugMode) {
print('⚠️ resetCount error: $e');
}
log('resetCount error: $e');
return false;
}
}
/// Upload attachments
Future<List<ChatAttachment>?> uploadAttachments(String username, File file, String conversationId) async { // Fixed: match actual usage
try {
if (chatLoginResponse == null || chatParticipantModel == null) {
if (kDebugMode) {
print('⚠️ Cannot upload - chat not initialized');
}
return null;
}
// Upload single file
final files = [file];
// TODO: Implement file upload to chat API
// The ChatApiClient doesn't have uploadAttachments method yet
// For now, return empty list
if (kDebugMode) {
print('⚠️ uploadAttachments not implemented in ChatApiClient yet');
print(' Username: $username');
print(' File: ${file.path}');
print(' Conversation: $conversationId');
}
return [];
} catch (e) {
if (kDebugMode) {
print('⚠️ Error uploading attachments: $e');
}
log('uploadAttachments error: $e');
return null;
}
}
/// Get unread messages
Future<List<UnReadMessage>> getUnReadMessages(String employeeId) async { // Fixed: accept employeeId and return List<UnReadMessage>
try {
if (chatLoginResponse == null) {
if (kDebugMode) {
print('⚠️ Cannot get unread messages - not logged in');
}
return [];
}
// TODO: Implement getUnreadMessages API in ChatApiClient
// The ChatApiClient doesn't have this method yet
// For now, return empty list
if (kDebugMode) {
print('⚠️ getUnreadMessages API not implemented in ChatApiClient yet');
print(' Requested for employeeId: $employeeId');
}
return [];
} catch (e) {
if (kDebugMode) {
print('⚠️ Error getting unread messages: $e');
}
log('getUnReadMessages error: $e');
return [];
}
}
}