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/core/response_models/prayers_widget_model.dart'; import 'package:queuing_system/core/response_models/weathers_widget_model.dart'; import 'package:queuing_system/core/response_models/widgets_config_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'; import 'package:shared_preferences/shared_preferences.dart'; class AppProvider extends ChangeNotifier { AppProvider() { callInitializations(); } Future callInitializations() async { await startSignalHubConnection(); await getInfoWidgetsDetailsFromServer(); await getLastTimeUpdatedFromCache(); listenNetworkConnectivity(); listenAudioPlayerEvents(); getTheWidgetsConfigurationsEveryMidnight(); } 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(); } } } } WidgetsConfigModel? currentWidgetsConfigModel = WidgetsConfigModel(); Future getInfoWidgetsConfigurationsFromServer() async { WidgetsConfigModel? widgetsConfigModel = await API.getWidgetConfigsFromServer(currentDeviceIp, onFailure: (error) { log("Api call failed with this error: ${error.toString()}"); }); if (widgetsConfigModel != null) { currentWidgetsConfigModel = widgetsConfigModel; log("I got this data: ${widgetsConfigModel.toString()}"); notifyListeners(); } } WeathersWidgetModel currentWeathersWidgetModel = WeathersWidgetModel(); Future getWeatherDetailsFromServer() async { log("I got this data from Weather: "); WeathersWidgetModel? weathersWidgetModel = await API.getWeatherDetailsFromServer( (currentWidgetsConfigModel!.cityKey ?? "").toString(), onFailure: (error) => log("Api call failed with this error: ${error.toString()}"), ); if (weathersWidgetModel != null) { currentWeathersWidgetModel = weathersWidgetModel; log("I got this data from Weather: ${weathersWidgetModel.toString()}"); notifyListeners(); } } PrayersWidgetModel nextPrayerToShow = PrayersWidgetModel(); Future getTheNextPrayerToShow() async { } List currentPrayersWidgetModel = []; Future getPrayerDetailsFromServer() async { List prayersWidgetModel = await API.getPrayerDetailsFromServer( latitude: currentWidgetsConfigModel!.projectLatitude ?? 0, longitude: currentWidgetsConfigModel!.projectLongitude ?? 0, onFailure: (error) => log("Api call failed with this error: ${error.toString()}")); if (prayersWidgetModel.isNotEmpty) { currentPrayersWidgetModel = prayersWidgetModel; log("I got this data: ${prayersWidgetModel.toString()}"); notifyListeners(); } } Future getInfoWidgetsDetailsFromServer() async { if (currentWidgetsConfigModel == null) return; await getInfoWidgetsConfigurationsFromServer().whenComplete(() async { if (currentWidgetsConfigModel!.isWeatherReq!) { await getWeatherDetailsFromServer(); } if (currentWidgetsConfigModel!.isPrayerTimeReq!) { await getPrayerDetailsFromServer(); } }); int currentDate = DateTime.now().millisecondsSinceEpoch; await setLastTimeUpdatedInCache(lasTimeUpdated: currentDate.toString()); } Future getTheWidgetsConfigurationsEveryMidnight() async { if (currentWidgetsConfigModel == null) return; if (!currentWidgetsConfigModel!.isWeatherReq! && !currentWidgetsConfigModel!.isPrayerTimeReq!) { return; } DateTime current = DateTime.now(); Stream timer = Stream.periodic(const Duration(hours: 1), (i) { current = current.add(const Duration(hours: 1)); return current; }); timer.listen((data) async { DateTime dateTime = DateTime.parse(data.toString()); if (currentWidgetsConfigModel!.isWeatherReq!) { if (dateTime.day > currentLastTimeUpdated.day) { await getWeatherDetailsFromServer(); } } if (currentWidgetsConfigModel!.isPrayerTimeReq!) { if (dateTime.day > currentLastTimeUpdated.day) { await getPrayerDetailsFromServer(); } } }); } 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; } }); } //SHARED PREFERENCE HANDLING DateTime currentLastTimeUpdated = DateTime.now(); Future getLastTimeUpdatedFromCache() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); if (prefs.containsKey("lastTimeUpdated")) { String? lastTimeUpdated = prefs.getString("lastTimeUpdated"); currentLastTimeUpdated = DateTime.fromMillisecondsSinceEpoch(int.parse(lastTimeUpdated!)); return lastTimeUpdated; } else { return null; } } Future setLastTimeUpdatedInCache({required String lasTimeUpdated}) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString("lastTimeUpdated", lasTimeUpdated); } }