From 81fa1ea80d7270d41033364023d2dfa92bdef14b Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Wed, 15 Mar 2023 16:59:42 +0300 Subject: [PATCH] Added trrriiiinngg tone before voice call and few other changes --- assets/tones/call_tone.mp3 | Bin 0 -> 32493 bytes lib/core/api.dart | 10 +- lib/core/response_model/patient_call.dart | 13 +- lib/home/home_screen.dart | 111 +++++++++++------- lib/home/home_screen_components.dart | 4 +- lib/home/priority_calls.dart | 36 ++++-- lib/utils/call_by_voice.dart | 7 +- lib/utils/signalR_utils.dart | 45 +++---- macos/Flutter/GeneratedPluginRegistrant.swift | 2 +- pubspec.lock | 29 ++--- pubspec.yaml | 1 + 11 files changed, 152 insertions(+), 106 deletions(-) create mode 100644 assets/tones/call_tone.mp3 diff --git a/assets/tones/call_tone.mp3 b/assets/tones/call_tone.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d79a0462989a78e7cd0820574fc83ddb2a305bf4 GIT binary patch literal 32493 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 pNB;jnJ^ty?fAr`7uKxVfKj^, List) onSuccess, @required Function(dynamic) onFailure}) async { @@ -14,11 +14,11 @@ class API { body: body, onSuccess: (response, status) { if (status == 200) { - var calledByNurse = (response["CalledByNurse"] as List).map((j) => Tickets.fromJson(j)).toList(); + var calledByNurse = (response["CalledByNurseNew"] as List).map((j) => Tickets.fromJson(j)).toList(); - final patients = (response["ClinicCurrentPatient"] as List).map((j) => Tickets.fromJson(j)).toList(); + final patients = (response["ClinicCurrentPatientNew"] as List).map((j) => Tickets.fromJson(j)).toList(); calledByNurse.addAll(patients); - log("calledByNurse: ${calledByNurse.toString()} "); + log("CalledByNurseNew: ${calledByNurse.toString()} "); log("patients: ${patients.toString()} "); var isQueuePatients = calledByNurse.where((element) => element.isQueue == false).toList(); diff --git a/lib/core/response_model/patient_call.dart b/lib/core/response_model/patient_call.dart index ca93354..c126cbb 100644 --- a/lib/core/response_model/patient_call.dart +++ b/lib/core/response_model/patient_call.dart @@ -17,10 +17,13 @@ class Tickets { this.callNoStr, this.queueNo, this.queueDuration, + this.isQueue, + this.isVoiceReq, + this.isToneReq, }); int getRandomNum() { - return Random().nextInt(2); + return Random().nextInt(1); } Tickets.fromJson(dynamic json) { @@ -39,6 +42,8 @@ class Tickets { queueDuration = json['QueueDuration']; callNoStr = json['CallNoStr'] ?? json['CallNo'].toString(); isQueue = json["ISQueue"] ?? false; + isToneReq = json["IsToneReq"] ?? true; + isVoiceReq = json["IsVoiceReq"] ?? true; // isQueue = getRandomNum(); } @@ -58,6 +63,8 @@ class Tickets { String callNoStr; bool callUpdated = false; bool isQueue; + bool isToneReq; + bool isVoiceReq; Map toJson() { final map = {}; @@ -76,12 +83,14 @@ class Tickets { map['QueueNo'] = queueNo; map['QueueDuration'] = queueDuration; map['ISQueue'] = isQueue; + map['IsToneReq'] = isToneReq; + map['IsVoiceReq'] = isVoiceReq; return map; } @override String toString() { - return (callNoStr).toString(); + return (queueNo).toString(); } CallType getCallType() { diff --git a/lib/home/home_screen.dart b/lib/home/home_screen.dart index 5f263ad..9b74296 100644 --- a/lib/home/home_screen.dart +++ b/lib/home/home_screen.dart @@ -2,9 +2,9 @@ import 'dart:developer'; import 'package:connectivity/connectivity.dart'; import 'package:flutter/material.dart'; +import 'package:just_audio/just_audio.dart'; import 'package:queuing_system/core/api.dart'; import 'package:queuing_system/core/base/app_scaffold_widget.dart'; -import 'package:queuing_system/core/config/config.dart'; import 'package:queuing_system/core/config/size_config.dart'; import 'package:queuing_system/core/response_model/patient_call.dart'; import 'package:queuing_system/header/app_header.dart'; @@ -22,7 +22,9 @@ var DEVICE_IP = "10.10.15.11"; // Testing IP // var DEVICE_IP = "10.70.249.21"; // (Make sure by Haroon before use it) Production IP class MyHomePage extends StatefulWidget { - String title = "MyHomePage"; + final String title = "MyHomePage"; + + const MyHomePage({Key key}) : super(key: key); @override State createState() => _MyHomePageState(); @@ -82,30 +84,30 @@ class _MyHomePageState extends State { ), ], ), - Row( - children: [ - const SizedBox(width: 60), - SizedBox( - width: 200, - child: TextField( - controller: controller, - )), - const SizedBox(width: 30), - isLoading - ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: onUpdateIPPressed, - child: const Text( - "Update IP", - style: TextStyle(color: Colors.white), - ), - style: ElevatedButton.styleFrom(backgroundColor: AppGlobal.appRedColor), - ), - const SizedBox(width: 30), - Text("IP: $DEVICE_IP", style: const TextStyle(fontWeight: FontWeight.w600)), - const SizedBox(width: 20), - ], - ), + // Row( + // children: [ + // const SizedBox(width: 60), + // SizedBox( + // width: 200, + // child: TextField( + // controller: controller, + // )), + // const SizedBox(width: 30), + // isLoading + // ? const CircularProgressIndicator() + // : ElevatedButton( + // onPressed: onUpdateIPPressed, + // child: const Text( + // "Update IP", + // style: TextStyle(color: Colors.white), + // ), + // style: ElevatedButton.styleFrom(backgroundColor: AppGlobal.appRedColor), + // ), + // const SizedBox(width: 30), + // Text("IP: $DEVICE_IP", style: const TextStyle(fontWeight: FontWeight.w600)), + // const SizedBox(width: 20), + // ], + // ), ], ), ), @@ -168,35 +170,64 @@ class _MyHomePageState extends State { } CallByVoice voiceCaller; + final AudioPlayer audioPlayer = AudioPlayer(); int callFlag = 0; voiceCall() async { - //TODO: After calling this voice call, we should delay for milliseconds that is given by API. After that we will check if there are more patients in isQueuePatients we will remove the patient from waiting list and then update the state + //DONE: After calling this voice call, we should delay for milliseconds that is given by API. After that we will check if there are more patients in isQueuePatients we will remove the patient from waiting list and then update the state - if (waitings.isNotEmpty && voiceCaller == null) { - final postVoice = getCallTypeText(waitings.first); - voiceCaller = CallByVoice(waitings.first.callNoStr.toString(), preVoice: "Ticket Number", postVoice: postVoice, lang: 'en'); - await voiceCaller.startCalling(); - voiceCaller = null; + if (waitings.isNotEmpty) { + if (waitings.first.isToneReq) { + audioPlayer.setAsset("assets/tones/call_tone.mp3"); + await audioPlayer.play(); + await Future.delayed(const Duration(seconds: 2)); + } + if (waitings.first.isVoiceReq && voiceCaller == null) { + final postVoice = getCallTypeText(waitings.first); + voiceCaller = CallByVoice(waitings.first.queueNo.toString(), preVoice: "Ticket Number", postVoice: postVoice, lang: 'en'); + await voiceCaller.startCalling(); + voiceCaller = null; + } } if (isQueuePatients.isNotEmpty) { await Future.delayed(Duration(milliseconds: int.parse(isQueuePatients.first.queueDuration) * 10)).whenComplete(() async { - isQueuePatients.removeAt(0); - Tickets ticket = waitings.elementAt(0); - waitings.removeAt(0); - waitings.add(ticket); if (isQueuePatients.isNotEmpty) { - setState(() {}); + isQueuePatients.removeAt(0); + } + if (waitings.isNotEmpty) { + Tickets ticket = waitings.elementAt(0); + waitings.removeAt(0); + waitings.add(ticket); } - if (isQueuePatients.isEmpty && callFlag == 1) { - callFlag == 0; - await Future.delayed(const Duration(seconds: 3)); + if (isQueuePatients.isNotEmpty) { + setState(() {}); } }); + } else { + // if (isQueuePatients.isEmpty && callFlag == 1) { + // callFlag == 0; + // await Future.delayed(const Duration(seconds: 3)); + // waitings.clear(); + // API.getCallRequestInfoByClinicInfo(DEVICE_IP, onSuccess: (waitingCalls, isQueuePatientsCalls) { + // setState(() { + // waitings = waitingCalls; + // isQueuePatients = isQueuePatientsCalls; + // // currents = currentInClinic; + // }); + // + // log("--------------------"); + // log("waiting: $waitings"); + // log("isQueuePatients: $isQueuePatients"); + // log("--------------------"); + // + // updateTickets(); + // }, onFailure: (error) {}); + // } } } onUpdateAvailable(data) async { + print("here is the data: $data"); if (isQueuePatients.isNotEmpty && callFlag == 0) { callFlag = 1; return; diff --git a/lib/home/home_screen_components.dart b/lib/home/home_screen_components.dart index 3f3408f..4eb11c0 100644 --- a/lib/home/home_screen_components.dart +++ b/lib/home/home_screen_components.dart @@ -44,8 +44,8 @@ Widget priorityTicketsWithSideList(List tickets) { SizedBox( width: SizeConfig.getWidthMultiplier() * 13, child: AppText( - itm.callNoStr.toString(), - letterSpacing: -2.32, + itm.queueNo.toString(), + letterSpacing: -2, fontWeight: FontWeight.bold, fontSize: SizeConfig.getWidthMultiplier() * 4.5, textAlign: TextAlign.end, diff --git a/lib/home/priority_calls.dart b/lib/home/priority_calls.dart index 35ae16b..8bbb4e4 100644 --- a/lib/home/priority_calls.dart +++ b/lib/home/priority_calls.dart @@ -21,7 +21,7 @@ class PriorityTickets extends StatelessWidget { children: [ const SizedBox(height: 20), vTicketItem( - ticketNo: firstTicket.callNoStr ?? '', + ticketNo: firstTicket.queueNo ?? '', callType: firstTicket.getCallType(), scale: 1, blink: true, @@ -34,14 +34,14 @@ class PriorityTickets extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceAround, children: otherTickets .map((ticket) => Padding( - padding: EdgeInsets.only(top: SizeConfig.getHeightMultiplier() * 2), - child: vTicketItem( - ticketNo: ticket.callNoStr ?? '', + padding: EdgeInsets.only(top: SizeConfig.getHeightMultiplier() * 2), + child: vTicketItem( + ticketNo: ticket.queueNo ?? '', callType: ticket.getCallType(), scale: 0.7, roomNo: ticket.roomNo, ), - )) + )) .toList(), ) ] @@ -59,6 +59,11 @@ class vTicketItem extends StatelessWidget { const vTicketItem({@required this.ticketNo, @required this.roomNo, @required this.callType, this.scale, this.blink = false}); + String getFormattedTicket(String ticketNo) { + var formattedString = ticketNo.split(" "); + return formattedString[0] + " " + formattedString[1]; + } + @override Widget build(BuildContext context) { return Transform.scale( @@ -66,8 +71,13 @@ class vTicketItem extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - BlinkText(ticketNo, - style: TextStyle(fontSize: SizeConfig.getWidthMultiplier() * 10, letterSpacing: -9.32, height: 0.5, fontWeight: FontWeight.bold), + BlinkText(getFormattedTicket(ticketNo), + style: TextStyle( + fontSize: SizeConfig.getWidthMultiplier() * 10, + letterSpacing: -9.32, + height: 0.5, + fontWeight: FontWeight.bold, + ), beginColor: Colors.black, endColor: blink ? Colors.black.withOpacity(0.1) : Colors.black, // endColor: blink ? AppGlobal.appRedColor : Colors.black, @@ -95,12 +105,12 @@ class vTicketItem extends StatelessWidget { fontWeight: FontWeight.w600, fontHeight: 0.5, ), - Container( - color: Colors.grey.withOpacity(0.3), - width: 6, - height: SizeConfig.getHeightMultiplier() * 3, - margin: const EdgeInsets.symmetric(horizontal: 10), - ), + Container( + color: Colors.grey.withOpacity(0.3), + width: 6, + height: SizeConfig.getHeightMultiplier() * 3, + margin: const EdgeInsets.symmetric(horizontal: 10), + ), AppText( "Room: $roomNo", color: callType.color(), diff --git a/lib/utils/call_by_voice.dart b/lib/utils/call_by_voice.dart index a23887c..e537020 100644 --- a/lib/utils/call_by_voice.dart +++ b/lib/utils/call_by_voice.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/cupertino.dart'; import 'package:flutter_tts/flutter_tts.dart'; @@ -21,13 +19,14 @@ class CallByVoice { startCalling() async { textToSpeech.setLanguage("en-US"); - var splitText = ticketNo.split("-"); + var clinic = ticketNo.split(" "); + var splitText = clinic[1].split("-"); // Create Pre Voice Players if (preVoice != null && preVoice.isNotEmpty) { textToSpeech.setSpeechRate(rate); textToSpeech.setPitch(pitch); textToSpeech.setVolume(volume); - await textToSpeech.speak(preVoice + " .. " + splitText[0] + " .. " + splitText[1] + " .. " + postVoice); + await textToSpeech.speak(preVoice + " .. " + clinic[0] + " .. " + splitText[0] + " .. " + splitText[1] + " .. " + postVoice); } // // Create Ticket Number Voice Players diff --git a/lib/utils/signalR_utils.dart b/lib/utils/signalR_utils.dart index 505feb1..fe08ad1 100644 --- a/lib/utils/signalR_utils.dart +++ b/lib/utils/signalR_utils.dart @@ -15,30 +15,33 @@ https://vcallapi.hmg.com/patientcalling.html?IPAddress=10.10.14.20&Clinic=4&Proj --------------------------------------- */ -class SignalRHelper{ +class SignalRHelper { + // String hubBaseURL = "https://vcallapi.hmg.com/PatientCallingHub"; String hubBaseURL = "https://vcallapi.hmg.com/PatientCallingHub"; + // String hubBaseURL = "https://vcallapi.hmg.com/PatientCallingHub?IPAddress=10.10.14.20"; // "https://VCallApi.hmg.com/WebRTCHub?source=mobile&username=2001273"; - String msg ="Awaiting Patients Arrival"; + String msg = "Awaiting Patients Arrival"; HubConnection connection; - startSignalRConnection(String deviceIp, {@required Function(dynamic) onUpdateAvailable, @required VoidCallback onConnect, @required Function(dynamic) onDisconnect, @required VoidCallback onConnecting}) async { - + startSignalRConnection(String deviceIp, + {@required Function(dynamic) onUpdateAvailable, @required VoidCallback onConnect, @required Function(dynamic) onDisconnect, @required VoidCallback onConnecting}) async { // Hardcoded IP For Testing // deviceIp = "10.10.14.11"; print("Connecting Signal R with: $deviceIp"); final url = hubBaseURL+"?IPAddress=$deviceIp"; + // final url = hubBaseURL; connection = HubConnectionBuilder() .withUrl( - url, - HttpConnectionOptions( - client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), - transport: HttpTransportType.webSockets, - logging: (level, message) => { - print(message) - }, - )) + url, + HttpConnectionOptions( + client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), + transport: HttpTransportType.webSockets, + logging: (level, message) => { + print(message), + }, + )) .build(); connection.onclose(onDisconnect); @@ -49,33 +52,33 @@ class SignalRHelper{ onUpdateAvailable(message); }); + // try { await connection.start(); - - } + // } catch (e, s) { + // print("Here the error: ${e.toString()}"); + // } + } void sendMessage(List args) async { await connection.invoke('SendMessage', args: args); //['Bob', 'Says hi!'] } bool getConnectionState() { - if(connection == null ) return false; + if (connection == null) return false; if (connection.state == HubConnectionState.connected || connection.state == HubConnectionState.connecting) return true; if (connection.state == HubConnectionState.disconnected || connection.state == HubConnectionState.disconnecting) return false; } - closeConnection(BuildContext context) async { - if(connection.state == HubConnectionState.connected || connection.state == HubConnectionState.connecting) - { + if (connection.state == HubConnectionState.connected || connection.state == HubConnectionState.connecting) { await connection.stop(); } } startConnection(BuildContext context) async { - if(connection.state == HubConnectionState.connected || connection.state == HubConnectionState.connecting) - { + if (connection.state == HubConnectionState.connected || connection.state == HubConnectionState.connecting) { connection.off('addChatMessage'); await connection.start(); } } -} \ No newline at end of file +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index addc988..950f73d 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,7 @@ import audio_session import connectivity_macos import flutter_tts import just_audio -import path_provider_macos +import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 35bf3c8..4b25199 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -281,49 +281,42 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.13" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.20" - path_provider_ios: + version: "2.0.24" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios + name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.1.3" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" + version: "2.1.10" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.5" petitparser: dependency: transitive description: @@ -454,7 +447,7 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.6" + version: "3.0.7" vector_math: dependency: transitive description: @@ -475,14 +468,14 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.3" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0+2" + version: "1.0.0" xml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c1f5263..c79fd06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/tones/ fonts: