From 8ba3dcf43bf1f35b6e734811bc3790919e0a6862 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 10 Nov 2022 16:00:55 +0300 Subject: [PATCH 1/2] Chat Fixes & Favorite Api Implementation --- assets/icons/chat/doc.svg | 54 ++ assets/icons/chat/ppt.svg | 51 ++ assets/icons/chat/txt.svg | 51 ++ assets/icons/chat/xls.svg | 53 ++ assets/icons/chat/zip.svg | 51 ++ lib/api/chat/chat_provider_model.dart | 461 +++++++++++++++--- lib/classes/colors.dart | 1 + lib/classes/consts.dart | 9 +- lib/extensions/string_extensions.dart | 2 +- ...t => get_single_user_chat_list_model.dart} | 77 ++- ...e_user_favotire_unfavorite_chat_model.dart | 53 ++ lib/ui/chat/chat_bubble.dart | 85 ++-- lib/ui/chat/chat_detailed_screen.dart | 306 +++++++++--- lib/ui/chat/chat_home.dart | 121 +++-- .../search_employee_bottom_sheet.dart | 88 +++- lib/widgets/image_picker.dart | 9 +- pubspec.yaml | 4 + 17 files changed, 1251 insertions(+), 225 deletions(-) create mode 100644 assets/icons/chat/doc.svg create mode 100644 assets/icons/chat/ppt.svg create mode 100644 assets/icons/chat/txt.svg create mode 100644 assets/icons/chat/xls.svg create mode 100644 assets/icons/chat/zip.svg rename lib/models/chat/{get_single_user_chat_list_Model.dart => get_single_user_chat_list_model.dart} (58%) create mode 100644 lib/models/chat/make_user_favotire_unfavorite_chat_model.dart diff --git a/assets/icons/chat/doc.svg b/assets/icons/chat/doc.svg new file mode 100644 index 0000000..1f678df --- /dev/null +++ b/assets/icons/chat/doc.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/chat/ppt.svg b/assets/icons/chat/ppt.svg new file mode 100644 index 0000000..5134010 --- /dev/null +++ b/assets/icons/chat/ppt.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/chat/txt.svg b/assets/icons/chat/txt.svg new file mode 100644 index 0000000..bbaf693 --- /dev/null +++ b/assets/icons/chat/txt.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/chat/xls.svg b/assets/icons/chat/xls.svg new file mode 100644 index 0000000..325f974 --- /dev/null +++ b/assets/icons/chat/xls.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/chat/zip.svg b/assets/icons/chat/zip.svg new file mode 100644 index 0000000..9aaaf6b --- /dev/null +++ b/assets/icons/chat/zip.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index bcb748c..b3f37ab 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -1,8 +1,9 @@ import 'dart:convert'; - +import 'dart:io'; +import 'dart:math'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart'; import 'package:logging/logging.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; @@ -10,11 +11,14 @@ import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; 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_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as login; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; +import 'package:mohem_flutter_app/widgets/image_picker.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:logger/logger.dart' as L; +import 'package:uuid/uuid.dart'; class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List userChatHistory = []; @@ -22,8 +26,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { late HubConnection hubConnection; L.Logger logger = L.Logger(); TextEditingController message = TextEditingController(); - ScrollController scrollController = ScrollController(); bool isLoading = true; + bool isChatScreenActive = false; + late File selectedFile; + bool isFileSelected = false; + String sFileType = ""; + bool isMsgReply = false; + List repliedMsg = []; + int paginationVal = 0; Future getUserAutoLoginToken() async { String userName = AppState().memberInformationList!.eMPLOYEEEMAILADDRESS!.split("@").first.toString(); @@ -40,9 +50,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { token: AppState().chatDetails!.response!.token, ); return searchUserJsonModel(response.body); - logger.d(response.body); - isLoading = false; - notifyListeners(); } List searchUserJsonModel(String str) => List.from(json.decode(str).map((x) => ChatUser.fromJson(x))); @@ -52,25 +59,52 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatRecentUrl}", token: AppState().chatDetails!.response!.token, ); + + logger.d(AppState().chatDetails!.response!.token); ChatUserModel recentChat = userToList(response.body); + + Response favRes = await ApiClient().getJsonForResponse( + "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatFavoriteUsers}${AppState().chatDetails!.response!.id}", + token: AppState().chatDetails!.response!.token, + ); + print("============================== Fav Response ====================================="); + ChatUserModel favUsersList = userToList(favRes.body); + for (var user in recentChat.response!) { + for (var favUser in favUsersList.response!) { + logger.d(favUser.isFav); + if (user.id == favUser.id) { + user.isFav = favUser.isFav; + } + } + } + pChatHistory = recentChat.response; searchedChats = pChatHistory; isLoading = false; notifyListeners(); } - void getSingleUserChatHistory({required String senderUID, required int receiverUID, required String pagination}) async { + void getSingleUserChatHistory({required String senderUID, required int receiverUID, required bool loadMore}) async { isLoading = true; + if (!loadMore) paginationVal = 0; + logger.d(paginationVal); + isChatScreenActive = true; Response response = await ApiClient().getJsonForResponse( - "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSingleUserHistoryUrl}/$senderUID/$receiverUID/$pagination", + "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSingleUserHistoryUrl}/$senderUID/$receiverUID/$paginationVal", token: AppState().chatDetails!.response!.token, ); - logger.d(response.statusCode); - print(response.body); + + logger.d(response.body); if (response.statusCode == 204) { - userChatHistory = []; + if (!loadMore) userChatHistory = []; + Utils.showToast("No More Data To Load"); } else { - userChatHistory = getSingleUserChatModel(response.body); + if (loadMore) { + List temp = getSingleUserChatModel(response.body); + userChatHistory.insertAll(0, temp); + } else { + userChatHistory = getSingleUserChatModel(response.body); + } } isLoading = false; notifyListeners(); @@ -80,6 +114,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ChatUserModel userToList(String str) => ChatUserModel.fromJson(json.decode(str)); + Future uploadAttachments(String userId, File file) async { + dynamic result; + dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatMediaImageUploadUrl}')); + request.fields.addAll({'userId': userId, 'fileSource': '1'}); + request.files.add(await MultipartFile.fromPath('files', file.path)); + request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); + try { + StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + result = jsonDecode(await response.stream.bytesToString()); + } else { + result = []; + } + } catch (e) {} + return result; + } + Future buildHubConnection() async { HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hubConnection = await HubConnectionBuilder() @@ -113,7 +164,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { hubConnection.on("OnUserTypingAsync", onUserTyping); // hubConnection.on("OnUserCountAsync", userCountAsync); // hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); - // hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); + hubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); hubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); } else { hubConnection.on("OnUpdateUserStatusAsync", changeStatus); @@ -219,7 +270,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } userChatHistory.add(data.first); notifyListeners(); - scrollDown(); + logger.d(isChatScreenActive); + // if (isChatScreenActive) scrollDown(); } void onUserTyping(List? parameters) { @@ -228,7 +280,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { 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), () { @@ -241,12 +292,122 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } - void sendChatMessage(String chatMessage, int targetUserId, String targetUserName) async { - if (chatMessage == null || chatMessage.isEmpty) { - return; + 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; + default: + return 0; } + } - var contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + 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"; + default: + return ""; + } + } + + // void scrollDown() { + // scrollController.animateTo( + // scrollController.position.maxScrollExtent + 100, + // curve: Curves.easeOut, + // duration: const Duration(milliseconds: 300), + // ); + // notifyListeners(); + // } + + Future sendChatToServer( + {required int chatEventId, required fileTypeId, required int targetUserId, required String targetUserName, required chatReplyId, required bool isAttachment, required bool isReply}) async { + Uuid uuid = const Uuid(); + SingleUserChatModel data = SingleUserChatModel( + chatEventId: chatEventId, + chatSource: 1, + contant: message.text, + contantNo: uuid.v4(), + conversationId: uuid.v4(), + 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: getFileType(getFileExtension(selectedFile.path).toString()), + fileKind: getFileExtension(selectedFile.path), + fileName: selectedFile.path.split("/").last, + fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), + ) + : null, + ); + String chatData = + '{"contant":"${message.text}","contantNo":"${uuid.v4()}","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"${uuid.v4()}"}'; + await hubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); + userChatHistory.add(data); + isFileSelected = false; + isMsgReply = false; + sFileType = ""; + message.clear(); + notifyListeners(); + // scrollDown(); + } + + void sendChatMessage(int targetUserId, String targetUserName) async { + dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { searchedChats!.add( ChatUser( @@ -254,51 +415,233 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { userName: targetUserName, ), ); + notifyListeners(); + } + if (!isFileSelected && !isMsgReply) { + logger.d("Normal Text Message"); + if (message.text == null || message.text.isEmpty) { + return; + } + sendChatToServer(chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false); + } + if (isFileSelected && !isMsgReply) { + logger.d("Normal Attachment Message"); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); + String? ext = getFileExtension(selectedFile.path); + sendChatToServer(chatEventId: 2, fileTypeId: getFileType(ext.toString()), targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: true, chatReplyId: null, isReply: false); + } + if (!isFileSelected && isMsgReply) { + logger.d("Normal Text Message With Reply"); + if (message.text == null || message.text.isEmpty) { + return; + } + sendChatToServer( + chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: repliedMsg.first.userChatHistoryId, isAttachment: false, isReply: true); +//chatReplyId + } + if (isFileSelected && isMsgReply) { + logger.d("Attachment Message With Reply"); + logger.d(repliedMsg.first.userChatHistoryId); + dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); + String? ext = getFileExtension(selectedFile.path); + sendChatToServer( + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: repliedMsg.first.userChatHistoryId, + isReply: true); } - String chatData = - '{"contant":"$chatMessage","contantNo":"8a129295-36d7-7185-5d34-cc4eec7bcba4","chatEventId":1,"fileTypeId":null,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"conversationId":"715f8b13-96ee-cd36-cb07-5a982a219982"}'; - await hubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); - userChatHistory.add( - SingleUserChatModel( - chatEventId: 1, - chatSource: 1, - contant: chatMessage, - contantNo: "8a129295-36d7-7185-5d34-cc4eec7bcba4", - conversationId: "715f8b13-96ee-cd36-cb07-5a982a219982", - createdDate: DateTime.now(), - currentUserId: AppState().chatDetails!.response!.id, - currentUserName: AppState().chatDetails!.response!.userName, - targetUserId: targetUserId, - targetUserName: targetUserName, - ), - ); - message.clear(); + // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); + // if (contain.isEmpty) { + // searchedChats!.add( + // ChatUser( + // id: targetUserId, + // userName: targetUserName, + // ), + // ); + // notifyListeners(); + // } + // Uuid uuid = const Uuid(); + // dynamic fileID = fileUploadResponse.isEmpty ? null : getFileType(chatMessage); + // SingleUserChatModel data = SingleUserChatModel( + // chatEventId: fileUploadResponse.isEmpty ? 1 : 2, + // chatSource: 1, + // contant: chatMessage, + // contantNo: uuid.v4(), + // conversationId: uuid.v4(), + // createdDate: DateTime.now(), + // currentUserId: AppState().chatDetails!.response!.id, + // currentUserName: AppState().chatDetails!.response!.userName, + // targetUserId: targetUserId, + // targetUserName: targetUserName, + // fileTypeId: fileID, + // isReplied: false, + // // fileTypeResponse: FileTypeResponse( + // // fileTypeId: 0, + // // fileTypeDescription: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"], + // // fileName: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"], + // // fileKind: "image", + // // fileTypeName: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"].toString().split(".").last), + // ); + // + // String chatData = + // '{"contant":"$chatMessage","contantNo":"${uuid.v4()}","chatEventId":${fileUploadResponse.isEmpty ? 1 : 2},"fileTypeId": $fileID,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"conversationId":"${uuid.v4()}"}'; + // await hubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); + // userChatHistory.add(data); + // message.clear(); + // notifyListeners(); + // scrollDown(); + } + + void scrollListener() { + if (userChatHistory.length < paginationVal) { + print("Get New Data"); + } + } + + void selectImageToUpload(BuildContext context) { + ImageOptions.showImageOptionsNew(context, true, (String image, File file) async { + if (checkFileSize(file.path)) { + selectedFile = file; + isFileSelected = true; + 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"); + } + //Utils.showLoading(context); + notifyListeners(); + //Utils.hideLoading(context); + // Utils.showLoading(context); + // await m.uploadAttachments(AppState().chatDetails!.response!.id.toString(), file).then((value) { + // if (value == null) { + // m.logger.d("Returned EMPTY"); + // } else { + // m.sendChatMessage(value.isEmpty ? m.message.text : value.first["filePath"], userDetails["targetUser"].id, userDetails["targetUser"].userName, value); + // } + // }); + // Utils.hideLoading(context); + }); + } + + void removeAttachment() { + isFileSelected = false; + sFileType = ""; + message.text = ''; notifyListeners(); - scrollDown(); } - void scrollDown() { - scrollController.animateTo( - scrollController.position.maxScrollExtent + 100, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300), - ); + String? getFileExtension(String fileName) { + try { + return "." + fileName.split('.').last; + } catch (e) { + return null; + } + } + + bool checkFileSize(String path) { + int fileSizeLimit = 1024; + File f = File(path); + double fileSizeInKB = f.lengthSync() / 1024; + double fileSizeInMB = fileSizeInKB / 1024; + 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"; + default: + return "assets/images/thumb.svg"; + } + } + + void chatReply(SingleUserChatModel data) { + repliedMsg = []; + data.isReplied = true; + isMsgReply = true; + repliedMsg.add(data); + notifyListeners(); + } + + void closeMe() { + repliedMsg = []; + isMsgReply = false; + notifyListeners(); + } + + String dateFormte(DateTime data) { + DateFormat f = new DateFormat('hh:mm a dd MMM yyyy'); + f.format(data); + return f.format(data); + } + + Future favoriteUser({required int userID, required int targetUserID}) async { + Response response = + await ApiClient().postJsonForResponse("${ApiConsts.chatServerBaseApiUrl}FavUser/addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); + fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); + if (favoriteChatUser.response != null) { + for (var user in searchedChats!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + } + } + } notifyListeners(); } -// void _scrollListener() { -// if (scrollController.position.extentAfter.toInt() <= 0 && canCallApi) { -// if (userChatHistory.length < _ayatTangheemTypeMapped.totalItemsCount) { -// currentPageNo++; -// if (widget.tangheemQuery == null) { -// getTangheemData(); -// } else { -// getTangheemDataByKeyword(); -// } -// } -// canCallApi = false; -// } -// } + Future unFavoriteUser({required int userID, required int targetUserID}) async { + Response response = await ApiClient() + .postJsonForResponse("${ApiConsts.chatServerBaseApiUrl}FavUser/deleteFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); + fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); + if (favoriteChatUser.response != null) { + for (var user in searchedChats!) { + if (user.id == favoriteChatUser.response!.targetUserId!) { + user.isFav = favoriteChatUser.response!.isFav; + } + } + } + notifyListeners(); + } + void clearSelections() { + isChatScreenActive = false; + paginationVal = 0; + message.text = ''; + isFileSelected = false; + repliedMsg = []; + sFileType = ""; + } } diff --git a/lib/classes/colors.dart b/lib/classes/colors.dart index e670bbc..5e390c7 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -58,4 +58,5 @@ class MyColors { static const Color greyC4Color = Color(0xffC4C4C4); static const Color grey35Color = Color(0xff535353); static const Color grey9DColor = Color(0xff9D9D9D); + static const Color grey71Color = Color(0xff717171); } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index e82c30a..c98d136 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,7 +1,7 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server - static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server - // static String baseUrl = "https://hmgwebservices.com"; // Live server + //static String baseUrl = "https://uat.hmgwebservices.com"; // UAT server + static String baseUrl = "https://hmgwebservices.com"; // Live server static String baseUrlServices = baseUrl + "/Services/"; // server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String utilitiesRest = baseUrlServices + "Utilities.svc/REST/"; @@ -16,7 +16,12 @@ class ApiConsts { static String chatSearchMember = "user/getUserWithStatusAndFavAsync/"; static String chatRecentUrl = "UserChatHistory/getchathistorybyuserid"; //For a Mem static String chatSingleUserHistoryUrl = "UserChatHistory/GetUserChatHistory"; + static String chatMediaImageUploadUrl = "shared/upload"; + static String chatFavoriteUsers = "FavUser/getFavUserById/"; + //https://apiderichat.hmg.com/api/FavUser/getFavUserById/42062 +//https://apiderichat.hmg.com/api/shared/upload // 42062 is CurrentUserID and 36745 is targetUserID and 0 is For Pagination + // static String chatSearchMember = "https://apiderichat.hmg.com/api/user/getUserWithStatusAndFavAsync/aamir.muhammad/36239"; } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 37f41ae..9af8f2b 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -18,7 +18,7 @@ extension EmailValidator on String { Widget toText10({Color? color, bool isBold = false, int? maxlines, FontStyle? fontStyle}) => Text( this, - //maxLines: maxlines, + maxLines: maxlines, style: TextStyle(fontSize: 10, fontStyle: fontStyle ?? FontStyle.normal, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4), ); diff --git a/lib/models/chat/get_single_user_chat_list_Model.dart b/lib/models/chat/get_single_user_chat_list_model.dart similarity index 58% rename from lib/models/chat/get_single_user_chat_list_Model.dart rename to lib/models/chat/get_single_user_chat_list_model.dart index 0e3cb22..6a35f0e 100644 --- a/lib/models/chat/get_single_user_chat_list_Model.dart +++ b/lib/models/chat/get_single_user_chat_list_model.dart @@ -1,3 +1,9 @@ +import 'dart:convert'; + +List singleUserChatModelFromJson(String str) => List.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); + +String singleUserChatModelToJson(List data) => json.encode(List.from(data.map((x) => x.toJson()))); + class SingleUserChatModel { SingleUserChatModel({ this.userChatHistoryId, @@ -19,6 +25,7 @@ class SingleUserChatModel { this.conversationId, this.fileTypeResponse, this.userChatReplyResponse, + this.isReplied, }); int? userChatHistoryId; @@ -29,17 +36,18 @@ class SingleUserChatModel { String? currentUserName; int? targetUserId; String? targetUserName; - dynamic encryptedTargetUserId; - dynamic encryptedTargetUserName; + String? encryptedTargetUserId; + String? encryptedTargetUserName; int? chatEventId; - dynamic fileTypeId; + dynamic? fileTypeId; bool? isSeen; bool? isDelivered; DateTime? createdDate; int? chatSource; String? conversationId; FileTypeResponse? fileTypeResponse; - dynamic userChatReplyResponse; + UserChatReplyResponse? userChatReplyResponse; + bool? isReplied; factory SingleUserChatModel.fromJson(Map json) => SingleUserChatModel( userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], @@ -50,8 +58,8 @@ class SingleUserChatModel { currentUserName: json["currentUserName"] == null ? null : json["currentUserName"], targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], - encryptedTargetUserId: json["encryptedTargetUserId"], - encryptedTargetUserName: json["encryptedTargetUserName"], + encryptedTargetUserId: json["encryptedTargetUserId"] == null ? null : json["encryptedTargetUserId"], + encryptedTargetUserName: json["encryptedTargetUserName"] == null ? null : json["encryptedTargetUserName"], chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], fileTypeId: json["fileTypeId"], isSeen: json["isSeen"] == null ? null : json["isSeen"], @@ -60,7 +68,8 @@ class SingleUserChatModel { chatSource: json["chatSource"] == null ? null : json["chatSource"], conversationId: json["conversationId"] == null ? null : json["conversationId"], fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), - userChatReplyResponse: json["userChatReplyResponse"], + userChatReplyResponse: json["userChatReplyResponse"] == null ? null : UserChatReplyResponse.fromJson(json["userChatReplyResponse"]), + isReplied: false, ); Map toJson() => { @@ -72,8 +81,8 @@ class SingleUserChatModel { "currentUserName": currentUserName == null ? null : currentUserName, "targetUserId": targetUserId == null ? null : targetUserId, "targetUserName": targetUserName == null ? null : targetUserName, - "encryptedTargetUserId": encryptedTargetUserId, - "encryptedTargetUserName": encryptedTargetUserName, + "encryptedTargetUserId": encryptedTargetUserId == null ? null : encryptedTargetUserId, + "encryptedTargetUserName": encryptedTargetUserName == null ? null : encryptedTargetUserName, "chatEventId": chatEventId == null ? null : chatEventId, "fileTypeId": fileTypeId, "isSeen": isSeen == null ? null : isSeen, @@ -82,7 +91,7 @@ class SingleUserChatModel { "chatSource": chatSource == null ? null : chatSource, "conversationId": conversationId == null ? null : conversationId, "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), - "userChatReplyResponse": userChatReplyResponse, + "userChatReplyResponse": userChatReplyResponse == null ? null : userChatReplyResponse!.toJson(), }; } @@ -117,3 +126,51 @@ class FileTypeResponse { "fileName": fileName, }; } + +class UserChatReplyResponse { + UserChatReplyResponse({ + this.userChatHistoryId, + this.chatEventId, + this.contant, + this.contantNo, + this.fileTypeId, + this.createdDate, + this.targetUserId, + this.targetUserName, + this.fileTypeResponse, + }); + + int? userChatHistoryId; + int? chatEventId; + String? contant; + String? contantNo; + dynamic? fileTypeId; + DateTime? createdDate; + int? targetUserId; + String? targetUserName; + FileTypeResponse? fileTypeResponse; + + factory UserChatReplyResponse.fromJson(Map json) => UserChatReplyResponse( + userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], + chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], + contant: json["contant"] == null ? null : json["contant"], + contantNo: json["contantNo"] == null ? null : json["contantNo"], + fileTypeId: json["fileTypeId"], + createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + targetUserName: json["targetUserName"] == null ? null : json["targetUserName"], + fileTypeResponse: json["fileTypeResponse"] == null ? null : FileTypeResponse.fromJson(json["fileTypeResponse"]), + ); + + Map toJson() => { + "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, + "chatEventId": chatEventId == null ? null : chatEventId, + "contant": contant == null ? null : contant, + "contantNo": contantNo == null ? null : contantNo, + "fileTypeId": fileTypeId, + "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), + "targetUserId": targetUserId == null ? null : targetUserId, + "targetUserName": targetUserName == null ? null : targetUserName, + "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), + }; +} diff --git a/lib/models/chat/make_user_favotire_unfavorite_chat_model.dart b/lib/models/chat/make_user_favotire_unfavorite_chat_model.dart new file mode 100644 index 0000000..64eb6b1 --- /dev/null +++ b/lib/models/chat/make_user_favotire_unfavorite_chat_model.dart @@ -0,0 +1,53 @@ +// To parse this JSON data, do +// +// final favoriteChatUser = favoriteChatUserFromJson(jsonString); + +import 'dart:convert'; + +class FavoriteChatUser { + FavoriteChatUser({ + this.response, + this.errorResponses, + }); + + Response? response; + dynamic? errorResponses; + + factory FavoriteChatUser.fromRawJson(String str) => FavoriteChatUser.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory FavoriteChatUser.fromJson(Map json) => FavoriteChatUser( + response: json["response"] == null ? null : Response.fromJson(json["response"]), + errorResponses: json["errorResponses"], + ); + + Map toJson() => { + "response": response == null ? null : response!.toJson(), + "errorResponses": errorResponses, + }; +} + +class Response { + Response({ + this.targetUserId, + this.isFav, + }); + + int? targetUserId; + bool? isFav; + + factory Response.fromRawJson(String str) => Response.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Response.fromJson(Map json) => Response( + targetUserId: json["targetUserId"] == null ? null : json["targetUserId"], + isFav: json["isFav"] == null ? null : json["isFav"], + ); + + Map toJson() => { + "targetUserId": targetUserId == null ? null : targetUserId, + "isFav": isFav == null ? null : isFav, + }; +} diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index 74d2e2b..1e8aec4 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -2,82 +2,105 @@ import 'package:flutter/material.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:sizer/sizer.dart'; class ChatBubble extends StatelessWidget { const ChatBubble( {Key? key, required this.text, + required this.replyText, required this.isCurrentUser, required this.isSeen, required this.isDelivered, - required this.dateTime}) + required this.dateTime, + required this.isReplied, + required this.userName}) : super(key: key); final String text; + final String replyText; final bool isCurrentUser; final bool isSeen; final bool isDelivered; final String dateTime; + final bool isReplied; + final String userName; @override Widget build(BuildContext context) { return Padding( - // asymmetric padding - padding: EdgeInsets.fromLTRB( - isCurrentUser ? 64.0 : 16.0, - 4, - isCurrentUser ? 16.0 : 64.0, - 4, - ), + // padding: EdgeInsets.zero, + padding: EdgeInsets.only(left: isCurrentUser ? 110 : 20, right: isCurrentUser ? 20 : 110, bottom: 9), + child: Align( - // align the child within the container alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, child: DecoratedBox( - // chat bubble decoration decoration: BoxDecoration( color: Colors.white, gradient: isCurrentUser ? null - : LinearGradient( + : const LinearGradient( transform: GradientRotation(.46), begin: Alignment.topRight, end: Alignment.bottomLeft, - colors: [ - MyColors.gradiantEndColor, - MyColors.gradiantStartColor, - ]), + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ], + ), borderRadius: BorderRadius.circular(10), ), child: Padding( - padding: const EdgeInsets.all(12), + padding: EdgeInsets.only(top: isReplied ? 8 : 5, right:8, left: 8, bottom: 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - text.toText12( - color: - isCurrentUser ? MyColors.grey57Color : MyColors.white), - 8.height, + if (isReplied) + ClipRRect( + borderRadius: BorderRadius.circular(5.0), + child: Container( + decoration: BoxDecoration( + border: Border( + left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), + ), + color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5), + replyText + .toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4) + .paddingOnly(right: 5, top: 5, bottom: 8, left: 5), + ], + ), + ), + ], + ), + ), + ), + if (isReplied) 8.height, + text.toText12(color: isCurrentUser ? MyColors.grey57Color : MyColors.white), + Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end, children: [ - dateTime.toText12( - color: isCurrentUser - ? MyColors.grey41Color.withOpacity(.5) - : Colors.white.withOpacity(0.7)), + dateTime.toText12(color: isCurrentUser ? MyColors.grey41Color.withOpacity(.5) : Colors.white.withOpacity(0.7)), if (isCurrentUser) 5.width, if (isCurrentUser) Icon( - isDelivered - ? Icons.done_all - : Icons.done_all, - color: isSeen - ? MyColors.textMixColor - : MyColors.grey9DColor, + isDelivered ? Icons.done_all : Icons.done_all, + color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, size: 14, - ) + ), ], ), + ], ), ), diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 5f2fa97..d2d3598 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -1,4 +1,6 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -6,27 +8,53 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; +import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:sizer/sizer.dart'; +import 'package:swipe_to/swipe_to.dart'; class ChatDetailScreen extends StatelessWidget { + ChatDetailScreen({Key? key}) : super(key: key); dynamic userDetails; late ChatProviderModel data; + ScrollController scrollController = ScrollController(); + RefreshController _refreshController = RefreshController(initialRefresh: false); - ChatDetailScreen({Key? key}) : super(key: key); + void onRefresh() async { + print("Refresh Triggered"); + await Future.delayed(Duration(milliseconds: 1000)); + if (userDetails != null) { + data.paginationVal = data.paginationVal + 10; + data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true); + } + _refreshController.refreshCompleted(); + } @override Widget build(BuildContext context) { - userDetails = ModalRoute - .of(context)! - .settings - .arguments; + userDetails = ModalRoute.of(context)!.settings.arguments; data = Provider.of(context, listen: false); - data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, pagination: "0"); - Timer(const Duration(seconds: 1), () => data.scrollDown()); + if (userDetails != null) data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: false); + // + // if (userDetails != null) { + // scrollController.addListener(() { + // if (scrollController.position.minScrollExtent == scrollController.offset) { + // data.paginationVal++; + // data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true); + // } + // }); + // } + return Scaffold( backgroundColor: const Color(0xFFF8F8F8), appBar: AppBarWidget(context, title: userDetails["targetUser"].userName, showHomeButton: false, image: userDetails["targetUser"].image), @@ -35,73 +63,217 @@ class ChatDetailScreen extends StatelessWidget { return (m.isLoading ? ChatHomeShimmer() : Column( - children: [ - Expanded( - child: ListView.builder( - controller: m.scrollController, - shrinkWrap: true, - itemCount: m.userChatHistory.length, - padding: const EdgeInsets.symmetric(vertical: 10), - itemBuilder: (BuildContext context, int i) { - i == 0 ? m.logger.d(m.userChatHistory.length) : ""; - return ChatBubble( - text: m.userChatHistory[i].contant.toString(), - isSeen: m.userChatHistory[i].isSeen == true ? true : false, - isCurrentUser: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id ? true : false, - isDelivered: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id && m.userChatHistory[i].isDelivered == true ? true : false, - dateTime: m.userChatHistory[i].createdDate.toString(), - ); - }, - ), - ), - Card( - margin: EdgeInsets.zero, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: TextField( - controller: m.message, - decoration: InputDecoration( - hintText: LocaleKeys.typeheretoreply.tr(), - hintStyle: const TextStyle(color: MyColors.grey98Color), - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), - suffixIcon: SizedBox( - width: 100, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - IconButton( - icon: const Icon( - Icons.attach_file_rounded, - size: 27, - color: MyColors.lightGreenColor, + children: [ + Expanded( + flex: 2, + child: SmartRefresher( + enablePullDown: true, + enablePullUp: false, + header: const MaterialClassicHeader( + color: MyColors.gradiantEndColor, + ), + controller: _refreshController, + onRefresh: onRefresh, + child: ListView.builder( + controller: scrollController, + shrinkWrap: true, + itemCount: m.userChatHistory.length, + padding: EdgeInsets.zero, + itemBuilder: (BuildContext context, int i) { + return GestureDetector( + onTap: () { + m.logger.d(jsonEncode(m.userChatHistory[i])); + m.logger.d(jsonEncode(m.userChatHistory.length)); + }, + child: SwipeTo( + iconColor: MyColors.lightGreenColor, + child: ChatBubble( + text: m.userChatHistory[i].contant.toString(), + replyText: m.userChatHistory[i].userChatReplyResponse != null ? m.userChatHistory[i].userChatReplyResponse!.contant.toString() : "", + isSeen: m.userChatHistory[i].isSeen == true ? true : false, + isCurrentUser: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id ? true : false, + isDelivered: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id && m.userChatHistory[i].isDelivered == true ? true : false, + dateTime: m.dateFormte(m.userChatHistory[i].createdDate!), + isReplied: m.userChatHistory[i].userChatReplyResponse != null ? true : false, + userName: AppState().chatDetails!.response!.userName == m.userChatHistory[i].currentUserName.toString() ? "You" : m.userChatHistory[i].currentUserName.toString(), + ), + onRightSwipe: () { + m.chatReply(m.userChatHistory[i]); + }, + ), + ); + }, + ), + ), + ), + if (m.isMsgReply) + Row( + children: [ + Container( + height: 80, + color: MyColors.textMixColor, + width: 6, + ), + Expanded( + child: Container( + height: 80, + color: MyColors.black.withOpacity(0.10), + child: ListTile( + title: (AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString() ? "You" : m.repliedMsg.first.currentUserName.toString()) + .toText14(color: MyColors.lightGreenColor), + subtitle: (m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12(color: MyColors.white, maxLine: 2), + trailing: GestureDetector( + onTap: m.closeMe, + child: Container( + decoration: BoxDecoration( + color: MyColors.white.withOpacity(0.5), + borderRadius: const BorderRadius.all( + Radius.circular(20), + ), + ), + child: const Icon( + Icons.close, + size: 23, + color: MyColors.white, + ), + ), + ), ), - onPressed: () {}, ), - IconButton( - icon: SvgPicture.asset( - "assets/icons/chat/chat_send_icon.svg", - height: 26, - width: 35, + ), + ], + ), + if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg") + Card( + margin: EdgeInsets.zero, + elevation: 0, + child: Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20, top: 20, bottom: 0), + child: Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0.0), + ), + elevation: 0, + child: Container( + height: 200, + decoration: BoxDecoration( + image: DecorationImage( + image: FileImage( + m.selectedFile, + ), + fit: BoxFit.cover), + borderRadius: const BorderRadius.all( + Radius.circular(0), + ), ), - onPressed: () { - m.sendChatMessage(m.message.text, userDetails["targetUser"].id, userDetails["targetUser"].userName); - }, + child: const SizedBox( + width: double.infinity, + height: 200, + ), + ), + ), + ), + ), + Card( + margin: EdgeInsets.zero, + child: TextField( + controller: m.message, + decoration: InputDecoration( + hintText: m.isFileSelected ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(), + hintStyle: TextStyle(color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14), + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + contentPadding: EdgeInsets.only(left: m.sFileType.isNotEmpty ? 10 : 20, right: m.sFileType.isNotEmpty ? 0 : 5, top: 20, bottom: 20), + prefixIcon: m.sFileType.isNotEmpty + ? Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SvgPicture.asset( + m.getType(m.sFileType), + height: 30, + width: 25, + alignment: Alignment.center, + fit: BoxFit.cover, + ).paddingOnly(left: 20), + ], + ) + : null, + suffixIcon: Container( + width: 96, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, // added line + children: [ + if (m.sFileType.isNotEmpty) + IconButton( + padding: EdgeInsets.zero, + alignment: Alignment.centerRight, + icon: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + decoration: const BoxDecoration( + color: MyColors.redA3Color, + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + ), + child: const Icon( + Icons.close, + size: 15, + color: MyColors.white, + ), + ), + ("Clear").toText11(color: MyColors.redA3Color).paddingOnly(left: 4), + ], + ), + onPressed: () async { + m.removeAttachment(); + }, + ), + if (m.sFileType.isEmpty) + RotationTransition( + turns: const AlwaysStoppedAnimation(45 / 360), + child: IconButton( + padding: EdgeInsets.zero, + alignment: Alignment.topRight, + icon: const Icon( + Icons.attach_file_rounded, + size: 26, + color: MyColors.grey3AColor, + ), + onPressed: () async { + m.selectImageToUpload(context); + }, + ), + ), + IconButton( + alignment: Alignment.centerRight, + padding: EdgeInsets.zero, + icon: SvgPicture.asset( + "assets/icons/chat/chat_send_icon.svg", + height: 26, + width: 26, + ), + onPressed: () { + m.sendChatMessage(userDetails["targetUser"].id, userDetails["targetUser"].userName); + }, + ) + ], ), - ], + ).paddingOnly(right: 20), ), ), ), - ), - ), - ), - ], - )); + ], + )); }, ), ); diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index f6f8e24..106a4b3 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -8,13 +8,16 @@ import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheets/search_employee_bottom_sheet.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; +import 'package:sizer/sizer.dart'; class ChatHomeScreen extends StatefulWidget { const ChatHomeScreen({Key? key}) : super(key: key); @@ -81,45 +84,92 @@ class _ChatHomeScreenState extends State { if (m.searchedChats != null) ListView.separated( itemCount: m.searchedChats!.length, - padding: const EdgeInsets.only(top: 0), + padding: const EdgeInsets.only(top: 20), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) { - return ListTile( - leading: Stack( - children: [ - SvgPicture.asset( - "assets/images/user.svg", - height: 48, - width: 48, - ), - Positioned( - right: 5, - bottom: 1, - child: Container( - width: 10, - height: 10, - decoration: BoxDecoration( - color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, - borderRadius: const BorderRadius.all( - Radius.circular(10), + return SizedBox( + height: 55, + child: ListTile( + leading: Stack( + children: [ + SvgPicture.asset( + "assets/images/user.svg", + height: 48, + width: 48, + ), + Positioned( + right: 5, + bottom: 1, + child: Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: m.searchedChats![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, + borderRadius: const BorderRadius.all( + Radius.circular(10), + ), ), ), - ), - ) - ], + ) + ], + ), + title: (m.searchedChats![index].userName ?? "").toText14(color: MyColors.darkTextColor), + // subtitle: (m.searchedChats![index].isTyping == true ? "Typing ..." : "").toText11(color: MyColors.normalTextColor), + trailing: SizedBox( + width: 60, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + if (m.searchedChats![index].unreadMessageCount! > 0) + Flexible( + child: Container( + padding: EdgeInsets.zero, + alignment: Alignment.centerRight, + width: 18, + height: 18, + decoration: const BoxDecoration( + color: MyColors.redColor, + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + ), + child: (m.searchedChats![index].unreadMessageCount!.toString()) + .toText10( + color: MyColors.white, + ) + .center, + ), + ), + Flexible( + child: IconButton( + alignment: Alignment.centerRight, + padding: EdgeInsets.zero, + icon: Icon(m.searchedChats![index].isFav! ? Icons.star : Icons.star_border), + color: m.searchedChats![index].isFav! ? MyColors.yellowColor : MyColors.grey35Color, + onPressed: () { + if (m.searchedChats![index].isFav!) m.unFavoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!); + if (!m.searchedChats![index].isFav!) m.favoriteUser(userID: AppState().chatDetails!.response!.id!, targetUserID: m.searchedChats![index].id!); + }, + ), + ) + ], + ), + ), + minVerticalPadding: 0, + onTap: () { + Navigator.pushNamed( + context, + AppRoutes.chatDetailed, + arguments: {"targetUser": m.searchedChats![index]}, + ).then((value) { + m.clearSelections(); + }); + }, + onLongPress: () {}, ), - title: (m.searchedChats![index].userName ?? "").toText14(color: MyColors.darkTextColor), - subtitle: (m.searchedChats![index].isTyping == true ? "Typing ..." : "").toText11(color: MyColors.normalTextColor), - trailing: ("Today").toText10(color: MyColors.lightTextColor), - minVerticalPadding: 0, - onTap: () { - Navigator.pushNamed( - context, - AppRoutes.chatDetailed, - arguments: {"targetUser": m.searchedChats![index]}, - ); - }, ); }, separatorBuilder: (BuildContext context, int index) => const Padding( @@ -129,7 +179,6 @@ class _ChatHomeScreenState extends State { ), ), ), - // if (searchedUsersList == null) Utils.getNoChatWidget(context), ], ); }), @@ -156,11 +205,9 @@ class _ChatHomeScreenState extends State { ), ), onPressed: () async { - // var userData = await ChatApiClient() - // .getChatMemberFromSearch("aamir.muhammad", 36239); showMyBottomSheet( context, - callBackFunc: (){}, + callBackFunc: () {}, child: SearchEmployeeBottomSheet( title: LocaleKeys.searchForEmployee.tr(), apiMode: LocaleKeys.delegate.tr(), diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index 16942c5..fb14141 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -183,16 +183,66 @@ class _SearchEmployeeBottomSheetState extends State { if (widget.fromChat) if (chatUsersList != null && widget.fromChat) chatUsersList!.isEmpty - ? Utils.getNoDataWidget(context) + ? Column( + children: [ + 20.height, + Utils.getNoDataWidget(context), + ], + ) : ListView( physics: const BouncingScrollPhysics(), - padding: EdgeInsets.only(top: 0, bottom: 8), - children: [ + padding: const EdgeInsets.only(top: 15,), + children: [ ListView.separated( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (cxt, index) { - return ListTile( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (BuildContext cxt, int index) { + + + + + // return ListTile( + // leading: Stack( + // children: [ + // SvgPicture.asset( + // "assets/images/user.svg", + // height: 48, + // width: 48, + // ), + // Positioned( + // right: 5, + // bottom: 1, + // child: Container( + // width: 10, + // height: 10, + // decoration: BoxDecoration( + // color: chatUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, + // borderRadius: const BorderRadius.all( + // Radius.circular(10), + // ), + // ), + // ), + // ) + // ], + // ), + // title: (chatUsersList![index].userName ?? "").toText14(color: MyColors.darkTextColor), + // // subtitle: (chatUsersList![index].isTyping == true ? "Something is Typing" : "Last message text").toText11(color: MyColors.normalTextColor), + // // trailing: ("Today").toText10(color: MyColors.lightTextColor), + // minVerticalPadding: 0, + // onTap: () { + // Navigator.pop(context); + // Navigator.pushNamed( + // context, + // AppRoutes.chatDetailed, + // arguments: {"targetUser": chatUsersList![index]}, + // ); + // }, + // ); + + + return SizedBox( + height: 55, + child: ListTile( leading: Stack( children: [ SvgPicture.asset( @@ -217,8 +267,6 @@ class _SearchEmployeeBottomSheetState extends State { ], ), title: (chatUsersList![index].userName ?? "").toText14(color: MyColors.darkTextColor), - // subtitle: (chatUsersList![index].isTyping == true ? "Something is Typing" : "Last message text").toText11(color: MyColors.normalTextColor), - // trailing: ("Today").toText10(color: MyColors.lightTextColor), minVerticalPadding: 0, onTap: () { Navigator.pop(context); @@ -228,13 +276,21 @@ class _SearchEmployeeBottomSheetState extends State { arguments: {"targetUser": chatUsersList![index]}, ); }, - ); - }, - separatorBuilder: (BuildContext cxt, int index) => Container( - height: 1, - color: MyColors.borderE3Color, - ), - itemCount: chatUsersList?.length ?? 0), + onLongPress: () {}, + ), + ); + + + + }, + separatorBuilder: (BuildContext context, int index) => const Padding( + padding: EdgeInsets.only(right: 10, left: 70, bottom: 0,top: 0), + child: Divider( + color: Color(0xFFE5E5E5), + ), + ), + itemCount: chatUsersList?.length ?? 0, + ), 12.height, ], ).expanded, diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 5e5ac01..9fa0336 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -13,7 +13,7 @@ class ImageOptions { static void showImageOptionsNew(BuildContext context, bool showFilesOption, Function(String, File) image) { showMyBottomSheet( context, - callBackFunc: (){}, + callBackFunc: () {}, child: AttachmentOptions( showFilesOption: showFilesOption, onCameraTap: () async { @@ -43,7 +43,12 @@ class ImageOptions { } }, onFilesTap: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles(); + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['jpg', 'jpeg ', 'pdf', 'txt', 'docx', 'doc', 'pptx', 'xlsx', 'png', 'rar', 'zip', 'xls'], + ); + List files = result!.paths.map((path) => File(path!)).toList(); + image(result!.files.first.path.toString(), files.first); }, ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 633edd7..f2fbba8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -85,9 +85,13 @@ dependencies: appinio_swiper: ^1.1.1 expandable: ^5.0.1 + + #Chat signalr_netcore: ^1.3.3 logging: ^1.0.1 + swipe_to: ^1.0.2 + From 67f4fdef289f3d1165d978beea1f9c13c4be44f6 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Thu, 10 Nov 2022 16:06:25 +0300 Subject: [PATCH 2/2] Chat Fixes & Favorite Api Implementation --- lib/api/chat/chat_provider_model.dart | 88 +++---------------- lib/classes/consts.dart | 7 +- lib/ui/chat/chat_bubble.dart | 6 +- lib/ui/chat/chat_detailed_screen.dart | 59 ++++--------- lib/ui/chat/chat_home.dart | 4 +- .../search_employee_bottom_sheet.dart | 83 +++++------------ 6 files changed, 56 insertions(+), 191 deletions(-) diff --git a/lib/api/chat/chat_provider_model.dart b/lib/api/chat/chat_provider_model.dart index b3f37ab..b85aa85 100644 --- a/lib/api/chat/chat_provider_model.dart +++ b/lib/api/chat/chat_provider_model.dart @@ -141,20 +141,13 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ) .build(); hubConnection.onclose( - ({Exception? error}) { - // logger.d(error); - }, + ({Exception? error}) {}, ); hubConnection.onreconnecting( - ({Exception? error}) { - // logger.d(error); - // logger.d("Reconnecting"); - }, + ({Exception? error}) {}, ); hubConnection.onreconnected( - ({String? connectionId}) { - // logger.d("Reconnected"); - }, + ({String? connectionId}) {}, ); if (hubConnection.state != HubConnectionState.Connected) { await hubConnection.start(); @@ -403,7 +396,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { sFileType = ""; message.clear(); notifyListeners(); - // scrollDown(); } void sendChatMessage(int targetUserId, String targetUserName) async { @@ -437,7 +429,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } sendChatToServer( chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, chatReplyId: repliedMsg.first.userChatHistoryId, isAttachment: false, isReply: true); -//chatReplyId } if (isFileSelected && isMsgReply) { logger.d("Attachment Message With Reply"); @@ -445,60 +436,14 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); String? ext = getFileExtension(selectedFile.path); sendChatToServer( - chatEventId: 2, - fileTypeId: getFileType(ext.toString()), - targetUserId: targetUserId, - targetUserName: targetUserName, - isAttachment: true, - chatReplyId: repliedMsg.first.userChatHistoryId, - isReply: true); - } - - // dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); - // if (contain.isEmpty) { - // searchedChats!.add( - // ChatUser( - // id: targetUserId, - // userName: targetUserName, - // ), - // ); - // notifyListeners(); - // } - // Uuid uuid = const Uuid(); - // dynamic fileID = fileUploadResponse.isEmpty ? null : getFileType(chatMessage); - // SingleUserChatModel data = SingleUserChatModel( - // chatEventId: fileUploadResponse.isEmpty ? 1 : 2, - // chatSource: 1, - // contant: chatMessage, - // contantNo: uuid.v4(), - // conversationId: uuid.v4(), - // createdDate: DateTime.now(), - // currentUserId: AppState().chatDetails!.response!.id, - // currentUserName: AppState().chatDetails!.response!.userName, - // targetUserId: targetUserId, - // targetUserName: targetUserName, - // fileTypeId: fileID, - // isReplied: false, - // // fileTypeResponse: FileTypeResponse( - // // fileTypeId: 0, - // // fileTypeDescription: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"], - // // fileName: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"], - // // fileKind: "image", - // // fileTypeName: fileUploadResponse.isEmpty ? null : fileUploadResponse.first["filePath"].toString().split(".").last), - // ); - // - // String chatData = - // '{"contant":"$chatMessage","contantNo":"${uuid.v4()}","chatEventId":${fileUploadResponse.isEmpty ? 1 : 2},"fileTypeId": $fileID,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"conversationId":"${uuid.v4()}"}'; - // await hubConnection.invoke("AddChatUserAsync", args: [json.decode(chatData)]); - // userChatHistory.add(data); - // message.clear(); - // notifyListeners(); - // scrollDown(); - } - - void scrollListener() { - if (userChatHistory.length < paginationVal) { - print("Get New Data"); + chatEventId: 2, + fileTypeId: getFileType(ext.toString()), + targetUserId: targetUserId, + targetUserName: targetUserName, + isAttachment: true, + chatReplyId: repliedMsg.first.userChatHistoryId, + isReply: true, + ); } } @@ -513,18 +458,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } else { Utils.showToast("Max 1 mb size is allowed to upload"); } - //Utils.showLoading(context); notifyListeners(); - //Utils.hideLoading(context); - // Utils.showLoading(context); - // await m.uploadAttachments(AppState().chatDetails!.response!.id.toString(), file).then((value) { - // if (value == null) { - // m.logger.d("Returned EMPTY"); - // } else { - // m.sendChatMessage(value.isEmpty ? m.message.text : value.first["filePath"], userDetails["targetUser"].id, userDetails["targetUser"].userName, value); - // } - // }); - // Utils.hideLoading(context); }); } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index c98d136..c5788f9 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -10,6 +10,7 @@ class ApiConsts { static String user = baseUrlServices + "api/User/"; static String cocRest = baseUrlServices + "COCWS.svc/REST/"; + //Chat static String chatServerBaseUrl = "https://apiderichat.hmg.com"; static String chatServerBaseApiUrl = "https://apiderichat.hmg.com/api/"; static String chatHubConnectionUrl = chatServerBaseUrl + "/ConnectionChatHub"; @@ -18,12 +19,6 @@ class ApiConsts { static String chatSingleUserHistoryUrl = "UserChatHistory/GetUserChatHistory"; static String chatMediaImageUploadUrl = "shared/upload"; static String chatFavoriteUsers = "FavUser/getFavUserById/"; - //https://apiderichat.hmg.com/api/FavUser/getFavUserById/42062 -//https://apiderichat.hmg.com/api/shared/upload -// 42062 is CurrentUserID and 36745 is targetUserID and 0 is For Pagination - -// static String chatSearchMember = "https://apiderichat.hmg.com/api/user/getUserWithStatusAndFavAsync/aamir.muhammad/36239"; - } class SharedPrefsConsts { diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index 1e8aec4..5a878ca 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -29,7 +29,7 @@ class ChatBubble extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - // padding: EdgeInsets.zero, + // padding: EdgeInsets.zero, padding: EdgeInsets.only(left: isCurrentUser ? 110 : 20, right: isCurrentUser ? 20 : 110, bottom: 9), child: Align( @@ -51,7 +51,7 @@ class ChatBubble extends StatelessWidget { borderRadius: BorderRadius.circular(10), ), child: Padding( - padding: EdgeInsets.only(top: isReplied ? 8 : 5, right:8, left: 8, bottom: 5), + padding: EdgeInsets.only(top: isReplied ? 8 : 5, right: 8, left: 8, bottom: 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, @@ -85,7 +85,6 @@ class ChatBubble extends StatelessWidget { ), if (isReplied) 8.height, text.toText12(color: isCurrentUser ? MyColors.grey57Color : MyColors.white), - Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end, @@ -100,7 +99,6 @@ class ChatBubble extends StatelessWidget { ), ], ), - ], ), ), diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index d2d3598..fe7a968 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -8,19 +8,14 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; -import 'package:mohem_flutter_app/classes/colors.dart'; -import 'package:mohem_flutter_app/classes/utils.dart'; -import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart'; import 'package:mohem_flutter_app/widgets/app_bar_widget.dart'; -import 'package:mohem_flutter_app/widgets/image_picker.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; -import 'package:sizer/sizer.dart'; import 'package:swipe_to/swipe_to.dart'; class ChatDetailScreen extends StatelessWidget { @@ -30,13 +25,13 @@ class ChatDetailScreen extends StatelessWidget { ScrollController scrollController = ScrollController(); RefreshController _refreshController = RefreshController(initialRefresh: false); - void onRefresh() async { - print("Refresh Triggered"); - await Future.delayed(Duration(milliseconds: 1000)); + void getMoreChat() async { + if (userDetails != null) { data.paginationVal = data.paginationVal + 10; data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true); } + await Future.delayed(Duration(milliseconds: 1000)); _refreshController.refreshCompleted(); } @@ -45,16 +40,6 @@ class ChatDetailScreen extends StatelessWidget { userDetails = ModalRoute.of(context)!.settings.arguments; data = Provider.of(context, listen: false); if (userDetails != null) data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: false); - // - // if (userDetails != null) { - // scrollController.addListener(() { - // if (scrollController.position.minScrollExtent == scrollController.offset) { - // data.paginationVal++; - // data.getSingleUserChatHistory(senderUID: AppState().chatDetails!.response!.id.toString(), receiverUID: userDetails["targetUser"].id, loadMore: true); - // } - // }); - // } - return Scaffold( backgroundColor: const Color(0xFFF8F8F8), appBar: AppBarWidget(context, title: userDetails["targetUser"].userName, showHomeButton: false, image: userDetails["targetUser"].image), @@ -73,34 +58,28 @@ class ChatDetailScreen extends StatelessWidget { color: MyColors.gradiantEndColor, ), controller: _refreshController, - onRefresh: onRefresh, + onRefresh: getMoreChat, child: ListView.builder( controller: scrollController, shrinkWrap: true, itemCount: m.userChatHistory.length, padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int i) { - return GestureDetector( - onTap: () { - m.logger.d(jsonEncode(m.userChatHistory[i])); - m.logger.d(jsonEncode(m.userChatHistory.length)); - }, - child: SwipeTo( - iconColor: MyColors.lightGreenColor, - child: ChatBubble( - text: m.userChatHistory[i].contant.toString(), - replyText: m.userChatHistory[i].userChatReplyResponse != null ? m.userChatHistory[i].userChatReplyResponse!.contant.toString() : "", - isSeen: m.userChatHistory[i].isSeen == true ? true : false, - isCurrentUser: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id ? true : false, - isDelivered: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id && m.userChatHistory[i].isDelivered == true ? true : false, - dateTime: m.dateFormte(m.userChatHistory[i].createdDate!), - isReplied: m.userChatHistory[i].userChatReplyResponse != null ? true : false, - userName: AppState().chatDetails!.response!.userName == m.userChatHistory[i].currentUserName.toString() ? "You" : m.userChatHistory[i].currentUserName.toString(), - ), - onRightSwipe: () { - m.chatReply(m.userChatHistory[i]); - }, + return SwipeTo( + iconColor: MyColors.lightGreenColor, + child: ChatBubble( + text: m.userChatHistory[i].contant.toString(), + replyText: m.userChatHistory[i].userChatReplyResponse != null ? m.userChatHistory[i].userChatReplyResponse!.contant.toString() : "", + isSeen: m.userChatHistory[i].isSeen == true ? true : false, + isCurrentUser: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id ? true : false, + isDelivered: m.userChatHistory[i].currentUserId == AppState().chatDetails!.response!.id && m.userChatHistory[i].isDelivered == true ? true : false, + dateTime: m.dateFormte(m.userChatHistory[i].createdDate!), + isReplied: m.userChatHistory[i].userChatReplyResponse != null ? true : false, + userName: AppState().chatDetails!.response!.userName == m.userChatHistory[i].currentUserName.toString() ? "You" : m.userChatHistory[i].currentUserName.toString(), ), + onRightSwipe: () { + m.chatReply(m.userChatHistory[i]); + }, ); }, ), @@ -203,7 +182,7 @@ class ChatDetailScreen extends StatelessWidget { ], ) : null, - suffixIcon: Container( + suffixIcon: SizedBox( width: 96, child: Row( mainAxisAlignment: MainAxisAlignment.end, diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 106a4b3..38388ca 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -27,7 +27,7 @@ class ChatHomeScreen extends StatefulWidget { } class _ChatHomeScreenState extends State { - TextEditingController search = new TextEditingController(); + TextEditingController search = TextEditingController(); late ChatProviderModel data; @override @@ -213,8 +213,6 @@ class _ChatHomeScreenState extends State { apiMode: LocaleKeys.delegate.tr(), fromChat: true, onSelectEmployee: (_selectedEmployee) { - // Navigator.pop(context); - // selectedReplacementEmployee = _selectedEmployee; setState(() {}); }, ), diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index fb14141..63ce88b 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -136,12 +136,13 @@ class _SearchEmployeeBottomSheetState extends State { }, ).expanded, IconButton( - constraints: const BoxConstraints(), - onPressed: () async { - await SystemChannels.textInput.invokeMethod('TextInput.hide'); - widget.fromChat ? fetchChatUser() : fetchUserByInput(); - }, - icon: Icon(Icons.search)) + constraints: const BoxConstraints(), + onPressed: () async { + await SystemChannels.textInput.invokeMethod('TextInput.hide'); + widget.fromChat ? fetchChatUser() : fetchUserByInput(); + }, + icon: const Icon(Icons.search), + ) ], ), if (replacementList != null) @@ -184,62 +185,21 @@ class _SearchEmployeeBottomSheetState extends State { if (chatUsersList != null && widget.fromChat) chatUsersList!.isEmpty ? Column( - children: [ - 20.height, - Utils.getNoDataWidget(context), - ], - ) + children: [ + 20.height, + Utils.getNoDataWidget(context), + ], + ) : ListView( physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.only(top: 15,), + padding: const EdgeInsets.only( + top: 15, + ), children: [ ListView.separated( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext cxt, int index) { - - - - - // return ListTile( - // leading: Stack( - // children: [ - // SvgPicture.asset( - // "assets/images/user.svg", - // height: 48, - // width: 48, - // ), - // Positioned( - // right: 5, - // bottom: 1, - // child: Container( - // width: 10, - // height: 10, - // decoration: BoxDecoration( - // color: chatUsersList![index].userStatus == 1 ? MyColors.green2DColor : Colors.red, - // borderRadius: const BorderRadius.all( - // Radius.circular(10), - // ), - // ), - // ), - // ) - // ], - // ), - // title: (chatUsersList![index].userName ?? "").toText14(color: MyColors.darkTextColor), - // // subtitle: (chatUsersList![index].isTyping == true ? "Something is Typing" : "Last message text").toText11(color: MyColors.normalTextColor), - // // trailing: ("Today").toText10(color: MyColors.lightTextColor), - // minVerticalPadding: 0, - // onTap: () { - // Navigator.pop(context); - // Navigator.pushNamed( - // context, - // AppRoutes.chatDetailed, - // arguments: {"targetUser": chatUsersList![index]}, - // ); - // }, - // ); - - return SizedBox( height: 55, child: ListTile( @@ -279,12 +239,9 @@ class _SearchEmployeeBottomSheetState extends State { onLongPress: () {}, ), ); - - - }, separatorBuilder: (BuildContext context, int index) => const Padding( - padding: EdgeInsets.only(right: 10, left: 70, bottom: 0,top: 0), + padding: EdgeInsets.only(right: 10, left: 70, bottom: 0, top: 0), child: Divider( color: Color(0xFFE5E5E5), ), @@ -349,7 +306,9 @@ class _SearchEmployeeBottomSheetState extends State { decoration: BoxDecoration( color: Colors.transparent, border: Border.all(color: MyColors.borderColor, width: 1), - borderRadius: const BorderRadius.all(Radius.circular(100)), + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), ), padding: const EdgeInsets.all(4), child: Container( @@ -357,7 +316,9 @@ class _SearchEmployeeBottomSheetState extends State { height: double.infinity, decoration: BoxDecoration( color: value == groupValue ? MyColors.grey3AColor : Colors.transparent, - borderRadius: BorderRadius.all(const Radius.circular(100)), + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), ), ), ),