import 'dart:async'; import 'dart:developer'; import 'dart:io'; import 'package:connectivity/connectivity.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_tts/flutter_tts.dart'; import 'package:just_audio/just_audio.dart'; import 'package:queuing_system/core/api.dart'; import 'package:queuing_system/core/response_models/call_config_model.dart'; import 'package:queuing_system/core/response_models/patient_ticket_model.dart'; import 'package:queuing_system/utils/call_by_voice.dart'; import 'package:queuing_system/utils/call_type.dart'; import 'package:queuing_system/utils/signalR_utils.dart'; class AppProvider extends ChangeNotifier { AppProvider() { startSignalHubConnection(); listenNetworkConnectivity(); listenAudioPlayerEvents(); } SignalRHelper signalRHelper = SignalRHelper(); final AudioPlayer audioPlayer = AudioPlayer(); FlutterTts flutterTts = FlutterTts(); CallConfig patientCallConfigurations = CallConfig(); List patientTickets = []; List isQueuePatients = []; String currentDeviceIp = ""; bool isCallingInProgress = false; bool isInternetConnectionAvailable = true; bool isApiCallNeeded = false; updateInternetConnection(bool value) { isInternetConnectionAvailable = value; notifyListeners(); } Future getCurrentIP() async { final ips = await NetworkInterface.list(type: InternetAddressType.IPv4); for (var interface in ips) { if (interface.name == "eth0") { for (var address in interface.addresses) { currentDeviceIp = address.address; notifyListeners(); } } if (interface.name == "wlan0") { for (var address in interface.addresses) { currentDeviceIp = address.address; notifyListeners(); } } } } Future startSignalHubConnection() async { if (!signalRHelper.getConnectionState()) { await getCurrentIP().whenComplete(() => signalRHelper.startSignalRConnection( currentDeviceIp, onUpdateAvailable: onPingReceived, onConnect: onConnect, onConnecting: onConnecting, onDisconnect: onDisconnect, )); } } Future callPatientsAPI() async { patientTickets.clear(); API.getCallRequestInfoByClinicInfo(currentDeviceIp, onSuccess: (waitingCalls, isQueuePatientsCalls, callConfigs) async { patientCallConfigurations = callConfigs; if (waitingCalls.length > patientCallConfigurations.screenMaxDisplayPatients) { patientTickets = waitingCalls.sublist(0, patientCallConfigurations.screenMaxDisplayPatients); } else { patientTickets = waitingCalls; } isQueuePatients = isQueuePatientsCalls; notifyListeners(); if (patientTickets.isNotEmpty) { voiceCallPatientTicket(patientTickets.first); updatePatientTicket(patientTickets.first); } }, onFailure: (error) { log("Api call failed with this error: ${error.toString()}"); }); } onPingReceived(data) async { log("isCallingInProgress: $isCallingInProgress"); log("isApiCallNeeded: $isApiCallNeeded"); if (patientTickets.isNotEmpty) { if (isCallingInProgress) { isApiCallNeeded = true; } else { await callPatientsAPI(); } } else { await callPatientsAPI(); } } String getCallTypeText(PatientTicketModel ticket, CallConfig callConfig) { final callType = ticket.getCallType(); switch (callType) { case CallType.vitalSign: return callConfig.vitalSignText; case CallType.doctor: return callConfig.doctorText; case CallType.procedure: return callConfig.procedureText; case CallType.vaccination: return callConfig.vaccinationText; case CallType.nebulization: return callConfig.nebulizationText; default: return callConfig.vitalSignText; } } CallByVoice? voiceCaller; PatientTicketModel currentPatient = PatientTicketModel(); voiceCallPatientTicket(PatientTicketModel patientTicket) async { currentPatient = patientTicket; isCallingInProgress = true; log("Setting isCallingInProgress : $isCallingInProgress"); if (patientTicket.isToneReq && !patientTicket.isQueue) { audioPlayer.setAsset("assets/tones/call_tone.mp3"); await audioPlayer.play(); await Future.delayed(const Duration(seconds: 3)); } if (patientTicket.isVoiceReq && voiceCaller == null && !patientTicket.isQueue) { final postVoice = getCallTypeText(patientTicket, patientCallConfigurations); voiceCaller = CallByVoice(preVoice: "Ticket Number", ticketNo: patientTicket.queueNo.trim().toString(), postVoice: postVoice, lang: 'en', flutterTts: flutterTts); await voiceCaller!.startCalling(patientTicket.queueNo.trim().toString() != patientTicket.callNoStr.trim().toString()); voiceCaller = null; if (isQueuePatients.isNotEmpty) { isQueuePatients.removeAt(0); } } else { isCallingInProgress = false; log("Setting isCallingInProgress : $isCallingInProgress"); if (isApiCallNeeded) { log("I will start waiting!!"); Timer(Duration(seconds: patientCallConfigurations.concurrentCallDelaySec), () async { await callPatientsAPI(); log("Called the API after waiting!"); isApiCallNeeded = false; }); } } } Future listenAudioPlayerEvents() async { audioPlayer.playerStateStream.listen((playerState) async { if (playerState.processingState == ProcessingState.completed) { // isCallingInProgress = false; if (currentPatient.isVoiceReq) return; if (isQueuePatients.isNotEmpty) { log("isQueuePatients length : ${isQueuePatients.length}"); final length = isQueuePatients.length; for (int i = 0; i < length; i++) { await Future.delayed(Duration(seconds: patientCallConfigurations.concurrentCallDelaySec)).whenComplete(() async { PatientTicketModel temp = PatientTicketModel(); if (patientTickets.isNotEmpty) { temp = patientTickets.elementAt(0); patientTickets.removeAt(0); } notifyListeners(); isQueuePatients.removeAt(0); patientTickets.add(temp); notifyListeners(); await voiceCallPatientTicket(patientTickets.first); updatePatientTicket(patientTickets.first); }); } } isCallingInProgress = false; log("Setting isCallingInProgress : $isCallingInProgress"); if (isApiCallNeeded) { log("I will start waiting!!"); Timer(Duration(seconds: patientCallConfigurations.concurrentCallDelaySec), () async { await callPatientsAPI(); log("Called the API after waiting!"); isApiCallNeeded = false; }); } } }); flutterTts.setStartHandler(() { // isCallingInProgress = true; }); flutterTts.setCompletionHandler(() async { if (isQueuePatients.isNotEmpty) { log("isQueuePatients length : ${isQueuePatients.length}"); final length = isQueuePatients.length; for (int i = 0; i < length; i++) { await Future.delayed(Duration(seconds: patientCallConfigurations.concurrentCallDelaySec)).whenComplete(() async { PatientTicketModel temp = PatientTicketModel(); if (patientTickets.isNotEmpty) { temp = patientTickets.elementAt(0); patientTickets.removeAt(0); } notifyListeners(); isQueuePatients.removeAt(0); patientTickets.add(temp); notifyListeners(); await voiceCallPatientTicket(patientTickets.first); updatePatientTicket(patientTickets.first); }); } } isCallingInProgress = false; log("Setting isCallingInProgress : $isCallingInProgress"); if (isApiCallNeeded) { log("I will start waiting!!"); Timer(Duration(seconds: patientCallConfigurations.concurrentCallDelaySec), () async { await callPatientsAPI(); log("Called the API after waiting!"); isApiCallNeeded = false; }); } }); } // updatePatientTickets() { // if (patientTickets.isNotEmpty) { // List _ticketsToUpdate = patientTickets.where((t) => t.callUpdated == false).toList(); // API.callUpdateNotIsQueueRecordByIDAsync(currentDeviceIp, ticket: _ticketsToUpdate.first, onSuccess: (ticketsUpdated) { // log("[${ticketsUpdated.length}] Tickets Updated: $ticketsUpdated"); // }, onFailure: (e) { // log(" Tickets Update Failed with : ${e.toString()}"); // }); // } // } updatePatientTicket(PatientTicketModel patientTicket) { if (!patientTicket.isQueue) { API.callUpdateNotIsQueueRecordByIDAsync(currentDeviceIp, ticket: patientTicket, onSuccess: (ticketsUpdated) { log("[${patientTicket.callNoStr}] Ticket Updated: $ticketsUpdated"); }, onFailure: (e) { log(" Tickets Update ${patientTicket.callNoStr} Failed with Error : ${e.toString()}"); }); } } onConnect() { log("SignalR: onConnect"); } onDisconnect(exception) { log("SignalR: onDisconnect"); signalRHelper.startSignalRConnection(currentDeviceIp, onUpdateAvailable: onPingReceived, onConnect: onConnect, onConnecting: onConnecting, onDisconnect: onDisconnect); } onConnecting() { log("SignalR: onConnecting"); } listenNetworkConnectivity() async { Connectivity().onConnectivityChanged.listen((event) async { switch (event) { case ConnectivityResult.wifi: updateInternetConnection(true); await getCurrentIP(); if (signalRHelper.connection == null || signalRHelper.connection!.state != ConnectionState.active) { signalRHelper.connection!.start(); } break; case ConnectivityResult.none: updateInternetConnection(false); signalRHelper.closeConnection(); break; case ConnectivityResult.mobile: break; } }); } }