From 4f78e23922ab90016c5b5642498f25d22d03b086 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 19 Nov 2025 12:31:10 +0300 Subject: [PATCH] chat widget finalized. --- .../providers/api/gas_refill_provider.dart | 8 ++- lib/modules/cx_module/chat/chat_page.dart | 26 +++++---- lib/modules/cx_module/chat/chat_provider.dart | 58 ++++++++++++------- lib/modules/cx_module/chat/chat_widget.dart | 40 ++++++++++--- .../user/gas_refill/gas_refill_details.dart | 27 ++++++--- 5 files changed, 107 insertions(+), 52 deletions(-) diff --git a/lib/controllers/providers/api/gas_refill_provider.dart b/lib/controllers/providers/api/gas_refill_provider.dart index 40d6327a..8b522790 100644 --- a/lib/controllers/providers/api/gas_refill_provider.dart +++ b/lib/controllers/providers/api/gas_refill_provider.dart @@ -47,12 +47,16 @@ class GasRefillProvider extends ChangeNotifier { // failed _loading = false bool isLoading = false; + GasRefillModel? gasRefillModel; + Future getGasRefillObjectById(num id) async { try { + gasRefillModel = null; Response response = await ApiManager.instance.get(URLs.getGasRefillById + "?gasRefillId=$id"); - if (response.statusCode >= 200 && response.statusCode < 300) { - return GasRefillModel.fromJson(json.decode(response.body)["data"]); + gasRefillModel = GasRefillModel.fromJson(json.decode(response.body)["data"]); + notifyListeners(); + return gasRefillModel; } else { return null; } diff --git a/lib/modules/cx_module/chat/chat_page.dart b/lib/modules/cx_module/chat/chat_page.dart index 8a22fd1b..0ff1f567 100644 --- a/lib/modules/cx_module/chat/chat_page.dart +++ b/lib/modules/cx_module/chat/chat_page.dart @@ -34,12 +34,14 @@ enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } class ChatPage extends StatefulWidget { int moduleId; int requestId; - String assigneeEmployeeNumber; - String myEmployeeID; + String? assigneeEmployeeNumber; + String? myLoginUserID; + String? contactEmployeeINumber; String title; bool readOnly; - ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false, this.assigneeEmployeeNumber = "", this.myEmployeeID = ""}) : super(key: key); + ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false, this.assigneeEmployeeNumber, this.myLoginUserID, this.contactEmployeeINumber}) + : super(key: key); @override _ChatPageState createState() { @@ -86,18 +88,20 @@ class _ChatPageState extends State { // ? assigneeEmployeeNumber // :myEmployeeId; - String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; - String myEmployeeId = context.userProvider.user!.username!; + String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = widget.myLoginUserID ?? context.userProvider.user!.username!; receiver = context.userProvider.isNurse ? assigneeEmployeeNumber - : (context.userProvider.isEngineer ? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId! : ""); - Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver); + : (context.userProvider.isEngineer + ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) + : ""); + Provider.of(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); } @override void dispose() { - chatHubConnection.stop(); + chatHubConnection?.stop(); playerController.dispose(); recorderController.dispose(); super.dispose(); @@ -246,13 +250,13 @@ class _ChatPageState extends State { textInputAction: TextInputAction.none, keyboardType: TextInputType.multiline, onTap: () { - chatHubConnection.invoke("SendTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendTypingAsync", args: [receiver]); }, onTapOutside: (PointerDownEvent event) { - chatHubConnection.invoke("SendStopTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendStopTypingAsync", args: [receiver]); }, onChanged: (text) { - chatHubConnection.invoke("SendTypingAsync", args: [receiver]); + chatHubConnection!.invoke("SendTypingAsync", args: [receiver]); }, decoration: InputDecoration( enabledBorder: InputBorder.none, diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 6aadcc44..136dd28b 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -54,7 +54,7 @@ import 'model/get_single_user_chat_list_model.dart'; import 'model/user_chat_history_model.dart'; // import 'get_single_user_chat_list_model.dart'; -late HubConnection chatHubConnection; +HubConnection? chatHubConnection; class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { bool isTyping = false; @@ -83,6 +83,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { int? referenceID; void reset() { + chatHubConnection?.stop().then((value) { + chatHubConnection = null; + }); chatLoginTokenLoading = false; chatParticipantLoading = false; userChatHistoryLoading = false; @@ -108,11 +111,13 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } // } - Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber) async { + Future getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber, {bool isMounted = true}) async { reset(); receiverID = assigneeEmployeeNumber; chatLoginTokenLoading = true; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } try { chatLoginResponse = await ChatApiClient().getChatLoginToken(moduleId, requestId, title, myId, assigneeEmployeeNumber); chatParticipantModel = await ChatApiClient().loadParticipants(moduleId, requestId, assigneeEmployeeNumber); @@ -122,7 +127,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { print(ex); } chatLoginTokenLoading = false; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } } // Future getUserLoadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { @@ -146,17 +153,24 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } catch (e) {} // } - Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { + Future connectToHub(int moduleId, int requestId, String myId, String assigneeEmployeeNumber, bool readOnly, {bool isMounted = true}) async { userChatHistoryLoading = true; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } moduleID = moduleId; referenceID = requestId; - await buildHubConnection(chatParticipantModel!.id!.toString()); + if (!readOnly) { + await buildHubConnection(chatParticipantModel!.id!.toString()); + } + userChatHistory = await ChatApiClient().loadChatHistory(moduleId, requestId, myId, assigneeEmployeeNumber); chatResponseList = userChatHistory ?? []; chatResponseList.sort((a, b) => b.createdDate!.compareTo(a.createdDate!)); userChatHistoryLoading = false; - notifyListeners(); + if (isMounted) { + notifyListeners(); + } } // Future loadChatHistory(int moduleId, int requestId, String myId, String assigneeEmployeeNumber) async { @@ -174,7 +188,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { notifyListeners(); bool returnStatus = false; try { - await chatHubConnection.invoke("AddChatUserAsync", args: [object]); + await chatHubConnection!.invoke("AddChatUserAsync", args: [object]); returnStatus = true; } catch (ex) {} @@ -223,17 +237,17 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { Future buildHubConnection(String conversationID) async { chatHubConnection = await getHubConnection(); - await chatHubConnection.start(); + await chatHubConnection!.start(); if (kDebugMode) { print("Hub Conn: Startedddddddd"); } - await chatHubConnection.invoke("JoinConversation", args: [conversationID]); - chatHubConnection.on("ReceiveMessage", onMsgReceived1); - chatHubConnection.on("OnMessageReceivedAsync", onMsgReceived); - chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); - chatHubConnection.on("OnTypingAsync", OnTypingAsync); - chatHubConnection.on("OnStopTypingAsync", OnStopTypingAsync); + await chatHubConnection!.invoke("JoinConversation", args: [conversationID]); + chatHubConnection!.on("ReceiveMessage", onMsgReceived1); + chatHubConnection!.on("OnMessageReceivedAsync", onMsgReceived); + chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync); + chatHubConnection!.on("OnTypingAsync", OnTypingAsync); + chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync); //group On message @@ -255,7 +269,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // chatHubConnection.on("OnSubmitChatAsync", OnSubmitChatAsync); // chatHubConnection.on("OnUserTypingAsync", onUserTyping); - chatHubConnection.on("OnUserCountAsync", userCountAsync); + chatHubConnection?.on("OnUserCountAsync", userCountAsync); // chatHubConnection.on("OnUpdateUserChatHistoryWindowsAsync", updateChatHistoryWindow); // chatHubConnection.on("OnGetUserChatHistoryNotDeliveredAsync", chatNotDelivered); // chatHubConnection.on("OnUpdateUserChatHistoryStatusAsync", updateUserChatStatus); @@ -298,7 +312,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { // } Future invokeUserChatHistoryNotDeliveredAsync({required int userId}) async { - await chatHubConnection.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); + await chatHubConnection!.invoke("GetUserChatHistoryNotDeliveredAsync", args: [userId]); return ""; } @@ -361,7 +375,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryStatusAsync(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -369,7 +383,7 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { void updateUserChatHistoryOnMsg(List data) { try { - chatHubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); + chatHubConnection!.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); } catch (e) { throw e; } @@ -1766,12 +1780,12 @@ void setMsgTune() async { // } Future invokeChatCounter({required int userId}) async { - await chatHubConnection.invoke("GetChatCounversationCount", args: [userId]); + await chatHubConnection!.invoke("GetChatCounversationCount", args: [userId]); return ""; } void userTypingInvoke({required int currentUser, required int reciptUser}) async { - await chatHubConnection.invoke("UserTypingAsync", args: [reciptUser, currentUser]); + await chatHubConnection!.invoke("UserTypingAsync", args: [reciptUser, currentUser]); } // void groupTypingInvoke({required GroupResponse groupDetails, required int groupId}) async { diff --git a/lib/modules/cx_module/chat/chat_widget.dart b/lib/modules/cx_module/chat/chat_widget.dart index b9bc111b..9d7c8a36 100644 --- a/lib/modules/cx_module/chat/chat_widget.dart +++ b/lib/modules/cx_module/chat/chat_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'chat_page.dart'; import 'chat_provider.dart'; @@ -10,12 +11,23 @@ import 'chat_provider.dart'; class ChatWidget extends StatefulWidget { int moduleId; int requestId; - String assigneeEmployeeNumber; - String myEmployeeID; + String? assigneeEmployeeNumber; + String? myLoginUserID; + String? contactEmployeeINumber; bool isReadOnly; + bool isShow; String title; - ChatWidget({Key? key, this.isReadOnly = false, this.title = "Chat", required this.moduleId, required this.requestId, required this.assigneeEmployeeNumber, required this.myEmployeeID}) + ChatWidget( + {Key? key, + this.isReadOnly = false, + this.title = "Chat", + required this.moduleId, + required this.requestId, + this.assigneeEmployeeNumber, + this.myLoginUserID, + this.contactEmployeeINumber, + this.isShow = false}) : super(key: key); @override @@ -33,14 +45,25 @@ class _ChatWidgetState extends State { } void getChatToken() { + // ChatProvider cProvider = Provider.of(context, listen: false); + // if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; + // // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + // String myEmployeeId = widget.myLoginUserID; + // + // String receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + ChatProvider cProvider = Provider.of(context, listen: false); if (cProvider.chatLoginResponse != null && cProvider.referenceID == widget.requestId) return; - // String assigneeEmployeeNumber = Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; - String myEmployeeId = widget.myEmployeeID; + String assigneeEmployeeNumber = widget.assigneeEmployeeNumber ?? Provider.of(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; + String myEmployeeId = widget.myLoginUserID ?? context.userProvider.user!.username!; - String receiver = context.userProvider.isNurse ? widget.assigneeEmployeeNumber : widget.myEmployeeID; + String receiver = context.userProvider.isNurse + ? assigneeEmployeeNumber + : (context.userProvider.isEngineer + ? (widget.contactEmployeeINumber ?? Provider.of(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!) + : ""); - cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver); + cProvider.getUserAutoLoginTokenSilent(widget.moduleId, widget.requestId, widget.title, myEmployeeId, receiver, isMounted: mounted); } @override @@ -63,7 +86,8 @@ class _ChatWidgetState extends State { title: widget.title, readOnly: widget.isReadOnly, assigneeEmployeeNumber: widget.assigneeEmployeeNumber, - myEmployeeID: widget.myEmployeeID, + contactEmployeeINumber: widget.contactEmployeeINumber, + myLoginUserID: widget.myLoginUserID, ))); }, ).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 16aac3d5..3773c898 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -53,19 +53,28 @@ class _GasRefillDetailsPageState extends State { @override Widget build(BuildContext context) { _userProvider = Provider.of(context); - gasRefillProvider = Provider.of(context); + gasRefillProvider = Provider.of(context, listen: false); return Scaffold( appBar: DefaultAppBar( title: context.translation.gasRefillDetails, - // actions: [ - // if (context.userProvider.isEngineer || context.userProvider.isNurse) ...[ - // if (context.userProvider.isEngineer) - // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "1234") - // else - // ChatWidget(moduleId: 4, requestId: 1, assigneeEmployeeNumber: "123456", myEmployeeID: "123456") - // ] - // ], + actions: [ + // if (context.userProvider.isEngineer || context.userProvider.isNurse) + // Selector( + // selector: (_, myModel) => myModel.gasRefillModel, // Selects only the userName + // builder: (_, _gasRefillModel, __) { + // if (_gasRefillModel == null) return const SizedBox(); + // return ChatWidget( + // moduleId: 2, + // isShow: _gasRefillModel.status!.value! == 1, + // // isReadOnly: _gasRefillModel.status!.value! == 1, + // requestId: widget.model.id!.toInt(), + // assigneeEmployeeNumber: _gasRefillModel.assignedEmployee!.name!, + // myLoginUserID: context.userProvider.user!.username!, + // contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!, + // ); + // }) + ], ), key: _scaffoldKey, body: FutureBuilder(