|  |  |  | @ -85,12 +85,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   void registerEvents() { | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); | 
		
	
		
			
				|  |  |  |  |     //   chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); | 
		
	
		
			
				|  |  |  |  |     // hubConnection.on("OnSeenChatUserAsync", onChatSeen); | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnUserTypingAsync", onUserTyping); | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnUserCountAsync", userCountAsync); | 
		
	
		
			
				|  |  |  |  |     //  hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); | 
		
	
		
			
				|  |  |  |  |     //  chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); | 
		
	
		
			
				|  |  |  |  |     chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); | 
		
	
		
			
				|  |  |  |  |     print("Alll Registered"); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void getUserRecentChats() async { | 
		
	
	
		
			
				
					|  |  |  | @ -107,9 +108,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     if (favUList.response != null && recentChat.response != null) { | 
		
	
		
			
				|  |  |  |  |       favUsersList = favUList.response!; | 
		
	
		
			
				|  |  |  |  |       favUsersList.sort( | 
		
	
		
			
				|  |  |  |  |         (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo( | 
		
	
		
			
				|  |  |  |  |               b.userName!.toLowerCase(), | 
		
	
		
			
				|  |  |  |  |             ), | 
		
	
		
			
				|  |  |  |  |         (ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase()), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |       for (dynamic user in recentChat.response!) { | 
		
	
		
			
				|  |  |  |  |         for (dynamic favUser in favUList.response!) { | 
		
	
	
		
			
				
					|  |  |  | @ -230,16 +229,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   Future<dynamic> uploadAttachments(String userId, File file) async { | 
		
	
		
			
				|  |  |  |  |     dynamic result; | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       StreamedResponse response = await ChatApiClient().uploadMedia(userId, file); | 
		
	
		
			
				|  |  |  |  |       if (response.statusCode == 200) { | 
		
	
		
			
				|  |  |  |  |         result = jsonDecode(await response.stream.bytesToString()); | 
		
	
		
			
				|  |  |  |  |       Object? response = await ChatApiClient().uploadMedia(userId, file); | 
		
	
		
			
				|  |  |  |  |       if (response != null) { | 
		
	
		
			
				|  |  |  |  |         result = response; | 
		
	
		
			
				|  |  |  |  |       } else { | 
		
	
		
			
				|  |  |  |  |         result = []; | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       throw e; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -365,6 +363,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |           ChatUser( | 
		
	
		
			
				|  |  |  |  |             id: data.first.currentUserId, | 
		
	
		
			
				|  |  |  |  |             userName: data.first.currentUserName, | 
		
	
		
			
				|  |  |  |  |             email: data.first.currentUserEmail, | 
		
	
		
			
				|  |  |  |  |             unreadMessageCount: 0, | 
		
	
		
			
				|  |  |  |  |             isImageLoading: false, | 
		
	
		
			
				|  |  |  |  |             image: chatImages!.first.profilePicture ?? "", | 
		
	
	
		
			
				
					|  |  |  | @ -404,6 +403,28 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void OnSubmitChatAsync(List<Object?>? parameters) { | 
		
	
		
			
				|  |  |  |  |     logger.d(parameters); | 
		
	
		
			
				|  |  |  |  |     List<SingleUserChatModel> data = [], temp = []; | 
		
	
		
			
				|  |  |  |  |     for (dynamic msg in parameters!) { | 
		
	
		
			
				|  |  |  |  |       data = getSingleUserChatModel(jsonEncode(msg)); | 
		
	
		
			
				|  |  |  |  |       temp = getSingleUserChatModel(jsonEncode(msg)); | 
		
	
		
			
				|  |  |  |  |       data.first.targetUserId = temp.first.currentUserId; | 
		
	
		
			
				|  |  |  |  |       data.first.targetUserName = temp.first.currentUserName; | 
		
	
		
			
				|  |  |  |  |       data.first.targetUserEmail = temp.first.currentUserEmail; | 
		
	
		
			
				|  |  |  |  |       data.first.currentUserId = temp.first.targetUserId; | 
		
	
		
			
				|  |  |  |  |       data.first.currentUserName = temp.first.targetUserName; | 
		
	
		
			
				|  |  |  |  |       data.first.currentUserEmail = temp.first.targetUserEmail; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (isChatScreenActive && data.first.currentUserId == receiverID) { | 
		
	
		
			
				|  |  |  |  |       int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == 0); | 
		
	
		
			
				|  |  |  |  |       logger.d(index); | 
		
	
		
			
				|  |  |  |  |       userChatHistory[index] = data.first; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void sort() { | 
		
	
		
			
				|  |  |  |  |     searchedChats!.sort( | 
		
	
		
			
				|  |  |  |  |       (ChatUser a, ChatUser b) => b.unreadMessageCount!.compareTo(a.unreadMessageCount!), | 
		
	
	
		
			
				
					|  |  |  | @ -454,6 +475,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |         return 2; | 
		
	
		
			
				|  |  |  |  |       case ".rar": | 
		
	
		
			
				|  |  |  |  |         return 2; | 
		
	
		
			
				|  |  |  |  |       case ".aac": | 
		
	
		
			
				|  |  |  |  |         return 13; | 
		
	
		
			
				|  |  |  |  |       case ".mp3": | 
		
	
		
			
				|  |  |  |  |         return 14; | 
		
	
		
			
				|  |  |  |  |       default: | 
		
	
		
			
				|  |  |  |  |         return 0; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -487,6 +512,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |         return "application/octet-stream"; | 
		
	
		
			
				|  |  |  |  |       case ".rar": | 
		
	
		
			
				|  |  |  |  |         return "application/octet-stream"; | 
		
	
		
			
				|  |  |  |  |       case ".aac": | 
		
	
		
			
				|  |  |  |  |         return "audio/aac"; | 
		
	
		
			
				|  |  |  |  |       case ".mp3": | 
		
	
		
			
				|  |  |  |  |         return "audio/mp3"; | 
		
	
		
			
				|  |  |  |  |       default: | 
		
	
		
			
				|  |  |  |  |         return ""; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -501,11 +530,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       required bool isAttachment, | 
		
	
		
			
				|  |  |  |  |       required bool isReply, | 
		
	
		
			
				|  |  |  |  |       Uint8List? image, | 
		
	
		
			
				|  |  |  |  |       Uint8List? voice, | 
		
	
		
			
				|  |  |  |  |       required bool isImageLoaded}) async { | 
		
	
		
			
				|  |  |  |  |     Uuid uuid = const Uuid(); | 
		
	
		
			
				|  |  |  |  |     String contentNo = uuid.v4(); | 
		
	
		
			
				|  |  |  |  |     String msg = message.text; | 
		
	
		
			
				|  |  |  |  |     SingleUserChatModel data = SingleUserChatModel( | 
		
	
		
			
				|  |  |  |  |       userChatHistoryId: 0, | 
		
	
		
			
				|  |  |  |  |       chatEventId: chatEventId, | 
		
	
		
			
				|  |  |  |  |       chatSource: 1, | 
		
	
		
			
				|  |  |  |  |       contant: msg, | 
		
	
	
		
			
				
					|  |  |  | @ -530,7 +561,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |           : null, | 
		
	
		
			
				|  |  |  |  |       image: image, | 
		
	
		
			
				|  |  |  |  |       isImageLoaded: isImageLoaded, | 
		
	
		
			
				|  |  |  |  |       voice: voice, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     print("Model data---------------------------"); | 
		
	
		
			
				|  |  |  |  |     logger.d(data.toJson()); | 
		
	
		
			
				|  |  |  |  |     userChatHistory.insert(0, data); | 
		
	
		
			
				|  |  |  |  |     isFileSelected = false; | 
		
	
		
			
				|  |  |  |  |     isMsgReply = false; | 
		
	
	
		
			
				
					|  |  |  | @ -569,9 +603,11 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |           isReply: false, | 
		
	
		
			
				|  |  |  |  |           isImageLoaded: true, | 
		
	
		
			
				|  |  |  |  |           image: selectedFile.readAsBytesSync()); | 
		
	
		
			
				|  |  |  |  |     } // normal attachemnt msg | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (!isFileSelected && isMsgReply) { | 
		
	
		
			
				|  |  |  |  |       print("Normal Text To Text Reply"); | 
		
	
		
			
				|  |  |  |  |       if (kDebugMode) { | 
		
	
		
			
				|  |  |  |  |         print("Normal Text To Text Reply"); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       if (message.text == null || message.text.isEmpty) { | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
	
		
			
				
					|  |  |  | @ -723,6 +759,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |         return "assets/icons/chat/zip.svg"; | 
		
	
		
			
				|  |  |  |  |       case ".rar": | 
		
	
		
			
				|  |  |  |  |         return "assets/icons/chat/zip.svg"; | 
		
	
		
			
				|  |  |  |  |       case ".aac": | 
		
	
		
			
				|  |  |  |  |         return "assets/icons/chat/aac.svg"; | 
		
	
		
			
				|  |  |  |  |       case ".mp3": | 
		
	
		
			
				|  |  |  |  |         return "assets/icons/chat/zip.mp3"; | 
		
	
		
			
				|  |  |  |  |       default: | 
		
	
		
			
				|  |  |  |  |         return "assets/images/thumb.svg"; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -889,6 +929,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       String dirPath = '${appDocumentsDirectory.path}/chat_images'; | 
		
	
		
			
				|  |  |  |  |       if (!await Directory(dirPath).exists()) { | 
		
	
		
			
				|  |  |  |  |         await Directory(dirPath).create(); | 
		
	
		
			
				|  |  |  |  |         await File('$dirPath/.nomedia').create(); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       late File imageFile = File("$dirPath/$userID.jpg"); | 
		
	
		
			
				|  |  |  |  |       imageFile.writeAsBytesSync(decodedBytes); | 
		
	
	
		
			
				
					|  |  |  | @ -956,11 +997,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void userTypingInvoke({required int currentUser, required int reciptUser}) async { | 
		
	
		
			
				|  |  |  |  |     logger.d([reciptUser, currentUser]); | 
		
	
		
			
				|  |  |  |  |     await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Audio Recoding Work | 
		
	
		
			
				|  |  |  |  | // Audio Recoding Work | 
		
	
		
			
				|  |  |  |  |   Timer? _timer; | 
		
	
		
			
				|  |  |  |  |   int _recodeDuration = 0; | 
		
	
		
			
				|  |  |  |  |   bool isRecoding = false; | 
		
	
	
		
			
				
					|  |  |  | @ -972,13 +1012,18 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   late RecorderController recorderController; | 
		
	
		
			
				|  |  |  |  |   late PlayerController playerController; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   //////// Audio Recoding Work //////////////////// | 
		
	
		
			
				|  |  |  |  | //////// Audio Recoding Work //////////////////// | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<void> initAudio({required int receiverId}) async { | 
		
	
		
			
				|  |  |  |  |     // final dir = Directory((Platform.isAndroid | 
		
	
		
			
				|  |  |  |  |     //     ? await getExternalStorageDirectory() //FOR ANDROID | 
		
	
		
			
				|  |  |  |  |     //     : await getApplicationSupportDirectory() //FOR IOS | 
		
	
		
			
				|  |  |  |  |     // )! | 
		
	
		
			
				|  |  |  |  |     appDirectory = await getApplicationDocumentsDirectory(); | 
		
	
		
			
				|  |  |  |  |     String dirPath = '${appDirectory.path}/chat_audios'; | 
		
	
		
			
				|  |  |  |  |     if (!await Directory(dirPath).exists()) { | 
		
	
		
			
				|  |  |  |  |       await Directory(dirPath).create(); | 
		
	
		
			
				|  |  |  |  |       await File('$dirPath/.nomedia').create(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     path = "$dirPath/${AppState().chatDetails!.response!.id}-$receiverID-${DateTime.now().microsecondsSinceEpoch}.aac"; | 
		
	
		
			
				|  |  |  |  |     recorderController = RecorderController() | 
		
	
	
		
			
				
					|  |  |  | @ -986,6 +1031,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       ..androidOutputFormat = AndroidOutputFormat.mpeg4 | 
		
	
		
			
				|  |  |  |  |       ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC | 
		
	
		
			
				|  |  |  |  |       ..sampleRate = 6000 | 
		
	
		
			
				|  |  |  |  |       ..updateFrequency = const Duration(milliseconds: 100) | 
		
	
		
			
				|  |  |  |  |       ..bitRate = 18000; | 
		
	
		
			
				|  |  |  |  |     playerController = PlayerController(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -1014,15 +1060,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void _startTimer() { | 
		
	
		
			
				|  |  |  |  |   Future<void> _startTimer() async { | 
		
	
		
			
				|  |  |  |  |     _timer?.cancel(); | 
		
	
		
			
				|  |  |  |  |     _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { | 
		
	
		
			
				|  |  |  |  |     _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { | 
		
	
		
			
				|  |  |  |  |       _recodeDuration++; | 
		
	
		
			
				|  |  |  |  |       buildTimer(); | 
		
	
		
			
				|  |  |  |  |       notifyListeners(); | 
		
	
		
			
				|  |  |  |  |       if (_recodeDuration <= 59) { | 
		
	
		
			
				|  |  |  |  |         applyCounter(); | 
		
	
		
			
				|  |  |  |  |       } else { | 
		
	
		
			
				|  |  |  |  |         pauseRecoding(); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void applyCounter() { | 
		
	
		
			
				|  |  |  |  |     buildTimer(); | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<void> pauseRecoding() async { | 
		
	
		
			
				|  |  |  |  |     isPause = true; | 
		
	
		
			
				|  |  |  |  |     isPlaying = true; | 
		
	
	
		
			
				
					|  |  |  | @ -1030,27 +1084,16 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     path = await recorderController.stop(false); | 
		
	
		
			
				|  |  |  |  |     File file = File(path!); | 
		
	
		
			
				|  |  |  |  |     file.readAsBytesSync(); | 
		
	
		
			
				|  |  |  |  |     path = file.path; | 
		
	
		
			
				|  |  |  |  |     await playerController.preparePlayer(file.path, 1.0); | 
		
	
		
			
				|  |  |  |  |     // var tempDuration = _recodeDuration; | 
		
	
		
			
				|  |  |  |  |     // _recodeDuration = tempDuration; | 
		
	
		
			
				|  |  |  |  |     _timer?.cancel(); | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void resumeRecoding() { | 
		
	
		
			
				|  |  |  |  |     isPause = false; | 
		
	
		
			
				|  |  |  |  |     isPlaying = false; | 
		
	
		
			
				|  |  |  |  |     isRecoding = true; | 
		
	
		
			
				|  |  |  |  |     recorderController.record(path); | 
		
	
		
			
				|  |  |  |  |     _startTimer(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<void> deleteRecoding() async { | 
		
	
		
			
				|  |  |  |  |     _recodeDuration = 0; | 
		
	
		
			
				|  |  |  |  |     _timer?.cancel(); | 
		
	
		
			
				|  |  |  |  |    // path = await recorderController.stop(true); | 
		
	
		
			
				|  |  |  |  |     recorderController.reset(); | 
		
	
		
			
				|  |  |  |  |     print(path); | 
		
	
		
			
				|  |  |  |  |     recorderController.stop(true); | 
		
	
		
			
				|  |  |  |  |     if (path != null && path!.isNotEmpty) { | 
		
	
		
			
				|  |  |  |  |       File delFile = File(path!); | 
		
	
		
			
				|  |  |  |  |       double fileSizeInKB = delFile.lengthSync() / 1024; | 
		
	
	
		
			
				
					|  |  |  | @ -1095,8 +1138,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void sendVoiceMessage(BuildContext context, {required int targetUserId, required int userStatus, required String userEmail, required String targetUserName}) async { | 
		
	
		
			
				|  |  |  |  |     //recorderController.pause(); | 
		
	
		
			
				|  |  |  |  |     path = await recorderController.stop(false); | 
		
	
		
			
				|  |  |  |  |     if (!isPause) { | 
		
	
		
			
				|  |  |  |  |       path = await recorderController.stop(false); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     if (kDebugMode) { | 
		
	
		
			
				|  |  |  |  |       print(path); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -1110,17 +1154,156 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile); | 
		
	
		
			
				|  |  |  |  |     logger.d(value); | 
		
	
		
			
				|  |  |  |  |     String? ext = getFileExtension(voiceFile.path); | 
		
	
		
			
				|  |  |  |  |     logger.d(voiceFile.path!.split("/").last); | 
		
	
		
			
				|  |  |  |  |     Utils.hideLoading(context); | 
		
	
		
			
				|  |  |  |  |     // sendChatToServer( | 
		
	
		
			
				|  |  |  |  |     //     chatEventId: 2, | 
		
	
		
			
				|  |  |  |  |     //     fileTypeId: getFileType(ext.toString()), | 
		
	
		
			
				|  |  |  |  |     //     targetUserId: targetUserId, | 
		
	
		
			
				|  |  |  |  |     //     targetUserName: targetUserName, | 
		
	
		
			
				|  |  |  |  |     //     isAttachment: true, | 
		
	
		
			
				|  |  |  |  |     //     chatReplyId: null, | 
		
	
		
			
				|  |  |  |  |     //     isReply: false, | 
		
	
		
			
				|  |  |  |  |     //     isImageLoaded: true, | 
		
	
		
			
				|  |  |  |  |     //     image: voiceFile.readAsBytesSync()); | 
		
	
		
			
				|  |  |  |  |     sendVoiceMessageToServer( | 
		
	
		
			
				|  |  |  |  |       msgText: voiceFile.path!.split("/").last, | 
		
	
		
			
				|  |  |  |  |       chatEventId: 2, | 
		
	
		
			
				|  |  |  |  |       fileTypeId: getFileType(ext.toString()), | 
		
	
		
			
				|  |  |  |  |       targetUserId: targetUserId, | 
		
	
		
			
				|  |  |  |  |       targetUserName: targetUserName, | 
		
	
		
			
				|  |  |  |  |       isVoiceAttached: true, | 
		
	
		
			
				|  |  |  |  |       voice: voiceFile.readAsBytesSync(), | 
		
	
		
			
				|  |  |  |  |       userEmail: userEmail, | 
		
	
		
			
				|  |  |  |  |       userStatus: userStatus, | 
		
	
		
			
				|  |  |  |  |       chatReplyId: null, | 
		
	
		
			
				|  |  |  |  |       isAttachment: true, | 
		
	
		
			
				|  |  |  |  |       isReply: false, | 
		
	
		
			
				|  |  |  |  |       voicFile: voiceFile, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<void> sendVoiceMessageToServer( | 
		
	
		
			
				|  |  |  |  |       {String? msgText, | 
		
	
		
			
				|  |  |  |  |       int? chatEventId, | 
		
	
		
			
				|  |  |  |  |       int? fileTypeId, | 
		
	
		
			
				|  |  |  |  |       int? targetUserId, | 
		
	
		
			
				|  |  |  |  |       String? targetUserName, | 
		
	
		
			
				|  |  |  |  |       bool? isVoiceAttached, | 
		
	
		
			
				|  |  |  |  |       Uint8List? voice, | 
		
	
		
			
				|  |  |  |  |       String? userEmail, | 
		
	
		
			
				|  |  |  |  |       int? userStatus, | 
		
	
		
			
				|  |  |  |  |       bool? isReply, | 
		
	
		
			
				|  |  |  |  |       bool? isAttachment, | 
		
	
		
			
				|  |  |  |  |       int? chatReplyId, | 
		
	
		
			
				|  |  |  |  |       File? voicFile}) async { | 
		
	
		
			
				|  |  |  |  |     Uuid uuid = const Uuid(); | 
		
	
		
			
				|  |  |  |  |     String contentNo = uuid.v4(); | 
		
	
		
			
				|  |  |  |  |     String msg = msgText!; | 
		
	
		
			
				|  |  |  |  |     SingleUserChatModel data = SingleUserChatModel( | 
		
	
		
			
				|  |  |  |  |       chatEventId: chatEventId, | 
		
	
		
			
				|  |  |  |  |       chatSource: 1, | 
		
	
		
			
				|  |  |  |  |       contant: msg, | 
		
	
		
			
				|  |  |  |  |       contantNo: contentNo, | 
		
	
		
			
				|  |  |  |  |       conversationId: chatCID, | 
		
	
		
			
				|  |  |  |  |       createdDate: DateTime.now(), | 
		
	
		
			
				|  |  |  |  |       currentUserId: AppState().chatDetails!.response!.id, | 
		
	
		
			
				|  |  |  |  |       currentUserName: AppState().chatDetails!.response!.userName, | 
		
	
		
			
				|  |  |  |  |       targetUserId: targetUserId, | 
		
	
		
			
				|  |  |  |  |       targetUserName: targetUserName, | 
		
	
		
			
				|  |  |  |  |       isReplied: false, | 
		
	
		
			
				|  |  |  |  |       fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |       userChatReplyResponse: isReply! ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, | 
		
	
		
			
				|  |  |  |  |       fileTypeResponse: isAttachment! | 
		
	
		
			
				|  |  |  |  |           ? FileTypeResponse( | 
		
	
		
			
				|  |  |  |  |               fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |               fileTypeName: getFileExtension(voicFile!.path).toString(), | 
		
	
		
			
				|  |  |  |  |               fileKind: "file", | 
		
	
		
			
				|  |  |  |  |               fileName: msgText, | 
		
	
		
			
				|  |  |  |  |               fileTypeDescription: getFileTypeDescription(getFileExtension(voicFile!.path).toString()), | 
		
	
		
			
				|  |  |  |  |             ) | 
		
	
		
			
				|  |  |  |  |           : null, | 
		
	
		
			
				|  |  |  |  |       image: null, | 
		
	
		
			
				|  |  |  |  |       isImageLoaded: false, | 
		
	
		
			
				|  |  |  |  |       voice: voice, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     userChatHistory.insert(0, data); | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |     String chatData = | 
		
	
		
			
				|  |  |  |  |         '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; | 
		
	
		
			
				|  |  |  |  |     await chatHubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (searchedChats != null) { | 
		
	
		
			
				|  |  |  |  |       dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); | 
		
	
		
			
				|  |  |  |  |       if (contain.isEmpty) { | 
		
	
		
			
				|  |  |  |  |         List<String> emails = []; | 
		
	
		
			
				|  |  |  |  |         emails.add(await EmailImageEncryption().encrypt(val: userEmail!)); | 
		
	
		
			
				|  |  |  |  |         List<ChatUserImageModel> chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); | 
		
	
		
			
				|  |  |  |  |         searchedChats!.add( | 
		
	
		
			
				|  |  |  |  |           ChatUser( | 
		
	
		
			
				|  |  |  |  |             id: targetUserId, | 
		
	
		
			
				|  |  |  |  |             userName: targetUserName, | 
		
	
		
			
				|  |  |  |  |             unreadMessageCount: 0, | 
		
	
		
			
				|  |  |  |  |             email: userEmail, | 
		
	
		
			
				|  |  |  |  |             isImageLoading: false, | 
		
	
		
			
				|  |  |  |  |             image: chatImages.first.profilePicture ?? "", | 
		
	
		
			
				|  |  |  |  |             isImageLoaded: true, | 
		
	
		
			
				|  |  |  |  |             isTyping: false, | 
		
	
		
			
				|  |  |  |  |             isFav: false, | 
		
	
		
			
				|  |  |  |  |             userStatus: userStatus, | 
		
	
		
			
				|  |  |  |  |             userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), | 
		
	
		
			
				|  |  |  |  |           ), | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |         notifyListeners(); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       List<String> emails = []; | 
		
	
		
			
				|  |  |  |  |       emails.add(await EmailImageEncryption().encrypt(val: userEmail!)); | 
		
	
		
			
				|  |  |  |  |       List<ChatUserImageModel> chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); | 
		
	
		
			
				|  |  |  |  |       searchedChats!.add( | 
		
	
		
			
				|  |  |  |  |         ChatUser( | 
		
	
		
			
				|  |  |  |  |           id: targetUserId, | 
		
	
		
			
				|  |  |  |  |           userName: targetUserName, | 
		
	
		
			
				|  |  |  |  |           unreadMessageCount: 0, | 
		
	
		
			
				|  |  |  |  |           email: userEmail, | 
		
	
		
			
				|  |  |  |  |           isImageLoading: false, | 
		
	
		
			
				|  |  |  |  |           image: chatImages.first.profilePicture ?? "", | 
		
	
		
			
				|  |  |  |  |           isImageLoaded: true, | 
		
	
		
			
				|  |  |  |  |           isTyping: false, | 
		
	
		
			
				|  |  |  |  |           isFav: false, | 
		
	
		
			
				|  |  |  |  |           userStatus: userStatus, | 
		
	
		
			
				|  |  |  |  |           userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, targetUserId.toString()), | 
		
	
		
			
				|  |  |  |  |         ), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |       notifyListeners(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void playVoice( | 
		
	
		
			
				|  |  |  |  |     BuildContext context, { | 
		
	
		
			
				|  |  |  |  |     required SingleUserChatModel data, | 
		
	
		
			
				|  |  |  |  |   }) async { | 
		
	
		
			
				|  |  |  |  |     Utils.showLoading(context); | 
		
	
		
			
				|  |  |  |  |     Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? "")); | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       String path = await downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); | 
		
	
		
			
				|  |  |  |  |       logger.d(path); | 
		
	
		
			
				|  |  |  |  |       File file = File(path!); | 
		
	
		
			
				|  |  |  |  |       file.readAsBytesSync(); | 
		
	
		
			
				|  |  |  |  |       Utils.hideLoading(context); | 
		
	
		
			
				|  |  |  |  |       await playerController.preparePlayer(file.path, 1.0); | 
		
	
		
			
				|  |  |  |  |       notifyListeners(); | 
		
	
		
			
				|  |  |  |  |       playerController.startPlayer(finishMode: FinishMode.pause); | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       Utils.showToast("Cannot open file."); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<String> downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { | 
		
	
		
			
				|  |  |  |  |     String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; | 
		
	
		
			
				|  |  |  |  |     if (!await Directory(dirPath).exists()) { | 
		
	
		
			
				|  |  |  |  |       await Directory(dirPath).create(); | 
		
	
		
			
				|  |  |  |  |       await File('$dirPath/.nomedia').create(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     File file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}." + ext); | 
		
	
		
			
				|  |  |  |  |     await file.writeAsBytes(bytes); | 
		
	
		
			
				|  |  |  |  |     return file.path; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | //     data.scrollController.animateTo( | 
		
	
		
			
				|  |  |  |  | //               data.scrollController.position.maxScrollExtent, | 
		
	
		
			
				|  |  |  |  | //               duration: const Duration(milliseconds: 100), | 
		
	
		
			
				|  |  |  |  | //               curve: Curves.easeOut, | 
		
	
		
			
				|  |  |  |  | //             ); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |