import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart'; import 'package:just_audio/just_audio.dart' as JustAudio; import 'package:just_audio/just_audio.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; import 'package:mohem_flutter_app/api/my_team/my_team_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/encryption.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; import 'package:mohem_flutter_app/models/chat/create_group_request.dart' as createGroup; import 'package:mohem_flutter_app/models/chat/get_group_chat_history.dart' as groupchathistory; import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart' as groups; import 'package:mohem_flutter_app/models/chat/get_user_groups_by_id.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as userLoginToken; import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/models/chat/target_users.dart'; import 'package:mohem_flutter_app/models/my_team/get_employee_subordinates_list.dart'; import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:open_filex/open_filex.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:uuid/uuid.dart'; import 'package:flutter/material.dart' as Material; class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ScrollController scrollController = ScrollController(); TextEditingController message = TextEditingController(); TextEditingController search = TextEditingController(); TextEditingController searchGroup = TextEditingController(); List userChatHistory = [], repliedMsg = []; List? pChatHistory, searchedChats; String chatCID = ''; bool isLoading = true; bool isChatScreenActive = false; int receiverID = 0; late File selectedFile; String sFileType = ""; List favUsersList = []; int paginationVal = 0; int? cTypingUserId = 0; bool isTextMsg = false, isReplyMsg = false, isAttachmentMsg = false, isVoiceMsg = false; // Audio Recoding Work Timer? _timer; int _recodeDuration = 0; bool isRecoding = false; bool isPause = false; bool isPlaying = false; String? path; String? musicFile; late Directory appDirectory; late RecorderController recorderController; late PlayerController playerController; List getEmployeeSubordinatesList = []; List teamMembersList = []; groups.GetUserGroups userGroups = groups.GetUserGroups(); Material.TextDirection textDirection = Material.TextDirection.ltr; bool isRTL = false; String msgText = ""; //Chat Home Page Counter int chatUConvCounter = 0; late List groupChatHistory, groupChatReplyData; /// Search Provider List? chatUsersList = []; int pageNo = 1; bool disbaleChatForThisUser = false; List? uGroups = [], searchGroups = []; Future 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; Utils.showToast( userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", ); disbaleChatForThisUser = true; notifyListeners(); } } Future buildHubConnection() async { chatHubConnection = await getHubConnection(); await chatHubConnection.start(); if (kDebugMode) { logger.i("Hub Conn: Startedddddddd"); } chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); //group On message chatHubConnection.on("OnDeliveredGroupChatHistoryAsync", onGroupMsgReceived); } Future getHubConnection() async { HubConnection hub; HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Desktop&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); return hub; } void registerEvents() { chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); chatHubConnection.on("OnGetGroupUserStatusAsync", getGroupUserStatus); // // {"type":1,"target":"","arguments":[[{"id":217869,"userName":"Sultan.Khan","email":"Sultan.Khan@cloudsolutions.com.sa","phone":null,"title":"Sultan.Khan","userStatus":1,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":false,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null},{"id":15153,"userName":"Tamer.Fanasheh","email":"Tamer.F@cloudsolutions.com.sa","phone":null,"title":"Tamer Fanasheh","userStatus":2,"image":null,"unreadMessageCount":0,"userAction":3,"isPin":false,"isFav":false,"isAdmin":true,"rKey":null,"totalCount":0,"isHuaweiDevice":false,"deviceToken":null}]]} if (kDebugMode) { logger.i("All listeners registered"); } } Future getUserRecentChats() async { ChatUserModel recentChat = await ChatApiClient().getRecentChats(); ChatUserModel favUList = await ChatApiClient().getFavUsers(); // userGroups = await ChatApiClient().getGroupsByUserId(); if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; favUsersList.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); for (dynamic user in recentChat.response!) { for (dynamic favUser in favUList.response!) { if (user.id == favUser.id) { user.isFav = favUser.isFav; } } } } pChatHistory = recentChat.response ?? []; uGroups = userGroups.groupresponse ?? []; pChatHistory!.sort((ChatUser a, ChatUser b) => a.userName!.toLowerCase().compareTo(b.userName!.toLowerCase())); searchedChats = pChatHistory; isLoading = false; await invokeUserChatHistoryNotDeliveredAsync(userId: int.parse(AppState().chatDetails!.response!.id.toString())); sort(); notifyListeners(); if (searchedChats!.isNotEmpty || favUsersList.isNotEmpty) { getUserImages(); } } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } void getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false}) async { isLoading = true; if (isNewChat) userChatHistory = []; if (!loadMore) paginationVal = 0; isChatScreenActive = true; receiverID = receiverUID; Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); if (response.statusCode == 204) { if (isNewChat) { userChatHistory = []; } else if (loadMore) {} } else { if (loadMore) { List temp = getSingleUserChatModel(response.body).reversed.toList(); userChatHistory.addAll(temp); } else { userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); } } isLoading = false; notifyListeners(); if (isChatScreenActive && receiverUID == receiverID) { markRead(userChatHistory, receiverUID); } generateConvId(); } void generateConvId() async { Uuid uuid = const Uuid(); chatCID = uuid.v4(); } void markRead(List data, int receiverID) { for (SingleUserChatModel element in data!) { if (AppState().chatDetails!.response!.id! == element.targetUserId) { if (element.isSeen != null) { if (!element.isSeen!) { element.isSeen = true; dynamic data = [ { "userChatHistoryId": element.userChatHistoryId, "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, "isDelivered": true, "isSeen": true, } ]; updateUserChatHistoryStatusAsync(data); notifyListeners(); } } for (ChatUser element in searchedChats!) { if (element.id == receiverID) { element.unreadMessageCount = 0; chatUConvCounter = 0; } } } } notifyListeners(); } void updateUserChatHistoryStatusAsync(List data) { try { chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } } void updateUserChatHistoryOnMsg(List data) { try { chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } } List getSingleUserChatModel(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); List getGroupChatHistoryAsync(String str) => List.from(json.decode(str).map((x) => groupchathistory.GetGroupChatHistoryAsync.fromJson(x))); Future uploadAttachments(String userId, File file, String fileSource) async { dynamic result; try { Object? response = await ChatApiClient().uploadMedia(userId, file, fileSource); if (response != null) { result = response; } else { result = []; } } catch (e) { throw e; } return result; } void updateUserChatStatus(List? args) { dynamic items = args!.toList(); for (var cItem in items[0]) { for (SingleUserChatModel chat in userChatHistory) { if (cItem["contantNo"].toString() == chat.contantNo.toString()) { chat.isSeen = cItem["isSeen"]; chat.isDelivered = cItem["isDelivered"]; } } } notifyListeners(); } void getGroupUserStatus(List? args) { //note: need to implement this function... print(args); } void onChatSeen(List? args) { dynamic items = args!.toList(); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { // user.userStatus = items.first["userStatus"]; // } // } // notifyListeners(); } void userCountAsync(List? args) { dynamic items = args!.toList(); // logger.d(items); //logger.d("---------------------------------User Count Async -------------------------------------"); //logger.d(items); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { // user.userStatus = items.first["userStatus"]; // } // } // notifyListeners(); } void updateChatHistoryWindow(List? args) { dynamic items = args!.toList(); if (kDebugMode) { logger.i("---------------------------------Update Chat History Windows Async -------------------------------------"); } logger.d(items); // for (var user in searchedChats!) { // if (user.id == items.first["id"]) { // user.userStatus = items.first["userStatus"]; // } // } // notifyListeners(); } void chatNotDelivered(List? args) { dynamic items = args!.toList(); for (dynamic item in items[0]) { for (ChatUser element in searchedChats!) { if (element.id == item["currentUserId"]) { int? val = element.unreadMessageCount ?? 0; element.unreadMessageCount = val! + 1; } } } notifyListeners(); } void changeStatus(List? args) { dynamic items = args!.toList(); for (ChatUser user in searchedChats!) { if (user.id == items.first["id"]) { user.userStatus = items.first["userStatus"]; } } if (teamMembersList.isNotEmpty) { for (ChatUser user in teamMembersList!) { if (user.id == items.first["id"]) { user.userStatus = items.first["userStatus"]; } } } notifyListeners(); } void filter(String value) async { List? tmp = []; if (value.isEmpty || value == "") { tmp = pChatHistory; } else { for (ChatUser element in pChatHistory!) { if (element.userName!.toLowerCase().contains(value.toLowerCase())) { tmp.add(element); } } } searchedChats = tmp; notifyListeners(); } Future onMsgReceived(List? parameters) async { List 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 (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); } if (data.first.userChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { if (data.first.userChatReplyResponse!.fileTypeId == 12 || data.first.userChatReplyResponse!.fileTypeId == 4 || data.first.userChatReplyResponse!.fileTypeId == 3) { data.first.userChatReplyResponse!.image = await ChatApiClient() .downloadURL(fileName: data.first.userChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 1); data.first.userChatReplyResponse!.isImageLoaded = true; } } } } if (searchedChats != null) { dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: data.first.currentUserEmail!)); List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); searchedChats!.add( ChatUser( id: data.first.currentUserId, userName: data.first.currentUserName, email: data.first.currentUserEmail, unreadMessageCount: 0, isImageLoading: false, image: chatImages!.first.profilePicture ?? "", isImageLoaded: true, userStatus: 1, isTyping: false, userLocalDownlaodedImage: await downloadImageLocal(chatImages.first.profilePicture, data.first.currentUserId.toString()), ), ); } } setMsgTune(); if (isChatScreenActive && data.first.currentUserId == receiverID) { userChatHistory.insert(0, data.first); } else { if (searchedChats != null) { for (ChatUser user in searchedChats!) { if (user.id == data.first.currentUserId) { int tempCount = user.unreadMessageCount ?? 0; user.unreadMessageCount = tempCount + 1; } } sort(); } } List list = [ { "userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive && data.first.currentUserId == receiverID ? true : false } ]; updateUserChatHistoryOnMsg(list); invokeChatCounter(userId: AppState().chatDetails!.response!.id!); notifyListeners(); } Future onGroupMsgReceived(List? parameters) async { List data = [], temp = []; for (dynamic msg in parameters!) { // groupChatHistory.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); data.add(groupchathistory.GetGroupChatHistoryAsync.fromJson(msg)); temp = data; // data.first.currentUserId = temp.first.currentUserId; // data.first.currentUserName = temp.first.currentUserName; // // data.first.currentUserId = temp.first.currentUserId; // data.first.currentUserName = temp.first.currentUserName; if (data.first.fileTypeId == 12 || data.first.fileTypeId == 4 || data.first.fileTypeId == 3) { data.first.image = await ChatApiClient().downloadURL(fileName: data.first.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); } if (data.first.groupChatReplyResponse != null) { if (data.first.fileTypeResponse != null) { if (data.first.groupChatReplyResponse!.fileTypeId == 12 || data.first.groupChatReplyResponse!.fileTypeId == 4 || data.first.groupChatReplyResponse!.fileTypeId == 3) { data.first.groupChatReplyResponse!.image = await ChatApiClient() .downloadURL(fileName: data.first.groupChatReplyResponse!.contant!, fileTypeDescription: data.first.fileTypeResponse!.fileTypeDescription ?? "image/jpg", fileSource: 2); data.first.groupChatReplyResponse!.isImageLoaded = true; } } } } // if (searchedChats != null) { // dynamic contain = searchedChats! // .where((ChatUser element) => element.id == data.first.currentUserId); // if (contain.isEmpty) { // List emails = []; // emails.add(await EmailImageEncryption() // .encrypt(val: data.first.currentUserEmail!)); // List chatImages = // await ChatApiClient().getUsersImages(encryptedEmails: emails); // searchedChats!.add( // ChatUser( // id: data.first.currentUserId, // userName: data.first.currentUserName, // email: data.first.currentUserEmail, // unreadMessageCount: 0, // isImageLoading: false, // image: chatImages!.first.profilePicture ?? "", // isImageLoaded: true, // userStatus: 1, // isTyping: false, // userLocalDownlaodedImage: await downloadImageLocal( // chatImages.first.profilePicture, // data.first.currentUserId.toString()), // ), // ); // } // } groupChatHistory.insert(0, data.first); setMsgTune(); // if (isChatScreenActive && data.first.currentUserId == receiverID) { // } else { // if (searchedChats != null) { // for (ChatUser user in searchedChats!) { // if (user.id == data.first.currentUserId) { // int tempCount = user.unreadMessageCount ?? 0; // user.unreadMessageCount = tempCount + 1; // } // } sort(); //} //} // // List list = [ // { // "userChatHistoryId": data.first.groupId, // "TargetUserId": temp.first.currentUserId, // "isDelivered": true, // "isSeen": isChatScreenActive && data.first.currentUserId == receiverID // ? true // : false // } // ]; // updateUserChatHistoryOnMsg(list); // invokeChatCounter(userId: AppState().chatDetails!.response!.id!); notifyListeners(); } void OnSubmitChatAsync(List? parameters) { print(isChatScreenActive); print(receiverID); print(isChatScreenActive); logger.i(parameters); List 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!), ); } void onUserTyping(List? parameters) { for (ChatUser user in searchedChats!) { if (user.id == parameters![1] && parameters[0] == true) { user.isTyping = parameters[0] as bool?; Future.delayed( const Duration(seconds: 2), () { user.isTyping = false; notifyListeners(); }, ); } } notifyListeners(); } int getFileType(String value) { switch (value) { case ".pdf": return 1; case ".png": return 3; case ".txt": return 5; case ".jpg": return 12; case ".jpeg": return 4; case ".xls": return 7; case ".xlsx": return 7; case ".doc": return 6; case ".docx": return 6; case ".ppt": return 8; case ".pptx": return 8; case ".zip": return 2; case ".rar": return 2; case ".aac": return 13; case ".mp3": return 14; case ".mp4": return 16; case ".mov": return 16; case ".avi": return 16; case ".flv": return 16; default: return 0; } } String getFileTypeDescription(String value) { switch (value) { case ".pdf": return "application/pdf"; case ".png": return "image/png"; case ".txt": return "text/plain"; case ".jpg": return "image/jpg"; case ".jpeg": return "image/jpeg"; case ".ppt": return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; case ".pptx": return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; case ".doc": return "application/vnd.openxmlformats-officedocument.wordprocessingm"; case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingm"; case ".xls": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; case ".zip": return "application/octet-stream"; case ".rar": return "application/octet-stream"; case ".aac": return "audio/aac"; case ".mp3": return "audio/mp3"; case ".mp4": return "video/mp4"; case ".avi": return "video/avi"; case ".flv": return "video/flv"; case ".mov": return "video/mov"; default: return ""; } } Future sendChatToServer( {required int chatEventId, required fileTypeId, required int targetUserId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply, Uint8List? image, required bool isImageLoaded, String? userEmail, int? userStatus, File? voiceFile, required bool isVoiceAttached}) async { Uuid uuid = const Uuid(); String contentNo = uuid.v4(); String msg; if (isVoiceAttached) { msg = voiceFile!.path.split("/").last; } else { msg = message.text; logger.w(msg); } SingleUserChatModel data = SingleUserChatModel( userChatHistoryId: 0, 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: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), fileKind: "file", fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString()), ) : null, image: image, isImageLoaded: isImageLoaded, voice: isVoiceMsg ? voiceFile! : null, voiceController: isVoiceMsg ? AudioPlayer() : null); if (kDebugMode) { logger.i("model data: " + jsonEncode(data)); } userChatHistory.insert(0, data); isTextMsg = false; isReplyMsg = false; isAttachmentMsg = false; isVoiceMsg = false; sFileType = ""; message.clear(); 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: [json.decode(chatData)]); } //groupChatMessage Future sendGroupChatToServer( {required int chatEventId, required fileTypeId, required int targetGroupId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply, Uint8List? image, required bool isImageLoaded, String? userEmail, int? userStatus, File? voiceFile, required bool isVoiceAttached, required List userList}) async { Uuid uuid = const Uuid(); String contentNo = uuid.v4(); String msg; if (isVoiceAttached) { msg = voiceFile!.path.split("/").last; } else { msg = message.text; logger.w(msg); } groupchathistory.GetGroupChatHistoryAsync data = groupchathistory.GetGroupChatHistoryAsync( //userChatHistoryId: 0, chatEventId: chatEventId, chatSource: 1, contant: msg, contantNo: contentNo, conversationId: chatCID, createdDate: DateTime.now().toString(), currentUserId: AppState().chatDetails!.response!.id, currentUserName: AppState().chatDetails!.response!.userName, groupId: targetGroupId, groupName: targetUserName, isReplied: false, fileTypeId: fileTypeId, fileTypeResponse: isAttachment ? groupchathistory.FileTypeResponse( fileTypeId: fileTypeId, fileTypeName: isVoiceMsg ? getFileExtension(voiceFile!.path).toString() : getFileExtension(selectedFile.path).toString(), fileKind: "file", fileName: isVoiceMsg ? msg : selectedFile.path.split("/").last, fileTypeDescription: isVoiceMsg ? getFileTypeDescription(getFileExtension(voiceFile!.path).toString()) : getFileTypeDescription(getFileExtension(selectedFile.path).toString())) : null, image: image, isImageLoaded: isImageLoaded, voice: isVoiceMsg ? voiceFile! : null, voiceController: isVoiceMsg ? AudioPlayer() : null); if (kDebugMode) { logger.i("model data: " + jsonEncode(data)); } groupChatHistory.insert(0, data); isTextMsg = false; isReplyMsg = false; isAttachmentMsg = false; isVoiceMsg = false; sFileType = ""; message.clear(); notifyListeners(); List targetUsers = []; for (GroupUserList element in userList) { targetUsers.add(TargetUsers(isDelivered: false, isSeen: false, targetUserId: element.id, userAction: element.userAction, userStatus: element.userStatus)); } String chatData = '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId":$fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"groupId":$targetGroupId,"groupChatHistoryLineRequestList":${json.encode(targetUsers)},"chatReplyId": $chatReplyId,"conversationId":"${uuid.v4()}"}'; await chatHubConnection.invoke("AddGroupChatHistoryAsync", args: [json.decode(chatData)]); } void sendGroupChatMessage( BuildContext context, { required int targetUserId, required int userStatus, required String userEmail, required String targetUserName, required List userList, }) async { if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Text Message"); if (message.text.isEmpty) { return; } sendGroupChatToServer( chatEventId: 1, fileTypeId: null, targetGroupId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false, isImageLoaded: false, image: null, isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, userList: userList); } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Text Message as Reply"); if (message.text.isEmpty) { return; } sendGroupChatToServer( chatEventId: 1, fileTypeId: null, targetGroupId: targetUserId, targetUserName: targetUserName, chatReplyId: groupChatReplyData.first.groupChatHistoryId, isAttachment: false, isReply: true, isImageLoaded: groupChatReplyData.first.isImageLoaded!, image: groupChatReplyData.first.image, isVoiceAttached: false, voiceFile: null, userEmail: userEmail, userStatus: userStatus, userList: userList); } // Attachment else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Image Message"); Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetGroupId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: null, isReply: false, isImageLoaded: true, image: selectedFile.readAsBytesSync(), isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, userList: userList); } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Image as Reply Msg"); Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "2"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetGroupId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: repliedMsg.first.userChatHistoryId, isReply: true, isImageLoaded: true, image: selectedFile.readAsBytesSync(), isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus, userList: userList); } //Voice else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { logger.d("// Normal Voice Message"); if (!isPause) { path = await recorderController.stop(false); } if (kDebugMode) { logger.i("path:" + path!); } File voiceFile = File(path!); voiceFile.readAsBytesSync(); _timer?.cancel(); isPause = false; isPlaying = false; isRecoding = false; Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), //, targetGroupId: targetUserId, targetUserName: targetUserName, chatReplyId: null, isAttachment: true, isReply: isReplyMsg, isImageLoaded: false, voiceFile: voiceFile, isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus, userList: userList); notifyListeners(); } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { logger.d("// Voice as Reply Msg"); if (!isPause) { path = await recorderController.stop(false); } if (kDebugMode) { logger.i("path:" + path!); } File voiceFile = File(path!); voiceFile.readAsBytesSync(); _timer?.cancel(); isPause = false; isPlaying = false; isRecoding = false; Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "2"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendGroupChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetGroupId: targetUserId, targetUserName: targetUserName, chatReplyId: null, isAttachment: true, isReply: isReplyMsg, isImageLoaded: false, voiceFile: voiceFile, isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus, userList: userList); notifyListeners(); } if (searchedChats != null) { dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: userEmail)); List 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 sendChatMessage( BuildContext context, { required int targetUserId, required int userStatus, required String userEmail, required String targetUserName, }) async { if (kDebugMode) { print("====================== Values ============================"); print("Is Text " + isTextMsg.toString()); print("isReply " + isReplyMsg.toString()); print("isAttachment " + isAttachmentMsg.toString()); print("isVoice " + isVoiceMsg.toString()); } //Text if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Text Message"); if (message.text.isEmpty) { return; } sendChatToServer( chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false, isImageLoaded: false, image: null, isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus); } else if (isTextMsg && !isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Text Message as Reply"); if (message.text.isEmpty) { return; } sendChatToServer( chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: repliedMsg.first.userChatHistoryId, isAttachment: false, isReply: true, isImageLoaded: repliedMsg.first.isImageLoaded!, image: repliedMsg.first.image, isVoiceAttached: false, voiceFile: null, userEmail: userEmail, userStatus: userStatus); } // Attachment else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && !isReplyMsg) { logger.d("// Normal Image Message"); Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: null, isReply: false, isImageLoaded: true, image: selectedFile.readAsBytesSync(), isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus); } else if (!isTextMsg && isAttachmentMsg && !isVoiceMsg && isReplyMsg) { logger.d("// Image as Reply Msg"); Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile, "1"); String? ext = getFileExtension(selectedFile.path); Utils.hideLoading(context); sendChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: repliedMsg.first.userChatHistoryId, isReply: true, isImageLoaded: true, image: selectedFile.readAsBytesSync(), isVoiceAttached: false, userEmail: userEmail, userStatus: userStatus); } //Voice else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && !isReplyMsg) { logger.d("// Normal Voice Message"); if (!isPause) { path = await recorderController.stop(false); } if (kDebugMode) { logger.i("path:" + path!); } File voiceFile = File(path!); voiceFile.readAsBytesSync(); _timer?.cancel(); isPause = false; isPlaying = false; isRecoding = false; Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: null, isAttachment: true, isReply: isReplyMsg, isImageLoaded: false, voiceFile: voiceFile, isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus); notifyListeners(); } else if (!isTextMsg && !isAttachmentMsg && isVoiceMsg && isReplyMsg) { logger.d("// Voice as Reply Msg"); if (!isPause) { path = await recorderController.stop(false); } if (kDebugMode) { logger.i("path:" + path!); } File voiceFile = File(path!); voiceFile.readAsBytesSync(); _timer?.cancel(); isPause = false; isPlaying = false; isRecoding = false; Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), voiceFile, "1"); String? ext = getFileExtension(voiceFile.path); Utils.hideLoading(context); sendChatToServer( chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: null, isAttachment: true, isReply: isReplyMsg, isImageLoaded: false, voiceFile: voiceFile, isVoiceAttached: true, userEmail: userEmail, userStatus: userStatus); notifyListeners(); } if (searchedChats != null) { dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { List emails = []; emails.add(await EmailImageEncryption().encrypt(val: userEmail)); List 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 emails = []; // emails.add(await EmailImageEncryption().encrypt(val: userEmail)); // List 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 selectImageToUpload(BuildContext context) { ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { if (checkFileSize(file.path)) { selectedFile = file; isAttachmentMsg = true; isTextMsg = false; sFileType = getFileExtension(file.path)!; message.text = file.path.split("/").last; Navigator.of(context).pop(); } else { Utils.showToast("Max 1 mb size is allowed to upload"); } notifyListeners(); }); } void removeAttachment() { isAttachmentMsg = false; sFileType = ""; message.text = ''; notifyListeners(); } String? getFileExtension(String fileName) { try { if (kDebugMode) { logger.i("ext: " + "." + fileName.split('.').last); } return "." + fileName.split('.').last; } catch (e) { return null; } } bool checkFileSize(String path) { int fileSizeLimit = 5120; File f = File(path); double fileSizeInKB = f.lengthSync() / 5000; double fileSizeInMB = fileSizeInKB / 5000; if (fileSizeInKB > fileSizeLimit) { return false; } else { return true; } } String getType(String type) { switch (type) { case ".pdf": return "assets/images/pdf.svg"; case ".png": return "assets/images/png.svg"; case ".txt": return "assets/icons/chat/txt.svg"; case ".jpg": return "assets/images/jpg.svg"; case ".jpeg": return "assets/images/jpg.svg"; case ".xls": return "assets/icons/chat/xls.svg"; case ".xlsx": return "assets/icons/chat/xls.svg"; case ".doc": return "assets/icons/chat/doc.svg"; case ".docx": return "assets/icons/chat/doc.svg"; case ".ppt": return "assets/icons/chat/ppt.svg"; case ".pptx": return "assets/icons/chat/ppt.svg"; case ".zip": 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"; } } void chatReply(SingleUserChatModel data) { repliedMsg = []; data.isReplied = true; isReplyMsg = true; repliedMsg.add(data); notifyListeners(); } void groupChatReply(groupchathistory.GetGroupChatHistoryAsync data) { groupChatReplyData = []; data.isReplied = true; isReplyMsg = true; groupChatReplyData.add(data); notifyListeners(); } void closeMe() { repliedMsg = []; isReplyMsg = false; notifyListeners(); } String dateFormte(DateTime data) { DateFormat f = DateFormat('hh:mm a dd MMM yyyy', "en_US"); f.format(data); return f.format(data); } Future favoriteUser({required int userID, required int targetUserID, required bool fromSearch}) async { fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().favUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } } } for (ChatUser user in chatUsersList!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; dynamic contain = favUsersList!.where((ChatUser element) => element.id == favoriteChatUser.response!.targetUserId!); if (contain.isEmpty) { favUsersList.add(user); } } } } if (fromSearch) { for (ChatUser user in favUsersList) { if (user.id == targetUserID) { user.userLocalDownlaodedImage = null; user.isImageLoading = false; user.isImageLoaded = false; } } } notifyListeners(); } Future unFavoriteUser({required int userID, required int targetUserID}) async { fav.FavoriteChatUser favoriteChatUser = await ChatApiClient().unFavUser(userID: userID, targetUserID: targetUserID); if (favoriteChatUser.response != null) { for (ChatUser user in searchedChats!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; } } favUsersList.removeWhere( (ChatUser element) => element.id == targetUserID, ); } for (ChatUser user in chatUsersList!) { if (user.id == favoriteChatUser.response!.targetUserId!) { user.isFav = favoriteChatUser.response!.isFav; } } notifyListeners(); } void clearSelections() { searchedChats = pChatHistory; search.clear(); isChatScreenActive = false; receiverID = 0; paginationVal = 0; message.text = ''; isAttachmentMsg = false; repliedMsg = []; sFileType = ""; isReplyMsg = false; isTextMsg = false; isVoiceMsg = false; notifyListeners(); } void clearAll() { searchedChats = pChatHistory; search.clear(); isChatScreenActive = false; receiverID = 0; paginationVal = 0; message.text = ''; isTextMsg = false; isAttachmentMsg = false; isVoiceMsg = false; isReplyMsg = false; repliedMsg = []; sFileType = ""; } void disposeData() { if (!disbaleChatForThisUser) { search.clear(); isChatScreenActive = false; receiverID = 0; paginationVal = 0; message.text = ''; isTextMsg = false; isAttachmentMsg = false; isVoiceMsg = false; isReplyMsg = false; repliedMsg = []; sFileType = ""; deleteData(); favUsersList.clear(); searchedChats?.clear(); pChatHistory?.clear(); uGroups?.clear(); searchGroup?.clear(); chatHubConnection.stop(); AppState().chatDetails = null; } } void deleteData() { List exists = [], unique = []; if (searchedChats != null) exists.addAll(searchedChats!); exists.addAll(favUsersList!); Map profileMap = {}; for (ChatUser item in exists) { profileMap[item.email!] = item; } unique = profileMap.values.toList(); for (ChatUser element in unique!) { deleteFile(element.id.toString()); } } void getUserImages() async { List emails = []; List exists = [], unique = []; exists.addAll(searchedChats!); exists.addAll(favUsersList!); Map profileMap = {}; for (ChatUser item in exists) { profileMap[item.email!] = item; } unique = profileMap.values.toList(); for (ChatUser element in unique!) { emails.add(await EmailImageEncryption().encrypt(val: element.email!)); } List chatImages = await ChatApiClient().getUsersImages(encryptedEmails: emails); for (ChatUser user in searchedChats!) { for (ChatUserImageModel uImage in chatImages) { if (user.email == uImage.email) { user.image = uImage.profilePicture ?? ""; user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); user.isImageLoading = false; user.isImageLoaded = true; } } } for (ChatUser favUser in favUsersList) { for (ChatUserImageModel uImage in chatImages) { if (favUser.email == uImage.email) { favUser.image = uImage.profilePicture ?? ""; favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); favUser.isImageLoading = false; favUser.isImageLoaded = true; } } } notifyListeners(); } Future downloadImageLocal(String? encodedBytes, String userID) async { File? myfile; if (encodedBytes == null) { return myfile; } else { await deleteFile(userID); Uint8List decodedBytes = base64Decode(encodedBytes); Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); 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); return imageFile; } } Future deleteFile(String userID) async { Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); String dirPath = '${appDocumentsDirectory.path}/chat_images'; late File imageFile = File('$dirPath/$userID.jpg'); if (await imageFile.exists()) { await imageFile.delete(); } } Future downChatMedia(Uint8List bytes, String ext) async { String dir = (await getApplicationDocumentsDirectory()).path; File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); await file.writeAsBytes(bytes); return file.path; } void setMsgTune() async { JustAudio.AudioPlayer player = JustAudio.AudioPlayer(); await player.setVolume(1.0); String audioAsset = ""; if (Platform.isAndroid) { audioAsset = "assets/audio/pulse_tone_android.mp3"; } else { audioAsset = "assets/audio/pulse_tune_ios.caf"; } try { await player.setAsset(audioAsset); await player.load(); player.play(); } catch (e) { print("Error: $e"); } } Future getChatMedia(BuildContext context, {required String fileName, required String fileTypeName, required int fileTypeID, required int fileSource}) async { Utils.showLoading(context); if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2 || fileTypeID == 16) { Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName), fileSource: fileSource); try { String path = await downChatMedia(encodedString, fileTypeName ?? ""); Utils.hideLoading(context); OpenFilex.open(path); } catch (e) { Utils.showToast("Cannot open file."); } } } void onNewChatConversion(List? params) { dynamic items = params!.toList(); chatUConvCounter = items[0]["singleChatCount"] ?? 0; notifyListeners(); } Future invokeChatCounter({required int userId}) async { await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); return ""; } void userTypingInvoke({required int currentUser, required int reciptUser}) async { await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); } void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { var data = json.decode(json.encode(groupDetails.groupUserList)); await chatHubConnection.invoke("GroupTypingAsync", args: ["${groupDetails.adminUser!.userName}", data, groupId]); } //////// Audio Recoding Work //////////////////// Future 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() ..androidEncoder = AndroidEncoder.aac ..androidOutputFormat = AndroidOutputFormat.mpeg4 ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC ..sampleRate = 6000 ..updateFrequency = const Duration(milliseconds: 100) ..bitRate = 18000; playerController = PlayerController(); } void disposeAudio() { isRecoding = false; isPlaying = false; isPause = false; isVoiceMsg = false; recorderController.dispose(); playerController.dispose(); } void startRecoding(BuildContext context) async { await Permission.microphone.request().then((PermissionStatus status) { if (status.isPermanentlyDenied) { Utils.confirmDialog( context, "The app needs microphone access to be able to record audio.", onTap: () { Navigator.of(context).pop(); openAppSettings(); }, ); } else if (status.isDenied) { Utils.confirmDialog( context, "The app needs microphone access to be able to record audio.", onTap: () { Navigator.of(context).pop(); openAppSettings(); }, ); } else if (status.isGranted) { sRecoding(); } else { startRecoding(context); } }); } void sRecoding() async { isVoiceMsg = true; recorderController.reset(); await recorderController.record(path: path); _recodeDuration = 0; _startTimer(); isRecoding = !isRecoding; notifyListeners(); } Future _startTimer() async { _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) async { _recodeDuration++; if (_recodeDuration <= 59) { applyCounter(); } else { pauseRecoding(); } }); } void applyCounter() { buildTimer(); notifyListeners(); } Future pauseRecoding() async { isPause = true; isPlaying = true; recorderController.pause(); path = await recorderController.stop(false); File file = File(path!); file.readAsBytesSync(); path = file.path; await playerController.preparePlayer(path:file.path, volume: 1.0); _timer?.cancel(); notifyListeners(); } Future deleteRecoding() async { _recodeDuration = 0; _timer?.cancel(); if (path == null) { path = await recorderController.stop(true); } else { await recorderController.stop(true); } if (path != null && path!.isNotEmpty) { File delFile = File(path!); double fileSizeInKB = delFile.lengthSync() / 1024; double fileSizeInMB = fileSizeInKB / 1024; if (kDebugMode) { debugPrint("Deleted file size: ${delFile.lengthSync()}"); debugPrint("Deleted file size in KB: " + fileSizeInKB.toString()); debugPrint("Deleted file size in MB: " + fileSizeInMB.toString()); } if (await delFile.exists()) { delFile.delete(); } isPause = false; isRecoding = false; isPlaying = false; isVoiceMsg = false; notifyListeners(); } } String buildTimer() { String minutes = _formatNum(_recodeDuration ~/ 60); String seconds = _formatNum(_recodeDuration % 60); return '$minutes : $seconds'; } String _formatNum(int number) { String numberStr = number.toString(); if (number < 10) { numberStr = '0' + numberStr; } return numberStr; } Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { File file; try { String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; if (!await Directory(dirPath).exists()) { await Directory(dirPath).create(); await File('$dirPath/.nomedia').create(); } file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); await file.writeAsBytes(bytes); } catch (e) { if (kDebugMode) { print(e); } file = File(""); } return file; } void scrollToMsg(SingleUserChatModel data) { if (data.userChatReplyResponse != null && data.userChatReplyResponse!.userChatHistoryId != null) { int index = userChatHistory.indexWhere((SingleUserChatModel element) => element.userChatHistoryId == data.userChatReplyResponse!.userChatHistoryId); if (index >= 1) { double contentSize = scrollController.position.viewportDimension + scrollController.position.maxScrollExtent; double target = contentSize * index / userChatHistory.length; scrollController.position.animateTo( target, duration: const Duration(seconds: 1), curve: Curves.easeInOut, ); } } } Future getTeamMembers() async { teamMembersList = []; isLoading = true; if (AppState().getemployeeSubordinatesList.isNotEmpty) { getEmployeeSubordinatesList = AppState().getemployeeSubordinatesList; for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { if (element.eMPLOYEEEMAILADDRESS != null) { if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { teamMembersList.add( ChatUser( id: int.parse(element.eMPLOYEENUMBER!), email: element.eMPLOYEEEMAILADDRESS, userName: element.eMPLOYEENAME, phone: element.eMPLOYEEMOBILENUMBER, userStatus: 0, unreadMessageCount: 0, isFav: false, isTyping: false, isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } } } } else { getEmployeeSubordinatesList = await MyTeamApiClient().getEmployeeSubordinates("", "", ""); AppState().setemployeeSubordinatesList = getEmployeeSubordinatesList; for (GetEmployeeSubordinatesList element in getEmployeeSubordinatesList) { if (element.eMPLOYEEEMAILADDRESS != null) { if (element.eMPLOYEEEMAILADDRESS!.isNotEmpty) { teamMembersList.add( ChatUser( id: int.parse(element.eMPLOYEENUMBER!), email: element.eMPLOYEEEMAILADDRESS, userName: element.eMPLOYEENAME, phone: element.eMPLOYEEMOBILENUMBER, userStatus: 0, unreadMessageCount: 0, isFav: false, isTyping: false, isImageLoading: false, image: element.eMPLOYEEIMAGE ?? "", isImageLoaded: element.eMPLOYEEIMAGE == null ? false : true, userLocalDownlaodedImage: element.eMPLOYEEIMAGE == null ? null : await downloadImageLocal(element.eMPLOYEEIMAGE ?? "", element.eMPLOYEENUMBER!), ), ); } } } } for (ChatUser user in searchedChats!) { for (ChatUser teamUser in teamMembersList!) { if (user.id == teamUser.id) { teamUser.userStatus = user.userStatus; } } } isLoading = false; notifyListeners(); } void inputBoxDirection(String val) { if (val.isNotEmpty) { isTextMsg = true; } else { isTextMsg = false; } msgText = val; notifyListeners(); } void onDirectionChange(bool val) { isRTL = val; notifyListeners(); } Material.TextDirection getTextDirection(String v) { String str = v.trim(); if (str.isEmpty) return Material.TextDirection.ltr; int firstUnit = str.codeUnitAt(0); if (firstUnit > 0x0600 && firstUnit < 0x06FF || firstUnit > 0x0750 && firstUnit < 0x077F || firstUnit > 0x07C0 && firstUnit < 0x07EA || firstUnit > 0x0840 && firstUnit < 0x085B || firstUnit > 0x08A0 && firstUnit < 0x08B4 || firstUnit > 0x08E3 && firstUnit < 0x08FF || firstUnit > 0xFB50 && firstUnit < 0xFBB1 || firstUnit > 0xFBD3 && firstUnit < 0xFD3D || firstUnit > 0xFD50 && firstUnit < 0xFD8F || firstUnit > 0xFD92 && firstUnit < 0xFDC7 || firstUnit > 0xFDF0 && firstUnit < 0xFDFC || firstUnit > 0xFE70 && firstUnit < 0xFE74 || firstUnit > 0xFE76 && firstUnit < 0xFEFC || firstUnit > 0x10800 && firstUnit < 0x10805 || firstUnit > 0x1B000 && firstUnit < 0x1B0FF || firstUnit > 0x1D165 && firstUnit < 0x1D169 || firstUnit > 0x1D16D && firstUnit < 0x1D172 || firstUnit > 0x1D17B && firstUnit < 0x1D182 || firstUnit > 0x1D185 && firstUnit < 0x1D18B || firstUnit > 0x1D1AA && firstUnit < 0x1D1AD || firstUnit > 0x1D242 && firstUnit < 0x1D244) { return Material.TextDirection.rtl; } return Material.TextDirection.ltr; } void openChatByNoti(BuildContext context) async { SingleUserChatModel nUser = SingleUserChatModel(); Utils.saveStringFromPrefs("isAppOpendByChat", "false"); if (await Utils.getStringFromPrefs("notificationData") != "null") { nUser = SingleUserChatModel.fromJson(jsonDecode(await Utils.getStringFromPrefs("notificationData"))); Utils.saveStringFromPrefs("notificationData", "null"); Future.delayed(const Duration(seconds: 2)); for (ChatUser user in searchedChats!) { if (user.id == nUser.targetUserId) { Navigator.pushNamed(context, AppRoutes.chatDetailed, arguments: ChatDetailedScreenParams(user, false)); return; } } } Utils.saveStringFromPrefs("notificationData", "null"); } //group chat functions added here void filterGroups(String value) async { // filter function added here. List tmp = []; if (value.isEmpty || value == "") { tmp = userGroups.groupresponse!; } else { for (groups.GroupResponse element in uGroups!) { if (element.groupName!.toLowerCase().contains(value.toLowerCase())) { tmp.add(element); } } } uGroups = tmp; notifyListeners(); } Future deleteGroup(GroupResponse groupDetails) async { isLoading = true; await ChatApiClient().deleteGroup(groupDetails.groupId); userGroups = await ChatApiClient().getGroupsByUserId(); uGroups = userGroups.groupresponse; isLoading = false; notifyListeners(); } Future getGroupChatHistory(groups.GroupResponse groupDetails) async { isLoading = true; groupChatHistory = await ChatApiClient().getGroupChatHistory(groupDetails.groupId, groupDetails.groupUserList as List); isLoading = false; notifyListeners(); } void updateGroupAdmin(int? groupId, List groupUserList) async { isLoading = true; await ChatApiClient().updateGroupAdmin(groupId, groupUserList); isLoading = false; notifyListeners(); } Future addGroupAndUsers(createGroup.CreateGroupRequest request) async { isLoading = true; var groups = await ChatApiClient().addGroupAndUsers(request); userGroups.groupresponse!.add(GroupResponse.fromJson(json.decode(groups)['response'])); isLoading = false; notifyListeners(); } Future updateGroupAndUsers(createGroup.CreateGroupRequest request) async { isLoading = true; await ChatApiClient().updateGroupAndUsers(request); userGroups = await ChatApiClient().getGroupsByUserId(); uGroups = userGroups.groupresponse; isLoading = false; notifyListeners(); } }