Merge branch 'master' into development_sikander
# Conflicts: # lib/classes/consts.dart # lib/generated/locale_keys.g.dart # lib/ui/landing/dashboard_screen.dartmerge-requests/17/head
						commit
						d200624ac2
					
				| @ -0,0 +1,24 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" width="29.557" height="29.557" viewBox="0 0 29.557 29.557"> | ||||
|   <g id="chat_3_" data-name="chat (3)" transform="translate(0 -0.008)"> | ||||
|     <g id="Group_8672" data-name="Group 8672" transform="translate(0 0.007)"> | ||||
|       <g id="Group_8671" data-name="Group 8671" transform="translate(0 0)"> | ||||
|         <path id="Path_13684" data-name="Path 13684" d="M29.348,17.685l-2.039-2.379A8.6,8.6,0,0,0,29.556,9.59c0-5.369-5.209-9.583-11.315-9.583-6.207,0-11.257,4.3-11.257,9.583,0,.133,0,.266.011.4-4.131,1.641-7,5.18-7,9.271a9.341,9.341,0,0,0,2.483,6.276L.214,28.127a.866.866,0,0,0,.652,1.436H13.046c.1,0,.4-.055.462-.061A12.95,12.95,0,0,0,21,26.322a9.481,9.481,0,0,0,3.3-7.207H28.69A.867.867,0,0,0,29.348,17.685ZM13.219,27.79c-.076.006-.337.029-.39.042H2.774l1.538-1.758a.866.866,0,0,0-.056-1.2,7.739,7.739,0,0,1-2.525-5.616c0-4.694,4.687-8.515,10.449-8.515,5.73,0,10.391,3.82,10.391,8.515C22.571,23.649,18.482,27.36,13.219,27.79ZM24.1,17.383h0C23.057,12.566,18.06,9.013,12.18,9.013a14.281,14.281,0,0,0-3.461.422c.1-4.258,4.333-7.7,9.523-7.7,5.284,0,9.583,3.522,9.583,7.851a7.016,7.016,0,0,1-2.284,5.058.866.866,0,0,0-.059,1.189l1.326,1.547Z" transform="translate(0 -0.007)" fill="#989898"/> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g id="Group_8674" data-name="Group 8674" transform="translate(5.253 17.383)"> | ||||
|       <g id="Group_8673" data-name="Group 8673"> | ||||
|         <path id="Path_13685" data-name="Path 13685" d="M92.729,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,92.729,301Z" transform="translate(-90.997 -300.999)" fill="#989898"/> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g id="Group_8676" data-name="Group 8676" transform="translate(10.448 17.383)"> | ||||
|       <g id="Group_8675" data-name="Group 8675"> | ||||
|         <path id="Path_13686" data-name="Path 13686" d="M182.726,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,182.726,301Z" transform="translate(-180.994 -300.999)" fill="#989898"/> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g id="Group_8678" data-name="Group 8678" transform="translate(15.644 17.383)"> | ||||
|       <g id="Group_8677" data-name="Group 8677"> | ||||
|         <path id="Path_13687" data-name="Path 13687" d="M272.723,301a1.732,1.732,0,1,0,1.732,1.732A1.734,1.734,0,0,0,272.723,301Z" transform="translate(-270.991 -300.999)" fill="#989898"/> | ||||
|       </g> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.2 KiB | 
| @ -0,0 +1,14 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" width="29.559" height="29.557" viewBox="0 0 29.559 29.557"> | ||||
|   <g id="chat_2_" data-name="chat (2)" transform="translate(0 -0.006)"> | ||||
|     <g id="Group_8680" data-name="Group 8680" transform="translate(0 8.954)"> | ||||
|       <g id="Group_8679" data-name="Group 8679" transform="translate(0)"> | ||||
|         <path id="Path_13688" data-name="Path 13688" d="M12.181,155C5.5,155,0,159.595,0,165.245a9.543,9.543,0,0,0,2.483,6.333L.214,174.171a.866.866,0,0,0,.652,1.436H13.046c4.936,0,11.315-4.25,11.315-10.362C24.361,159.595,18.865,155,12.181,155ZM6.927,166.832A1.732,1.732,0,1,1,8.659,165.1,1.734,1.734,0,0,1,6.927,166.832Zm5.253,0a1.732,1.732,0,1,1,1.732-1.732A1.734,1.734,0,0,1,12.181,166.832Zm5.253,0a1.732,1.732,0,1,1,1.732-1.732A1.734,1.734,0,0,1,17.434,166.832Z" transform="translate(0 -154.998)" fill="#2e303a"/> | ||||
|       </g> | ||||
|     </g> | ||||
|     <g id="Group_8682" data-name="Group 8682" transform="translate(7.077 0.006)"> | ||||
|       <g id="Group_8681" data-name="Group 8681" transform="translate(0 0)"> | ||||
|         <path id="Path_13689" data-name="Path 13689" d="M144.854,17.626l-2.039-2.379a8.6,8.6,0,0,0,2.248-5.716c0-5.252-5.05-9.525-11.257-9.525-5.613,0-10.381,3.5-11.223,8.05a16.022,16.022,0,0,1,5.1-.835c7.583,0,13.813,5.3,13.9,11.834H144.2A.867.867,0,0,0,144.854,17.626Z" transform="translate(-122.583 -0.006)" fill="#2e303a"/> | ||||
|       </g> | ||||
|     </g> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.3 KiB | 
| @ -0,0 +1,3 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" width="26.298" height="26.298" viewBox="0 0 26.298 26.298"> | ||||
|   <path id="send" d="M26.3,0,0,14.793l8.4,3.113L21.367,5.753l-9.86,13.3.008,0-.01,0V26.3l4.713-5.5,5.97,2.211Z" fill="#2bb8a6"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 236 B | 
| @ -0,0 +1,213 @@ | ||||
| import 'dart:convert'; | ||||
| 
 | ||||
| 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'; | ||||
| 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:signalr_netcore/hub_connection.dart'; | ||||
| import 'package:signalr_netcore/signalr_client.dart'; | ||||
| import 'package:logger/logger.dart' as L; | ||||
| 
 | ||||
| class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | ||||
|   List<SingleUserChatModel> userChatHistory = []; | ||||
|   List<ChatUser>? pChatHistory, searchedChats; | ||||
|   late HubConnection hubConnection; | ||||
|   L.Logger logger = L.Logger(); | ||||
|   TextEditingController message = TextEditingController(); | ||||
|   ScrollController scrollController = ScrollController(); | ||||
|   static String token = | ||||
|       "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiI0MjA2MiIsImVtYWlsIjoiYWFtaXIubXVoYW1tYWRAY2xvdWRzb2x1dGlvbnMuY29tLnNhIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy91c2VyZGF0YSI6ImFhbWlyLm11aGFtbWFkIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbW9iaWxlcGhvbmUiOiI5NjY1MzA4OTYwMTgiLCJuYmYiOjE2NjU5MjA2NDEsImV4cCI6MTY2NjAwNzA0MSwiaWF0IjoxNjY1OTIwNjQxfQ.70tXWdpXtQ20PNBO3WF9ScWNWSyECpFfrW7_iuOmNfWmA63PCZzlTO0E6I3q3K9Kg2CWvOT9-dSDLjlRuXuC2w"; | ||||
| 
 | ||||
|   bool isLoading = true; | ||||
| 
 | ||||
|   void getChatMemberFromSearch(String sName, int cUserId) async { | ||||
|     isLoading = true; | ||||
|     notifyListeners(); | ||||
|     Response response = await ApiClient().getJsonForResponse( | ||||
|       "${ApiConsts.chatSearchMember}$sName/$cUserId", | ||||
|       token: token, | ||||
|     ); | ||||
|     isLoading = false; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void getUserRecentChats() async { | ||||
|     Response response = await ApiClient().getJsonForResponse( | ||||
|       "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatRecentUrl}", | ||||
|       token: token, | ||||
|     ); | ||||
|     ChatUserModel recentChat = userToList(response.body); | ||||
|     pChatHistory = recentChat.response; | ||||
|     searchedChats = pChatHistory; | ||||
|     isLoading = false; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void getSingleUserChatHistory({required String senderUID, required int receiverUID, required String pagination}) async { | ||||
|     isLoading = true; | ||||
|     Response response = await ApiClient().getJsonForResponse( | ||||
|       "${ApiConsts.chatServerBaseApiUrl}${ApiConsts.chatSingleUserHistoryUrl}/$senderUID/$receiverUID/$pagination", | ||||
|       token: token, | ||||
|     ); | ||||
|     userChatHistory = getSingleUserChatintoModel(response.body); | ||||
|     isLoading = false; | ||||
|     logger.d(jsonEncode(userChatHistory)); | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   List<SingleUserChatModel> getSingleUserChatintoModel(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); | ||||
| 
 | ||||
|   ChatUserModel userToList(String str) => ChatUserModel.fromJson(json.decode(str)); | ||||
| 
 | ||||
|   void buildHubConnection() async { | ||||
|     HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); | ||||
|     hubConnection = await HubConnectionBuilder() | ||||
|         .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=42062&source=Web&access_token=$token", options: httpOp) | ||||
|         .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]) | ||||
|         .configureLogging(Logger("Logs Enabled")) | ||||
|         .build(); | ||||
|     hubConnection.onclose( | ||||
|       ({Exception? error}) { | ||||
|         logger.d(error); | ||||
|       }, | ||||
|     ); | ||||
|     hubConnection.onreconnecting( | ||||
|       ({Exception? error}) { | ||||
|         logger.d(error); | ||||
|         logger.d("Reconnecting"); | ||||
|       }, | ||||
|     ); | ||||
|     hubConnection.onreconnected( | ||||
|       ({String? connectionId}) { | ||||
|         logger.d("Reconnected"); | ||||
|       }, | ||||
|     ); | ||||
|     if (hubConnection.state != HubConnectionState.Connected) { | ||||
|       await hubConnection.start(); | ||||
|       hubConnection.on("OnUpdateUserStatusAsync", changeStatus); | ||||
|       hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); | ||||
|       //  hubConnection.on("OnUserTypingAsync", onUserTyping); | ||||
|       //hubConnection.on("OnUserTypingAsync", changeTypingStatus); | ||||
|     } else { | ||||
|       hubConnection.on("OnUpdateUserStatusAsync", changeStatus); | ||||
|       hubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); | ||||
|       //  hubConnection.on("OnUserTypingAsync", onUserTyping); | ||||
|       //hubConnection.on("OnUserTypingAsync", changeTypingStatus); | ||||
|     } | ||||
|     isLoading = false; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void changeStatus(List<Object?>? args) { | ||||
|     List items = args!.toList(); | ||||
|     for (var user in searchedChats!) { | ||||
|       if (user.id == items.first["id"]) { | ||||
|         user.userStatus = items.first["userStatus"]; | ||||
|       } | ||||
|     } | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void filter(String value) async { | ||||
|     List<ChatUser>? tmp = []; | ||||
|     if (value.isEmpty || value == "") { | ||||
|       tmp = pChatHistory; | ||||
|     } else { | ||||
|       for (var element in pChatHistory!) { | ||||
|         if (element.userName!.toLowerCase().contains(value.toLowerCase())) { | ||||
|           tmp.add(element); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     searchedChats = tmp; | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   Future<void> onMsgReceived(List<Object?>? parameters) async { | ||||
|     List<SingleUserChatModel> data = []; | ||||
|     for (dynamic msg in parameters!) { | ||||
|       data = getSingleUserChatintoModel(jsonEncode(msg)); | ||||
|       logger.d(msg); | ||||
|     } | ||||
|     userChatHistory.add(data.first); | ||||
|     notifyListeners(); | ||||
|     scrollDown(); | ||||
|   } | ||||
| 
 | ||||
|   void onUserTyping(List<Object?>? parameters) { | ||||
|     print("==================== Typing Active =================="); | ||||
|     logger.d(parameters); | ||||
|     for (ChatUser user in searchedChats!) { | ||||
|       if (user.id == parameters![1] && parameters[0] == true) { | ||||
|         user.isTyping = parameters[0] as bool?; | ||||
|       } else { | ||||
|         Future.delayed( | ||||
|           const Duration(milliseconds: 500), | ||||
|           () { | ||||
|             user.isTyping = false; | ||||
|           }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     notifyListeners(); | ||||
|   } | ||||
| 
 | ||||
|   void sendChatMessage(String chatMessage, int targetUserId, String targetUserName) async { | ||||
|     if (chatMessage == null || chatMessage.isEmpty) { | ||||
|       return; | ||||
|     } | ||||
|     String chatData = | ||||
|         '{"contant":"$chatMessage","contantNo":"8a129295-36d7-7185-5d34-cc4eec7bcba4","chatEventId":1,"fileTypeId":null,"currentUserId":42062,"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"conversationId":"715f8b13-96ee-cd36-cb07-5a982a219982"}'; | ||||
|     await hubConnection.invoke("AddChatUserAsync", args: <Object>[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: 42062, | ||||
|         currentUserName: "aamir.muhammad", | ||||
|         targetUserId: targetUserId, | ||||
|         targetUserName: targetUserName, | ||||
|       ), | ||||
|     ); | ||||
|     message.clear(); | ||||
|     notifyListeners(); | ||||
|     scrollDown(); | ||||
|   } | ||||
| 
 | ||||
|   void scrollDown() { | ||||
|     scrollController.animateTo( | ||||
|       scrollController.position.maxScrollExtent + 100, | ||||
|       curve: Curves.easeOut, | ||||
|       duration: const Duration(milliseconds: 300), | ||||
|     ); | ||||
| 
 | ||||
|     //   scrollController.animateTo(double.parse(userChatHistory.length.toString()), duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); | ||||
| 
 | ||||
|     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; | ||||
| //    } | ||||
| //  } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,82 @@ | ||||
| class ChatUserModel { | ||||
|   ChatUserModel({ | ||||
|     this.response, | ||||
|     this.errorResponses, | ||||
|   }); | ||||
| 
 | ||||
|   List<ChatUser>? response; | ||||
|   dynamic errorResponses; | ||||
| 
 | ||||
|   factory ChatUserModel.fromJson(Map<String, dynamic> json) => ChatUserModel( | ||||
|         response: json["response"] == null ? null : List<ChatUser>.from(json["response"].map((x) => ChatUser.fromJson(x))), | ||||
|         errorResponses: json["errorResponses"], | ||||
|       ); | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() => { | ||||
|         "response": response == null ? null : List<dynamic>.from(response!.map((x) => x.toJson())), | ||||
|         "errorResponses": errorResponses, | ||||
|       }; | ||||
| } | ||||
| 
 | ||||
| class ChatUser { | ||||
|   ChatUser({ | ||||
|     this.id, | ||||
|     this.userName, | ||||
|     this.email, | ||||
|     this.phone, | ||||
|     this.title, | ||||
|     this.userStatus, | ||||
|     this.image, | ||||
|     this.unreadMessageCount, | ||||
|     this.userAction, | ||||
|     this.isPin, | ||||
|     this.isFav, | ||||
|     this.isAdmin, | ||||
|     this.isTyping, | ||||
|   }); | ||||
| 
 | ||||
|   int? id; | ||||
|   String? userName; | ||||
|   String? email; | ||||
|   dynamic? phone; | ||||
|   dynamic? title; | ||||
|   int? userStatus; | ||||
|   dynamic? image; | ||||
|   int? unreadMessageCount; | ||||
|   dynamic? userAction; | ||||
|   bool? isPin; | ||||
|   bool? isFav; | ||||
|   bool? isAdmin; | ||||
|   bool? isTyping; | ||||
| 
 | ||||
|   factory ChatUser.fromJson(Map<String, dynamic> json) => ChatUser( | ||||
|         id: json["id"] == null ? null : json["id"], | ||||
|         userName: json["userName"] == null ? null : json["userName"], | ||||
|         email: json["email"] == null ? null : json["email"], | ||||
|         phone: json["phone"], | ||||
|         title: json["title"], | ||||
|         userStatus: json["userStatus"] == null ? null : json["userStatus"], | ||||
|         image: json["image"], | ||||
|         unreadMessageCount: json["unreadMessageCount"] == null ? null : json["unreadMessageCount"], | ||||
|         userAction: json["userAction"], | ||||
|         isPin: json["isPin"] == null ? null : json["isPin"], | ||||
|         isFav: json["isFav"] == null ? null : json["isFav"], | ||||
|         isAdmin: json["isAdmin"] == null ? null : json["isAdmin"], | ||||
|         isTyping: false, | ||||
|       ); | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() => { | ||||
|         "id": id == null ? null : id, | ||||
|         "userName": userName == null ? null : userName, | ||||
|         "email": email == null ? null : email, | ||||
|         "phone": phone, | ||||
|         "title": title, | ||||
|         "userStatus": userStatus == null ? null : userStatus, | ||||
|         "image": image, | ||||
|         "unreadMessageCount": unreadMessageCount == null ? null : unreadMessageCount, | ||||
|         "userAction": userAction, | ||||
|         "isPin": isPin == null ? null : isPin, | ||||
|         "isFav": isFav == null ? null : isFav, | ||||
|         "isAdmin": isAdmin == null ? null : isAdmin, | ||||
|       }; | ||||
| } | ||||
| @ -0,0 +1,119 @@ | ||||
| class SingleUserChatModel { | ||||
|   SingleUserChatModel({ | ||||
|     this.userChatHistoryId, | ||||
|     this.userChatHistoryLineId, | ||||
|     this.contant, | ||||
|     this.contantNo, | ||||
|     this.currentUserId, | ||||
|     this.currentUserName, | ||||
|     this.targetUserId, | ||||
|     this.targetUserName, | ||||
|     this.encryptedTargetUserId, | ||||
|     this.encryptedTargetUserName, | ||||
|     this.chatEventId, | ||||
|     this.fileTypeId, | ||||
|     this.isSeen, | ||||
|     this.isDelivered, | ||||
|     this.createdDate, | ||||
|     this.chatSource, | ||||
|     this.conversationId, | ||||
|     this.fileTypeResponse, | ||||
|     this.userChatReplyResponse, | ||||
|   }); | ||||
| 
 | ||||
|   int? userChatHistoryId; | ||||
|   int? userChatHistoryLineId; | ||||
|   String? contant; | ||||
|   String? contantNo; | ||||
|   int? currentUserId; | ||||
|   String? currentUserName; | ||||
|   int? targetUserId; | ||||
|   String? targetUserName; | ||||
|   dynamic encryptedTargetUserId; | ||||
|   dynamic encryptedTargetUserName; | ||||
|   int? chatEventId; | ||||
|   dynamic fileTypeId; | ||||
|   bool? isSeen; | ||||
|   bool? isDelivered; | ||||
|   DateTime? createdDate; | ||||
|   int? chatSource; | ||||
|   String? conversationId; | ||||
|   FileTypeResponse? fileTypeResponse; | ||||
|   dynamic userChatReplyResponse; | ||||
| 
 | ||||
|   factory SingleUserChatModel.fromJson(Map<String, dynamic> json) => SingleUserChatModel( | ||||
|         userChatHistoryId: json["userChatHistoryId"] == null ? null : json["userChatHistoryId"], | ||||
|         userChatHistoryLineId: json["userChatHistoryLineId"] == null ? null : json["userChatHistoryLineId"], | ||||
|         contant: json["contant"] == null ? null : json["contant"], | ||||
|         contantNo: json["contantNo"] == null ? null : json["contantNo"], | ||||
|         currentUserId: json["currentUserId"] == null ? null : json["currentUserId"], | ||||
|         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"], | ||||
|         chatEventId: json["chatEventId"] == null ? null : json["chatEventId"], | ||||
|         fileTypeId: json["fileTypeId"], | ||||
|         isSeen: json["isSeen"] == null ? null : json["isSeen"], | ||||
|         isDelivered: json["isDelivered"] == null ? null : json["isDelivered"], | ||||
|         createdDate: json["createdDate"] == null ? null : DateTime.parse(json["createdDate"]), | ||||
|         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"], | ||||
|       ); | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() => { | ||||
|         "userChatHistoryId": userChatHistoryId == null ? null : userChatHistoryId, | ||||
|         "userChatHistoryLineId": userChatHistoryLineId == null ? null : userChatHistoryLineId, | ||||
|         "contant": contant == null ? null : contant, | ||||
|         "contantNo": contantNo == null ? null : contantNo, | ||||
|         "currentUserId": currentUserId == null ? null : currentUserId, | ||||
|         "currentUserName": currentUserName == null ? null : currentUserName, | ||||
|         "targetUserId": targetUserId == null ? null : targetUserId, | ||||
|         "targetUserName": targetUserName == null ? null : targetUserName, | ||||
|         "encryptedTargetUserId": encryptedTargetUserId, | ||||
|         "encryptedTargetUserName": encryptedTargetUserName, | ||||
|         "chatEventId": chatEventId == null ? null : chatEventId, | ||||
|         "fileTypeId": fileTypeId, | ||||
|         "isSeen": isSeen == null ? null : isSeen, | ||||
|         "isDelivered": isDelivered == null ? null : isDelivered, | ||||
|         "createdDate": createdDate == null ? null : createdDate!.toIso8601String(), | ||||
|         "chatSource": chatSource == null ? null : chatSource, | ||||
|         "conversationId": conversationId == null ? null : conversationId, | ||||
|         "fileTypeResponse": fileTypeResponse == null ? null : fileTypeResponse!.toJson(), | ||||
|         "userChatReplyResponse": userChatReplyResponse, | ||||
|       }; | ||||
| } | ||||
| 
 | ||||
| class FileTypeResponse { | ||||
|   FileTypeResponse({ | ||||
|     this.fileTypeId, | ||||
|     this.fileTypeName, | ||||
|     this.fileTypeDescription, | ||||
|     this.fileKind, | ||||
|     this.fileName, | ||||
|   }); | ||||
| 
 | ||||
|   int? fileTypeId; | ||||
|   dynamic fileTypeName; | ||||
|   dynamic fileTypeDescription; | ||||
|   dynamic fileKind; | ||||
|   dynamic fileName; | ||||
| 
 | ||||
|   factory FileTypeResponse.fromJson(Map<String, dynamic> json) => FileTypeResponse( | ||||
|         fileTypeId: json["fileTypeId"] == null ? null : json["fileTypeId"], | ||||
|         fileTypeName: json["fileTypeName"], | ||||
|         fileTypeDescription: json["fileTypeDescription"], | ||||
|         fileKind: json["fileKind"], | ||||
|         fileName: json["fileName"], | ||||
|       ); | ||||
| 
 | ||||
|   Map<String, dynamic> toJson() => { | ||||
|         "fileTypeId": fileTypeId == null ? null : fileTypeId, | ||||
|         "fileTypeName": fileTypeName, | ||||
|         "fileTypeDescription": fileTypeDescription, | ||||
|         "fileKind": fileKind, | ||||
|         "fileName": fileName, | ||||
|       }; | ||||
| } | ||||
| @ -0,0 +1,88 @@ | ||||
| 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'; | ||||
| 
 | ||||
| class ChatBubble extends StatelessWidget { | ||||
|   const ChatBubble( | ||||
|       {Key? key, | ||||
|       required this.text, | ||||
|       required this.isCurrentUser, | ||||
|       required this.isSeen, | ||||
|       required this.isDelivered, | ||||
|       required this.dateTime}) | ||||
|       : super(key: key); | ||||
|   final String text; | ||||
|   final bool isCurrentUser; | ||||
|   final bool isSeen; | ||||
|   final bool isDelivered; | ||||
|   final String dateTime; | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Padding( | ||||
|       // asymmetric padding | ||||
|       padding: EdgeInsets.fromLTRB( | ||||
|         isCurrentUser ? 64.0 : 16.0, | ||||
|         4, | ||||
|         isCurrentUser ? 16.0 : 64.0, | ||||
|         4, | ||||
|       ), | ||||
|       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( | ||||
|                     transform: GradientRotation(.46), | ||||
|                     begin: Alignment.topRight, | ||||
|                     end: Alignment.bottomLeft, | ||||
|                     colors: [ | ||||
|                         MyColors.gradiantEndColor, | ||||
|                         MyColors.gradiantStartColor, | ||||
|                       ]), | ||||
|             borderRadius: BorderRadius.circular(10), | ||||
|           ), | ||||
|           child: Padding( | ||||
|             padding: const EdgeInsets.all(12), | ||||
|             child: Column( | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               mainAxisAlignment: MainAxisAlignment.start, | ||||
|               children: [ | ||||
|                 text.toText12( | ||||
|                     color: | ||||
|                         isCurrentUser ? MyColors.grey57Color : MyColors.white), | ||||
|                 8.height, | ||||
|                 Row( | ||||
|                   crossAxisAlignment: CrossAxisAlignment.end, | ||||
|                   mainAxisAlignment: MainAxisAlignment.end, | ||||
|                   children: [ | ||||
|                     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, | ||||
|                         size: 14, | ||||
|                       ) | ||||
|                   ], | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,86 @@ | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_svg/flutter_svg.dart'; | ||||
| import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; | ||||
| import 'package:mohem_flutter_app/classes/colors.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/shimmer/dashboard_shimmer_widget.dart'; | ||||
| import 'package:provider/provider.dart'; | ||||
| 
 | ||||
| class ChatDetailScreen extends StatelessWidget { | ||||
|   dynamic userDetails; | ||||
|   late ChatProviderModel data; | ||||
| 
 | ||||
|   ChatDetailScreen({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     userDetails = ModalRoute.of(context)!.settings.arguments; | ||||
|     data = Provider.of<ChatProviderModel>(context, listen: false); | ||||
|     data.getSingleUserChatHistory(senderUID: "42062", receiverUID: userDetails["targetUser"].id, pagination: "0"); | ||||
|     Timer(const Duration(seconds: 1), () => data.scrollDown()); | ||||
|     return Scaffold( | ||||
|       backgroundColor: const Color(0xFFF8F8F8), | ||||
|       appBar: AppBarWidget(context, title: userDetails["targetUser"].userName, showHomeButton: false, image: userDetails["targetUser"].image), | ||||
|       body: Consumer<ChatProviderModel>( | ||||
|         builder: (BuildContext context, ChatProviderModel m, Widget? child) { | ||||
|           return (m.isLoading | ||||
|               ? ChatHomeShimmer() | ||||
|               : Column( | ||||
|                   children: <Widget>[ | ||||
|                     Expanded( | ||||
|                       child: ListView.builder( | ||||
|                         controller: m.scrollController, | ||||
|                         shrinkWrap: true, | ||||
|                         itemCount: m.userChatHistory.length, | ||||
|                         padding: const EdgeInsets.symmetric(vertical: 10), | ||||
|                         itemBuilder: (BuildContext context, int i) { | ||||
|                           return ChatBubble( | ||||
|                             text: m.userChatHistory[i].contant.toString(), | ||||
|                             isSeen: m.userChatHistory[i].isSeen == true ? true : false, | ||||
|                             isCurrentUser: m.userChatHistory[i].currentUserId == 42062 ? true : false, | ||||
|                             isDelivered: m.userChatHistory[i].currentUserId == 42062 && 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: 'Type here to reply', | ||||
|                             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: IconButton( | ||||
|                               icon: SvgPicture.asset( | ||||
|                                 "assets/icons/chat/chat_send_icon.svg", | ||||
|                                 height: 26, | ||||
|                                 width: 35, | ||||
|                               ), | ||||
|                               onPressed: () { | ||||
|                                 m.sendChatMessage(m.message.text, userDetails["targetUser"].id, userDetails["targetUser"].userName); | ||||
|                               }, | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ], | ||||
|                 )); | ||||
|         }, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,175 @@ | ||||
| import 'dart:convert'; | ||||
| 
 | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/cupertino.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_svg/flutter_svg.dart'; | ||||
| import 'package:mohem_flutter_app/api/chat/chat_provider_model.dart'; | ||||
| import 'package:mohem_flutter_app/classes/colors.dart'; | ||||
| import 'package:mohem_flutter_app/config/routes.dart'; | ||||
| import 'package:mohem_flutter_app/extensions/string_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'; | ||||
| 
 | ||||
| class ChatHomeScreen extends StatefulWidget { | ||||
|   const ChatHomeScreen({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   State<ChatHomeScreen> createState() => _ChatHomeScreenState(); | ||||
| } | ||||
| 
 | ||||
| class _ChatHomeScreenState extends State<ChatHomeScreen> { | ||||
|   TextEditingController search = new TextEditingController(); | ||||
|   late ChatProviderModel data; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     data = Provider.of<ChatProviderModel>(context, listen: false); | ||||
|     data.buildHubConnection(); | ||||
|     data.getUserRecentChats(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void dispose() { | ||||
|     super.dispose(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       backgroundColor: Colors.white, | ||||
|       appBar: AppBarWidget(context, title: "My Chats", showHomeButton: false), | ||||
|       body: Consumer<ChatProviderModel>(builder: (BuildContext context, ChatProviderModel m, Widget? child) { | ||||
|         return m.isLoading | ||||
|             ? ChatHomeShimmer() | ||||
|             : ListView( | ||||
|                 shrinkWrap: true, | ||||
|                 physics: const AlwaysScrollableScrollPhysics(), | ||||
|                 children: [ | ||||
|                   Padding( | ||||
|                     padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 20), | ||||
|                     child: TextField( | ||||
|                       onChanged: (String val) { | ||||
|                         m.filter(val); | ||||
|                       }, | ||||
|                       decoration: InputDecoration( | ||||
|                         border: InputBorder.none, | ||||
|                         focusedBorder: InputBorder.none, | ||||
|                         enabledBorder: OutlineInputBorder( | ||||
|                           borderRadius: BorderRadius.circular(5), | ||||
|                           borderSide: const BorderSide( | ||||
|                             color: Color(0xFFE5E5E5), | ||||
|                           ), | ||||
|                         ), | ||||
|                         errorBorder: InputBorder.none, | ||||
|                         disabledBorder: InputBorder.none, | ||||
|                         contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), | ||||
|                         hintText: "Search from chat", | ||||
|                         hintStyle: const TextStyle(color: MyColors.lightTextColor, fontStyle: FontStyle.italic), | ||||
|                         filled: true, | ||||
|                         fillColor: const Color(0xFFF7F7F7), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                   if (m.searchedChats != null) | ||||
|                     ListView.separated( | ||||
|                       itemCount: m.searchedChats!.length, | ||||
|                       padding: const EdgeInsets.only(top: 0), | ||||
|                       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), | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                 ), | ||||
|                               ) | ||||
|                             ], | ||||
|                           ), | ||||
|                           title: (m.searchedChats![index].userName ?? "").toText14(color: MyColors.darkTextColor), | ||||
|                           subtitle: (m.searchedChats![index].isTyping == true ? "Something is Typing" : "Last message text").toText11(color: MyColors.normalTextColor), | ||||
|                           trailing: ("Today").toText10(color: MyColors.lightTextColor), | ||||
|                           minVerticalPadding: 0, | ||||
|                           onTap: () { | ||||
|                             Navigator.pushNamed( | ||||
|                               context, | ||||
|                               AppRoutes.chatDetailed, | ||||
|                               arguments: {"currentUser": "42062", "targetUser": m.searchedChats![index]}, | ||||
|                             ); | ||||
|                           }, | ||||
|                         ); | ||||
|                       }, | ||||
|                       separatorBuilder: (BuildContext context, int index) => const Padding( | ||||
|                         padding: EdgeInsets.only(right: 10, left: 70), | ||||
|                         child: Divider( | ||||
|                           color: Color(0xFFE5E5E5), | ||||
|                         ), | ||||
|                       ), | ||||
|                     ), | ||||
|                   // if (searchedUsersList == null) Utils.getNoChatWidget(context), | ||||
|                 ], | ||||
|               ); | ||||
|       }), | ||||
|       floatingActionButton: FloatingActionButton( | ||||
|         child: Container( | ||||
|           width: 60, | ||||
|           height: 60, | ||||
|           decoration: const BoxDecoration( | ||||
|             shape: BoxShape.circle, | ||||
|             gradient: LinearGradient( | ||||
|               transform: GradientRotation(.46), | ||||
|               begin: Alignment.topRight, | ||||
|               end: Alignment.bottomLeft, | ||||
|               colors: [ | ||||
|                 MyColors.gradiantEndColor, | ||||
|                 MyColors.gradiantStartColor, | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|           child: const Icon( | ||||
|             Icons.add, | ||||
|             size: 30, | ||||
|             color: MyColors.white, | ||||
|           ), | ||||
|         ), | ||||
|         onPressed: () async { | ||||
|           // var userData = await ChatApiClient() | ||||
|           //     .getChatMemberFromSearch("aamir.muhammad", 36239); | ||||
|           showMyBottomSheet( | ||||
|             context, | ||||
|             child: SearchEmployeeBottomSheet( | ||||
|               title: LocaleKeys.searchForEmployee.tr(), | ||||
|               apiMode: LocaleKeys.delegate.tr(), | ||||
|               onSelectEmployee: (_selectedEmployee) { | ||||
|                 //   Navigator.pop(context); | ||||
|                 // selectedReplacementEmployee = _selectedEmployee; | ||||
|                 setState(() {}); | ||||
|               }, | ||||
|             ), | ||||
|           ); | ||||
|         }, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in New Issue