From 7d1086522d094c6886cadd720acfb5bf9d9f3b02 Mon Sep 17 00:00:00 2001 From: "Aamir.Muhammad" Date: Mon, 12 Dec 2022 11:04:28 +0300 Subject: [PATCH] Chat Fixes & Counter Updated on Signal R --- lib/api/chat/chat_api_client.dart | 98 ++++++---- lib/api/dashboard_api_client.dart | 7 +- .../chat/chat_count_conversation_model.dart | 28 +-- .../chat/get_search_user_chat_model.dart | 36 ++-- lib/provider/chat_provider_model.dart | 169 ++++++++++++++---- lib/provider/dashboard_provider_model.dart | 23 +-- lib/ui/chat/chat_bubble.dart | 50 +++--- lib/ui/chat/chat_detailed_screen.dart | 61 ++++--- lib/ui/chat/chat_home.dart | 18 +- lib/ui/chat/chat_home_screen.dart | 38 ++-- lib/ui/chat/favorite_users_screen.dart | 25 +-- lib/ui/landing/dashboard_screen.dart | 9 +- lib/widgets/app_bar_widget.dart | 13 ++ .../search_employee_bottom_sheet.dart | 3 +- lib/widgets/image_picker.dart | 2 +- 15 files changed, 367 insertions(+), 213 deletions(-) diff --git a/lib/api/chat/chat_api_client.dart b/lib/api/chat/chat_api_client.dart index bea5b7c..3ef8fba 100644 --- a/lib/api/chat/chat_api_client.dart +++ b/lib/api/chat/chat_api_client.dart @@ -2,11 +2,11 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/consts.dart'; -import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/exceptions/api_exception.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.dart'; @@ -29,6 +29,9 @@ class ChatApiClient { "password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", }, ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } user.UserAutoLoginModel userLoginResponse = user.userAutoLoginModelFromJson(response.body); return userLoginResponse; } @@ -38,33 +41,36 @@ class ChatApiClient { "${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync/$sName/$cUserId", token: AppState().chatDetails!.response!.token, ); - return searchUserJsonModel(response.body); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + return List.from(json.decode(response.body).map((x) => ChatUser.fromJson(x))); } - List searchUserJsonModel(String str) => List.from(json.decode(str).map((x) => ChatUser.fromJson(x))); - Future getRecentChats() async { try { Response response = await ApiClient().getJsonForResponse( "${ApiConsts.chatRecentUrl}getchathistorybyuserid", token: AppState().chatDetails!.response!.token, ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } return ChatUserModel.fromJson( json.decode(response.body), ); } catch (e) { - e as APIException; - if (e.message == "api_common_unauthorized") { - user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); - if (userLoginResponse.response != null) { - AppState().setchatUserDetails = userLoginResponse; - getRecentChats(); - } else { - Utils.showToast( - userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", - ); - } - } + // if (e.message == "api_common_unauthorized") { + // user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + // if (userLoginResponse.response != null) { + // AppState().setchatUserDetails = userLoginResponse; + // getRecentChats(); + // } else { + // Utils.showToast( + // userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr", + // ); + // } + // } throw e; } } @@ -74,9 +80,10 @@ class ChatApiClient { "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}", token: AppState().chatDetails!.response!.token, ); - return ChatUserModel.fromJson( - json.decode(favRes.body), - ); + if (!kReleaseMode) { + logger.i("res: " + favRes.body); + } + return ChatUserModel.fromJson(json.decode(favRes.body)); } Future getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async { @@ -85,24 +92,30 @@ class ChatApiClient { "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", token: AppState().chatDetails!.response!.token, ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } return response; } catch (e) { - e as APIException; - if (e.message == "api_common_unauthorized") { - user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); - if (userLoginResponse.response != null) { - AppState().setchatUserDetails = userLoginResponse; - getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); - } else { - Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr"); - } - } + // e as APIException; + // if (e.message == "api_common_unauthorized") { + // user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + // if (userLoginResponse.response != null) { + // AppState().setchatUserDetails = userLoginResponse; + // getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); + // } else { + // Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr"); + // } + // } throw e; } } Future favUser({required int userID, required int targetUserID}) async { Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); return favoriteChatUser; } @@ -114,20 +127,23 @@ class ChatApiClient { {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token, ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } + fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); return favoriteChatUser; } catch (e) { e as APIException; - if (e.message == "api_common_unauthorized") { - logger.d("Token Generated On APIIIIII"); - user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); - if (userLoginResponse.response != null) { - AppState().setchatUserDetails = userLoginResponse; - unFavUser(userID: userID, targetUserID: targetUserID); - } else { - Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr"); - } - } + // if (e.message == "api_common_unauthorized") { + // user.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); + // if (userLoginResponse.response != null) { + // AppState().setchatUserDetails = userLoginResponse; + // unFavUser(userID: userID, targetUserID: targetUserID); + // } else { + // Utils.showToast(userLoginResponse.errorResponses!.first.fieldName.toString() + " Erorr"); + // } + // } throw e; } } @@ -138,6 +154,7 @@ class ChatApiClient { request.files.add(await MultipartFile.fromPath('files', file.path)); request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); StreamedResponse response = await request.send(); + if (!kReleaseMode) {} return response; } @@ -159,6 +176,9 @@ class ChatApiClient { {"encryptedEmails": encryptedEmails, "fromClient": false}, token: AppState().chatDetails!.response!.token, ); + if (!kReleaseMode) { + logger.i("res: " + response.body); + } return chatUserImageModelFromJson(response.body); } } diff --git a/lib/api/dashboard_api_client.dart b/lib/api/dashboard_api_client.dart index e30af91..48063c3 100644 --- a/lib/api/dashboard_api_client.dart +++ b/lib/api/dashboard_api_client.dart @@ -180,12 +180,7 @@ class DashboardApiClient { }, url, postParams); } - Future getChatCount() async { - Response response = await ApiClient().getJsonForResponse( - "${ApiConsts.chatLoginTokenUrl}unreadconversationcount/${AppState().getUserName}", - ); - return chatUnreadCovnCountModelFromJson(response.body); - } + // Future setAdvertisementViewed(String masterID, int advertisementId) async { // String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed"; diff --git a/lib/models/chat/chat_count_conversation_model.dart b/lib/models/chat/chat_count_conversation_model.dart index e584d32..1906803 100644 --- a/lib/models/chat/chat_count_conversation_model.dart +++ b/lib/models/chat/chat_count_conversation_model.dart @@ -1,8 +1,8 @@ -import 'dart:convert'; - -ChatUnreadCovnCountModel chatUnreadCovnCountModelFromJson(String str) => ChatUnreadCovnCountModel.fromJson(json.decode(str)); +// To parse this JSON data, do +// +// final chatUnreadCovnCountModel = chatUnreadCovnCountModelFromMap(jsonString); -String chatUnreadCovnCountModelToJson(ChatUnreadCovnCountModel data) => json.encode(data.toJson()); +import 'dart:convert'; class ChatUnreadCovnCountModel { ChatUnreadCovnCountModel({ @@ -13,13 +13,17 @@ class ChatUnreadCovnCountModel { int? singleChatCount; int? groupChatCount; - factory ChatUnreadCovnCountModel.fromJson(Map json) => ChatUnreadCovnCountModel( - singleChatCount: json["singleChatCount"] == null ? null : json["singleChatCount"], - groupChatCount: json["groupChatCount"] == null ? null : json["groupChatCount"], - ); + factory ChatUnreadCovnCountModel.fromJson(String str) => ChatUnreadCovnCountModel.fromMap(json.decode(str)); + + String toJson() => json.encode(toMap()); + + factory ChatUnreadCovnCountModel.fromMap(Map json) => ChatUnreadCovnCountModel( + singleChatCount: json["singleChatCount"] == null ? null : json["singleChatCount"], + groupChatCount: json["groupChatCount"] == null ? null : json["groupChatCount"], + ); - Map toJson() => { - "singleChatCount": singleChatCount == null ? null : singleChatCount, - "groupChatCount": groupChatCount == null ? null : groupChatCount, - }; + Map toMap() => { + "singleChatCount": singleChatCount == null ? null : singleChatCount, + "groupChatCount": groupChatCount == null ? null : groupChatCount, + }; } diff --git a/lib/models/chat/get_search_user_chat_model.dart b/lib/models/chat/get_search_user_chat_model.dart index fe87061..3d023fd 100644 --- a/lib/models/chat/get_search_user_chat_model.dart +++ b/lib/models/chat/get_search_user_chat_model.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + class ChatUserModel { ChatUserModel({ this.response, @@ -35,6 +37,7 @@ class ChatUser { this.isTyping, this.isImageLoaded, this.isImageLoading, + this.userLocalDownlaodedImage, }); int? id; @@ -52,24 +55,25 @@ class ChatUser { bool? isTyping; bool? isImageLoaded; bool? isImageLoading; + File? userLocalDownlaodedImage; factory ChatUser.fromJson(Map 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, - isImageLoaded: false, - isImageLoading: true, - ); + 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, + isImageLoaded: false, + isImageLoading: true, + userLocalDownlaodedImage: null); Map toJson() => { "id": id == null ? null : id, diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 5fb4cbf..94a296a 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/classes/consts.dart'; import 'package:mohem_flutter_app/classes/encryption.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/main.dart'; +import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart'; import 'package:mohem_flutter_app/models/chat/chat_user_image_model.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'; @@ -19,6 +20,8 @@ import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' a import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/image_picker.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:uuid/uuid.dart'; @@ -39,6 +42,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { List repliedMsg = []; List favUsersList = []; int paginationVal = 0; + bool currentUserTyping = false; + + //Chat + int chatUConvCounter = 0; Future getUserAutoLoginToken() async { userLoginToken.UserAutoLoginModel userLoginResponse = await ChatApiClient().getUserLoginToken(); @@ -56,30 +63,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { await chatHubConnection.start(); print("Startedddddddd"); chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); + chatHubConnection.on("OnGetChatConversationCount", onNewChatConversion); } Future getHubConnection() async { HubConnection hub; - // try { HttpConnectionOptions httpOp = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true); hub = HubConnectionBuilder() .withUrl(ApiConsts.chatHubConnectionUrl + "?UserId=${AppState().chatDetails!.response!.id}&source=Web&access_token=${AppState().chatDetails!.response!.token}", options: httpOp) .withAutomaticReconnect(retryDelays: [2000, 5000, 10000, 20000]).build(); - // isChatHubLoding = false; return hub; - // } catch (e) { - // getUserAutoLoginToken().whenComplete(() { - // getHubConnection(); - // }); - // throw e; - // } } void registerEvents() { chatHubConnection.on("OnUpdateUserStatusAsync", changeStatus); // chatHubConnection.on("OnDeliveredChatUserAsync", onMsgReceived); // hubConnection.on("OnSeenChatUserAsync", onChatSeen); - //hubConnection.on("OnUserTypingAsync", onUserTyping); + chatHubConnection.on("OnUserTypingAsync", onUserTyping); chatHubConnection.on("OnUserCountAsync", userCountAsync); // hubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); @@ -164,7 +164,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } isLoading = false; notifyListeners(); + markRead(userChatHistory, receiverUID); + generateConvId(); } @@ -176,26 +178,28 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void markRead(List data, int receiverID) { if (data != null) { for (SingleUserChatModel element in data!) { - if (element.isSeen != null) { - if (!element.isSeen!) { - element.isSeen = true; - dynamic data = [ - { - "userChatHistoryId": element.userChatHistoryId, - "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, - "isDelivered": true, - "isSeen": true, - } - ]; - updateUserChatHistoryStatusAsync(data); - notifyListeners(); + if (AppState().chatDetails!.response!.id! == element.targetUserId) { + if (element.isSeen != null) { + if (!element.isSeen!) { + element.isSeen = true; + dynamic data = [ + { + "userChatHistoryId": element.userChatHistoryId, + "TargetUserId": element.currentUserId == receiverID ? element.currentUserId : element.targetUserId, + "isDelivered": true, + "isSeen": true, + } + ]; + updateUserChatHistoryStatusAsync(data); + notifyListeners(); + } + } + for (ChatUser element in searchedChats!) { + if (element.id == receiverID) { + element.unreadMessageCount = 0; + chatUConvCounter = 0; + } } - } - } - for (ChatUser element in searchedChats!) { - if (element.id == receiverID) { - element.unreadMessageCount = 0; - // notifyListeners(); } } notifyListeners(); @@ -346,9 +350,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } } } - dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); - if (contain.isEmpty) { - searchedChats!.add(ChatUser(id: data.first.currentUserId, userName: data.first.currentUserName, unreadMessageCount: 0, isImageLoading: false, image: "", isImageLoaded: true, userStatus: 1)); + + if (searchedChats != null) { + dynamic contain = searchedChats!.where((ChatUser element) => element.id == data.first.currentUserId); + if (contain.isEmpty) { + searchedChats!.add( + ChatUser( + id: data.first.currentUserId, + userName: data.first.currentUserName, + unreadMessageCount: 0, + isImageLoading: false, + image: "", + isImageLoaded: true, + userStatus: 1, + isTyping: false, + userLocalDownlaodedImage: null), + ); + } } setMsgTune(); @@ -368,6 +386,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { {"userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive ? true : false} ]; updateUserChatHistoryOnMsg(list); + invokeChatCounter(userId: AppState().chatDetails!.response!.id!); notifyListeners(); } @@ -384,7 +403,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { if (user.id == parameters![1] && parameters[0] == true) { user.isTyping = parameters[0] as bool?; Future.delayed( - const Duration(seconds: 2), + const Duration(seconds: 1), () { user.isTyping = false; notifyListeners(); @@ -392,6 +411,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { ); } } + if (isChatScreenActive) { + currentUserTyping = true; + notifyListeners(); + Future.delayed( + const Duration(seconds: 2), + () { + currentUserTyping = false; + notifyListeners(); + }, + ); + } notifyListeners(); } @@ -473,7 +503,6 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { required bool isImageLoaded}) async { Uuid uuid = const Uuid(); String contentNo = uuid.v4(); - String msg = message.text; SingleUserChatModel data = SingleUserChatModel( chatEventId: chatEventId, @@ -492,8 +521,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { fileTypeResponse: isAttachment ? FileTypeResponse( fileTypeId: fileTypeId, - fileTypeName: getFileType(getFileExtension(selectedFile.path).toString()), - fileKind: getFileExtension(selectedFile.path), + fileTypeName: getFileExtension(selectedFile.path).toString(), + fileKind: "file", fileName: selectedFile.path.split("/").last, fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), ) @@ -517,7 +546,17 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); if (contain.isEmpty) { searchedChats!.add( - ChatUser(id: targetUserId, userName: targetUserName, unreadMessageCount: 0, isImageLoading: false, image: "", isImageLoaded: true), + ChatUser( + id: targetUserId, + userName: targetUserName, + unreadMessageCount: 0, + isImageLoading: false, + image: "", + isImageLoaded: true, + isTyping: false, + isFav: false, + userLocalDownlaodedImage: null, + ), ); notifyListeners(); } @@ -530,6 +569,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { chatEventId: 1, fileTypeId: null, targetUserId: targetUserId, targetUserName: targetUserName, isAttachment: false, chatReplyId: null, isReply: false, isImageLoaded: false, image: null); } // normal Text msg if (isFileSelected && !isMsgReply) { + bool isImage = false; print("Normal Attachment Msg"); Utils.showLoading(context); dynamic value = await uploadAttachments(AppState().chatDetails!.response!.id.toString(), selectedFile); @@ -605,6 +645,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { String? getFileExtension(String fileName) { try { + print("Ext: " + "." + fileName.split('.').last); return "." + fileName.split('.').last; } catch (e) { return null; @@ -740,6 +781,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUserImageModel uImage in chatImages) { if (user.email == uImage.email) { user.image = uImage.profilePicture ?? ""; + user.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, user.id.toString()); user.isImageLoading = false; user.isImageLoaded = true; } @@ -749,6 +791,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { for (ChatUserImageModel uImage in chatImages) { if (favUser.email == uImage.email) { favUser.image = uImage.profilePicture ?? ""; + favUser.userLocalDownlaodedImage = await downloadImageLocal(uImage.profilePicture, favUser.id.toString()); favUser.isImageLoading = false; favUser.isImageLoaded = true; } @@ -758,6 +801,35 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); } + Future downloadImageLocal(String? encodedBytes, String userID) async { + File? myfile; + if (encodedBytes == null) { + return myfile; + } else { + await deleteFile(userID); + Uint8List decodedBytes = base64Decode(encodedBytes); + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); // 1 + late File imageFile = File("${appDocumentsDirectory.path}/$userID.jpg"); + imageFile.writeAsBytesSync(decodedBytes); + return imageFile; + } + } + + Future deleteFile(String userID) async { + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + late File imageFile = File('${appDocumentsDirectory.path}/$userID.jpg'); + if (await imageFile.exists()) { + await imageFile.delete(); + } + } + + Future downChatMedia(Uint8List bytes, String ext) async { + String dir = (await getApplicationDocumentsDirectory()).path; + File file = File("$dir/" + DateTime.now().millisecondsSinceEpoch.toString() + "." + ext); + await file.writeAsBytes(bytes); + return file.path; + } + void setMsgTune() async { AudioPlayer player = AudioPlayer(); await player.setVolume(1.0); @@ -775,4 +847,29 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { print("Error: $e"); } } + + Future getChatMedia({required String fileName, required String fileTypeName, required int fileTypeID}) async { + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2) { + Uint8List encodedString = await ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: getFileTypeDescription(fileTypeName)); + try { + String path = await downChatMedia(encodedString, fileTypeName ?? ""); + OpenFile.open(path); + } catch (e) { + Utils.showToast("Cannot open file."); + } + } + } + + void onNewChatConversion(List? params) { + dynamic items = params!.toList(); + logger.d(items); + chatUConvCounter = items[0]["singleChatCount"] ?? 0; + notifyListeners(); + } + + Future invokeChatCounter({required int userId}) async { + print("invokedd"); + await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); + return ""; + } } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 48531b7..c1a186a 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -7,7 +7,6 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; -import 'package:mohem_flutter_app/models/chat/chat_count_conversation_model.dart'; import 'package:mohem_flutter_app/models/dashboard/drawer_menu_item_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_accrual_balances_list_model.dart'; import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart'; @@ -20,6 +19,7 @@ import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_respo import 'package:mohem_flutter_app/models/generic_response_model.dart'; import 'package:mohem_flutter_app/models/itg/itg_response_model.dart'; import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart'; +import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/widgets/dialogs/confirm_dialog.dart'; /// Mix-in [DiagnosticableTreeMixin] to have access to [debugFillProperties] for the devtool @@ -35,9 +35,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { bool isWorkListLoading = true; int workListCounter = 0; - //Chat - bool isChatCounterLoding = true; - int chatUConvCounter = 0; + //Misssing Swipe bool isMissingSwipeLoading = true; @@ -96,8 +94,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { accrualList = null; leaveBalanceAccrual = null; - isChatCounterLoding = true; - chatUConvCounter = 0; ticketBalance = 0; isServicesMenusLoading = true; @@ -273,21 +269,6 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { MohemmItgResponseItem? res = await DashboardApiClient().getITGPageNotification(); return res; } - - void fetchChatCounts() async { - try { - ChatUnreadCovnCountModel response = await DashboardApiClient().getChatCount(); - chatUConvCounter = response.singleChatCount!; - isChatCounterLoding = false; - notifyListeners(); - } catch (ex) { - logger.wtf(ex); - notifyListeners(); - Utils.handleException(ex, null, null); - } - } - - void notify() { notifyListeners(); } diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index ea43004..3e99678 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -1,17 +1,23 @@ +import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.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/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/main.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; +import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; +import 'package:open_file/open_file.dart'; +import 'package:provider/provider.dart'; // todo: @aamir use extension methods, and use correct widgets. @@ -19,11 +25,12 @@ class ChatBubble extends StatelessWidget { ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key); final String dateTime; final SingleUserChatModel cItem; - bool isCurrentUser = false; bool isSeen = false; bool isReplied = false; int? fileTypeID; + String? fileTypeName; + late ChatProviderModel data; String? fileTypeDescription; bool isDelivered = false; @@ -35,6 +42,7 @@ class ChatBubble extends StatelessWidget { isSeen = cItem.isSeen == true ? true : false; isReplied = cItem.userChatReplyResponse != null ? true : false; fileTypeID = cItem.fileTypeId; + fileTypeName = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeName : ""; fileTypeDescription = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeDescription : ""; isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && cItem.isDelivered == true ? true : false; userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString(); @@ -45,6 +53,8 @@ class ChatBubble extends StatelessWidget { Size windowSize = MediaQuery.of(context).size; screenOffset = Offset(windowSize.width / 2, windowSize.height / 2); makeAssign(); + data = Provider.of(context, listen: false); + return isCurrentUser ? currentUser(context) : receiptUser(context); } @@ -77,22 +87,6 @@ class ChatBubble extends StatelessWidget { if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 || cItem.userChatReplyResponse!.fileTypeId == 3 || cItem.userChatReplyResponse!.fileTypeId == 4) - // Container( - // padding: EdgeInsets.all(0), // Border width - // decoration: BoxDecoration(color: Colors.red, borderRadius: const BorderRadius.all(Radius.circular(8))), - // child: ClipRRect( - // borderRadius: const BorderRadius.all( - // Radius.circular(8), - // ), - // child: SizedBox.fromSize( - // size: Size.fromRadius(8), // Image radius - // child: showImage( - // isReplyPreview: true, - // fileName: cItem.userChatReplyResponse!.contant!, - // fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"), - // ), - // ), - // ), ClipRRect( borderRadius: BorderRadius.circular(8.0), child: SizedBox( @@ -116,8 +110,15 @@ class ChatBubble extends StatelessWidget { anchorPoint: screenOffset, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!), ); - }), - cItem.contant!.toText12(), + }) + else + Row( + children: [ + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2) + SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), + (cItem.contant ?? "").toText12(), + ], + ), Align( alignment: Alignment.centerRight, child: Row( @@ -200,7 +201,16 @@ class ChatBubble extends StatelessWidget { ); }) else - (cItem.contant ?? "").toText12(color: Colors.white), + Row( + children: [ + if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 || fileTypeID == 2) + SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly( + left: 0, + right: 10, + ), + (cItem.contant ?? "").toText12(color: Colors.white), + ], + ), Align( alignment: Alignment.centerRight, child: dateTime.toText10(color: Colors.white.withOpacity(.71)), diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 2ab5fd8..335eda7 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/call.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/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart'; @@ -23,9 +24,15 @@ import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:swipe_to/swipe_to.dart'; +class ChatDetailedScreenParams { + ChatUser? chatUser; + bool? isNewChat; + + ChatDetailedScreenParams(this.chatUser, this.isNewChat); +} + class ChatDetailScreen extends StatefulWidget { - // ignore: prefer_const_constructors_in_immutables - ChatDetailScreen({Key? key}) : super(key: key); + const ChatDetailScreen({Key? key}) : super(key: key); @override State createState() => _ChatDetailScreenState(); @@ -33,16 +40,16 @@ class ChatDetailScreen extends StatefulWidget { class _ChatDetailScreenState extends State { final RefreshController _rc = RefreshController(initialRefresh: false); - dynamic userDetails; late ChatProviderModel data; + ChatDetailedScreenParams? params; void getMoreChat() async { - if (userDetails != null) { + if (params != null) { data.paginationVal = data.paginationVal + 10; - if (userDetails != null) { + if (params != null) { data.getSingleUserChatHistory( senderUID: AppState().chatDetails!.response!.id!.toInt(), - receiverUID: userDetails["targetUser"].id, + receiverUID: params!.chatUser!.id!, loadMore: true, isNewChat: false, ); @@ -56,14 +63,14 @@ class _ChatDetailScreenState extends State { @override Widget build(BuildContext context) { - userDetails = ModalRoute.of(context)!.settings.arguments; + params = ModalRoute.of(context)!.settings.arguments as ChatDetailedScreenParams; data = Provider.of(context, listen: false); - if (userDetails != null) { + if (params != null) { data.getSingleUserChatHistory( senderUID: AppState().chatDetails!.response!.id!.toInt(), - receiverUID: userDetails["targetUser"].id, + receiverUID: params!.chatUser!.id!, loadMore: false, - isNewChat: userDetails["isNewChat"], + isNewChat: params!.isNewChat!, ); } @@ -71,9 +78,10 @@ class _ChatDetailScreenState extends State { backgroundColor: MyColors.backgroundColor, appBar: AppBarWidget( context, - title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach, + title: params!.chatUser!.userName.toString().replaceAll(".", " ").capitalizeFirstofEach, showHomeButton: false, - image: userDetails["targetUser"].image == null || userDetails["targetUser"].image.isEmpty ? null : userDetails["targetUser"].image, + image: params!.chatUser!.image == null || params!.chatUser!.image.isEmpty ? null : params!.chatUser!.image, + showTyping: true, actions: [ SvgPicture.asset("assets/icons/chat/call.svg", width: 21, height: 23).onPress(() { // makeCall(callType: "AUDIO", con: hubConnection); @@ -124,8 +132,13 @@ class _ChatDetailScreenState extends State { m.userChatHistory[i], ); }, - ).onPress(() { - logger.d(jsonEncode(m.userChatHistory[i])); + ).onPress(() async { + if (m.userChatHistory[i].fileTypeResponse != null) { + m.getChatMedia( + fileTypeName: m.userChatHistory[i].fileTypeResponse!.fileTypeName ?? "", + fileTypeID: m.userChatHistory[i].fileTypeResponse!.fileTypeId!, + fileName: m.userChatHistory[i].contant!); + } }); }, ), @@ -152,7 +165,7 @@ class _ChatDetailScreenState extends State { ], ).expanded, 12.width, - if (m.isMsgReply && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg), + if (m.isMsgReply && m.repliedMsg.isNotEmpty) showReplyImage(m.repliedMsg, m), 12.width, const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe), ], @@ -209,7 +222,7 @@ class _ChatDetailScreenState extends State { ), ).paddingOnly(right: 25), SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26).onPress( - () => m.sendChatMessage(userDetails["targetUser"].id, userDetails["targetUser"].userName, context), + () => m.sendChatMessage(params!.chatUser!.id!, params!.chatUser!.userName!, context), ), ], ), @@ -223,7 +236,8 @@ class _ChatDetailScreenState extends State { ); } - Widget showReplyImage(List data) { + Widget showReplyImage(List data, ChatProviderModel m) { + logger.d(jsonEncode(data)); if (data.first.isImageLoaded! && data.first.image != null) { return Container( width: 43, @@ -232,7 +246,14 @@ class _ChatDetailScreenState extends State { border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), image: DecorationImage(image: MemoryImage(data.first.image!), fit: BoxFit.cover)), ); } else { - return const SizedBox(); + return data.first.fileTypeResponse != null + ? Container( + width: 43, + height: 43, + constraints: BoxConstraints(), + decoration: BoxDecoration(border: Border.all(color: MyColors.darkGrey3BColor, width: 1), borderRadius: BorderRadius.circular(10.0), color: Colors.white), + child: SvgPicture.asset(m.getType(data.first.fileTypeResponse!.fileTypeName), alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 5, right: 5, top: 5, bottom: 5)) + : SizedBox(); } } @@ -240,7 +261,7 @@ class _ChatDetailScreenState extends State { print("================== Make call Triggered ============================"); Map json = { "callerID": AppState().chatDetails!.response!.id!.toString(), - "callReceiverID": userDetails["targetUser"].id.toString(), + "callReceiverID": params!.chatUser!.id.toString(), "notification_foreground": "true", "message": "Aamir is calling", "title": "Video Call", @@ -259,7 +280,7 @@ class _ChatDetailScreenState extends State { { "isSeen": false, "isDelivered": false, - "targetUserId": userDetails["targetUser"].id, + "targetUserId": params!.chatUser!.id!, "targetUserStatus": 4, } ], diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 76aa027..7d0631e 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -30,6 +30,16 @@ class _ChatHomeState extends State { super.initState(); data = Provider.of(context, listen: false); data.registerEvents(); + } + + @override + void dispose() { + super.dispose(); + data.clearAll(); + } + + void fetchAgain() { + print("Fetch Triggered"); if (chatHubConnection.state != HubConnectionState.Connected) { data.getUserAutoLoginToken().whenComplete(() async { await data.buildHubConnection(); @@ -42,14 +52,9 @@ class _ChatHomeState extends State { } } - @override - void dispose() { - super.dispose(); - data.clearAll(); - } - @override Widget build(BuildContext context) { + fetchAgain(); return Scaffold( backgroundColor: MyColors.white, appBar: AppBarWidget(context, title: LocaleKeys.chat.tr(), showHomeButton: true), @@ -85,7 +90,6 @@ class _ChatHomeState extends State { onPageChanged: (int pageIndex) { setState(() { tabIndex = pageIndex; - }); }, children: [ diff --git a/lib/ui/chat/chat_home_screen.dart b/lib/ui/chat/chat_home_screen.dart index 804332a..669504f 100644 --- a/lib/ui/chat/chat_home_screen.dart +++ b/lib/ui/chat/chat_home_screen.dart @@ -1,22 +1,19 @@ import 'dart:convert'; -import 'dart:typed_data'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_des/flutter_des.dart'; import 'package:flutter_svg/flutter_svg.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/encryption.dart'; import 'package:mohem_flutter_app/config/routes.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/provider/chat_provider_model.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.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/circular_avatar.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'; @@ -53,7 +50,9 @@ class _ChatHomeScreenState extends State { body: Consumer( builder: (BuildContext context, ChatProviderModel m, Widget? child) { return m.isLoading - ? ChatHomeShimmer(isDetailedScreen: false,) + ? ChatHomeShimmer( + isDetailedScreen: false, + ) : Column( children: [ TextField( @@ -102,20 +101,24 @@ class _ChatHomeScreenState extends State { height: 48, width: 48, ).toShimmer().circle(30), - if (m.searchedChats![index].isImageLoaded! && m.searchedChats![index].image.isNotEmpty) - CircularAvatar( - radius: 20, - height: 48, - width: 48, - url: m.searchedChats![index].image, - isImageBase64: true, - ), - if (!m.searchedChats![index].isImageLoading! && m.searchedChats![index].isImageLoaded! && m.searchedChats![index].image.isEmpty) + if (!m.searchedChats![index].isImageLoading! && m.searchedChats![index].userLocalDownlaodedImage == null) SvgPicture.asset( "assets/images/user.svg", height: 48, width: 48, ), + if (!m.searchedChats![index].isImageLoading! && m.searchedChats![index].userLocalDownlaodedImage != null) + Container( + width: 48.0, + height: 48.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + fit: BoxFit.cover, + image: FileImage(m.searchedChats![index].userLocalDownlaodedImage!), + ), + ), + ), Positioned( right: 5, bottom: 1, @@ -128,14 +131,13 @@ class _ChatHomeScreenState extends State { ).circle(10), ) ], - ).onPress(() { - print(jsonEncode(m.searchedChats![index])); - }), + ), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ (m.searchedChats![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13), + (m.searchedChats![index].isTyping! ? "Typing ..." : "").toText10(color: MyColors.lightGreyColor).paddingOnly(left: 11, top: 0), ], ).expanded, SizedBox( @@ -194,7 +196,7 @@ class _ChatHomeScreenState extends State { Navigator.pushNamed( context, AppRoutes.chatDetailed, - arguments: {"targetUser": m.searchedChats![index], "isNewChat": false}, + arguments: ChatDetailedScreenParams(m.searchedChats![index], false), ).then((Object? value) { m.clearSelections(); m.notifyListeners(); diff --git a/lib/ui/chat/favorite_users_screen.dart b/lib/ui/chat/favorite_users_screen.dart index 9378625..157a884 100644 --- a/lib/ui/chat/favorite_users_screen.dart +++ b/lib/ui/chat/favorite_users_screen.dart @@ -9,6 +9,7 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/config/routes.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart'; import 'package:provider/provider.dart'; @@ -45,20 +46,24 @@ class ChatFavoriteUsersScreen extends StatelessWidget { height: 48, width: 48, ).toShimmer().circle(30), - if (m.favUsersList![index].isImageLoaded! && m.favUsersList![index].image != null && m.favUsersList![index].image.isNotEmpty) - CircularAvatar( - radius: 20, - height: 48, - width: 48, - url: m.favUsersList![index].image, - isImageBase64: true, - ), - if (!m.favUsersList![index].isImageLoading! && m.favUsersList![index].isImageLoaded! && m.favUsersList![index].image.isEmpty) + if (!m.favUsersList![index].isImageLoading! && m.favUsersList![index].userLocalDownlaodedImage == null) SvgPicture.asset( "assets/images/user.svg", height: 48, width: 48, ), + if (!m.favUsersList![index].isImageLoading! && m.favUsersList![index].userLocalDownlaodedImage != null) + Container( + width: 48.0, + height: 48.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + fit: BoxFit.cover, + image: FileImage(m.favUsersList![index].userLocalDownlaodedImage!), + ), + ), + ), Positioned( right: 5, bottom: 1, @@ -106,7 +111,7 @@ class ChatFavoriteUsersScreen extends StatelessWidget { Navigator.pushNamed( context, AppRoutes.chatDetailed, - arguments: {"targetUser": m.favUsersList![index], "isNewChat": false}, + arguments: ChatDetailedScreenParams(m.favUsersList![index], false), ).then( (Object? value) { m.clearSelections(); diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 4e6988b..0e9053a 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -90,7 +90,6 @@ class _DashboardScreenState extends State { data.fetchMenuEntries(); data.getCategoryOffersListAPI(context); marathonProvider.getMarathonDetailsFromApi(); - data.fetchChatCounts(); _refreshController.refreshCompleted(); } @@ -503,8 +502,8 @@ class _DashboardScreenState extends State { "assets/icons/chat/chat.svg", color: currentIndex == 4 ? MyColors.grey3AColor : MyColors.grey98Color, ).paddingAll(4), - Consumer( - builder: (BuildContext cxt, DashboardProviderModel data, Widget? child) { + Consumer( + builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { return Positioned( right: 0, top: 0, @@ -538,9 +537,7 @@ class _DashboardScreenState extends State { } else if (index == 3) { Navigator.pushNamed(context, AppRoutes.itemsForSale); } else if (index == 4) { - Navigator.pushNamed(context, AppRoutes.chat).then((Object? value) { - data.fetchChatCounts(); - }); + Navigator.pushNamed(context, AppRoutes.chat); } }, ), diff --git a/lib/widgets/app_bar_widget.dart b/lib/widgets/app_bar_widget.dart index 199074a..3903327 100644 --- a/lib/widgets/app_bar_widget.dart +++ b/lib/widgets/app_bar_widget.dart @@ -5,7 +5,9 @@ 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/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:provider/provider.dart'; AppBar AppBarWidget(BuildContext context, {required String title, @@ -13,6 +15,7 @@ AppBar AppBarWidget(BuildContext context, bool showNotificationButton = false, bool showMemberButton = false, String? image, + bool showTyping = false, List? actions, void Function()? onHomeTapped, void Function()? onBackTapped}) { @@ -43,6 +46,16 @@ AppBar AppBarWidget(BuildContext context, ), if (image != null) 14.width, title.toText24(color: MyColors.darkTextColor, isBold: true).expanded, + if(showTyping) + Consumer( + builder: (BuildContext cxt, ChatProviderModel data, Widget? child) { + if (data.currentUserTyping) { + return ("Typing ...").toText10(color: MyColors.lightGreyColor).paddingOnly(left: 5, top: 0); + } else { + return const SizedBox(); + } + }, + ), ], ), centerTitle: false, diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index 475c4a5..77501bc 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -20,6 +20,7 @@ import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; import 'package:mohem_flutter_app/models/get_action_history_list_model.dart'; import 'package:mohem_flutter_app/models/worklist/get_favorite_replacements_model.dart'; import 'package:mohem_flutter_app/models/worklist/replacement_list_model.dart'; +import 'package:mohem_flutter_app/ui/chat/chat_detailed_screen.dart'; import 'package:mohem_flutter_app/widgets/button/default_button.dart'; import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart'; @@ -238,7 +239,7 @@ class _SearchEmployeeBottomSheetState extends State { Navigator.pushNamed( context, AppRoutes.chatDetailed, - arguments: {"targetUser": chatUsersList![index], "isNewChat": true}, + arguments: ChatDetailedScreenParams(chatUsersList![index], true), ); }, ), diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 69bf7e4..75466fc 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -45,7 +45,7 @@ class ImageOptions { onFilesTap: () async { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, - allowedExtensions: ['jpg', 'jpeg ', 'pdf', 'txt', 'docx', 'doc', 'pptx', 'xlsx', 'png', 'rar', 'zip', 'xls'], + allowedExtensions: ['jpg', 'jpeg ', 'pdf', 'txt', 'docx', 'doc', 'pptx', 'xlsx', 'png', 'rar', 'zip',], ); List files = result!.paths.map((path) => File(path!)).toList(); image(result.files.first.path.toString(), files.first);