import 'dart:async'; import 'dart:developer'; import 'package:flutter/cupertino.dart'; import 'package:hmg_qline/config/dependency_injection.dart'; import 'package:hmg_qline/constants/app_constants.dart'; import 'package:hmg_qline/models/global_config_model.dart'; import 'package:hmg_qline/models/ticket_model.dart'; import 'package:hmg_qline/repositories/screen_details_repo.dart'; import 'package:hmg_qline/repositories/signalR_repo.dart'; import 'package:hmg_qline/services/audio_service.dart'; import 'package:hmg_qline/services/cache_service.dart'; import 'package:hmg_qline/services/logger_service.dart'; import 'package:hmg_qline/services/text_to_speech_service.dart'; import 'package:hmg_qline/utilities/enums.dart'; import 'package:hmg_qline/view_models/screen_config_view_model.dart'; class QueuingViewModel extends ChangeNotifier { final ScreenDetailsRepo screenDetailsRepo; final SignalrRepo signalrRepo; final CacheService cacheService; final AudioService audioService; final TextToSpeechService textToSpeechService; final LoggerService loggerService; QueuingViewModel({ required this.screenDetailsRepo, required this.signalrRepo, required this.cacheService, required this.audioService, required this.textToSpeechService, required this.loggerService, }); Future initializeQueueingVM() async { await startHubConnection(); initializeAudioPlayer(); initializeTextToSpeech(); } Future startHubConnection() async { ScreenConfigViewModel screenConfigViewModel = getIt.get(); return await signalrRepo.startHubConnection( deviceIp: screenConfigViewModel.currentScreenIP, onHubTicketCall: onHubTicketCall, onHubConfigCall: onHubConfigCall, onHubReconnected: onHubReconnected, onHubDisconnected: onHubDisconnected, onHubConnecting: onHubConnecting, ); } Future stopHubConnection() async { return await signalrRepo.closeConnection(); } initializeAudioPlayer() { audioService.listenAudioPlayerEvents(onToneCompleted: onToneCompleted); } initializeTextToSpeech() { textToSpeechService.listenToTextToSpeechEvents(onVoiceCompleted: onVoiceCompleted); } Future onHubConfigCall(var response) async { loggerService.logToFile(message: response.toString(), source: "onHubConfigCall -> queueing_view_model.dart ", type: LogTypeEnum.data); if (response != null && response.isNotEmpty) { var data = response.first['data']; GlobalConfigurationsModel globalConfigurationsModel = GlobalConfigurationsModel.fromJson( json: data, qType: response.first['qType'] ?? 1, screenType: response.first['screenType'] ?? 1, ); log("onHubConfigCall: ${globalConfigurationsModel.toString()}"); ScreenConfigViewModel screenConfigViewModel = getIt.get(); screenConfigViewModel.updateGlobalConfigurationsModel(value: globalConfigurationsModel, needNotify: true, shouldUpdateNextPrayer: true); } } Future onHubTicketCall(List? response) async { loggerService.logToFile(message: response.toString(), source: "onHubTicketCall -> queueing_view_model.dart ", type: LogTypeEnum.data); log("onHubTicketCall: $response"); log("isCallingInProgress: $isCallingInProgress"); if (response != null && response.isNotEmpty) { TicketDetailsModel ticketDetailsModel = TicketDetailsModel.fromJson(response.first as Map); addNewTicket(ticketDetailsModel); } } Future onHubReconnected(var response) async { log("onHubConnected: $response"); loggerService.logToFile(message: response.toString(), source: "onHubReconnected -> queueing_view_model.dart ", type: LogTypeEnum.connectivity); ScreenConfigViewModel screenConfigViewModel = getIt.get(); screenConfigViewModel.updateIsHubConnected(true); screenConfigViewModel.notifyListeners(); } Future onHubDisconnected(var response) async { log("onHubDisconnected: $response"); loggerService.logToFile(message: response.toString(), source: "onHubDisconnected -> queueing_view_model.dart ", type: LogTypeEnum.connectivity); ScreenConfigViewModel screenConfigViewModel = getIt.get(); screenConfigViewModel.updateIsHubConnected(false); screenConfigViewModel.notifyListeners(); } Future onHubConnecting(var response) async => log("onHubConnecting: $response"); Future onToneCompleted() async { GlobalConfigurationsModel globalConfigurationsModel = getIt.get().globalConfigurationsModel; if (true) { await textToSpeechService.speechText(globalConfigurationsModel: globalConfigurationsModel, ticket: currentTickets.first, isMute: !(globalConfigurationsModel.isVoiceReq)); } else { waitAndCallNextTicketIfAvailable(); } } Future onVoiceCompleted() async { log("isSpeechCompleted::: $isSpeechCompleted"); if (isSpeechCompleted) { waitAndCallNextTicketIfAvailable(); } } waitAndCallNextTicketIfAvailable() { GlobalConfigurationsModel globalConfigurationsModel = getIt.get().globalConfigurationsModel; Timer(Duration(seconds: globalConfigurationsModel.concurrentCallDelaySec), () async { if (queueTickets.isNotEmpty) { int index = itemAlreadyAvailableAtIndex(ticketToSearch: queueTickets.first, listToSearchIn: currentTickets); if (index != -1) { currentTickets.removeAt(index); } currentTickets.insert(0, queueTickets.first); if (currentTickets.length > globalConfigurationsModel.screenMaxDisplayPatients) { currentTickets.removeLast(); } notifyListeners(); queueTickets.removeAt(0); callTicketOnScreen(ticketData: currentTickets.first.ticketModel); } else { isCallingInProgress = false; } }); } int itemAlreadyAvailableAtIndex({required TicketDetailsModel ticketToSearch, required List listToSearchIn}) { int isFoundAt = -1; try { isFoundAt = listToSearchIn.indexWhere((ticket) { log("ticket.ticketModel!.queueNo: ${ticket.ticketModel!.queueNo}"); log("ticketToSearch.ticketModel!.queueNo: ${ticketToSearch.ticketModel!.queueNo}"); return ticket.ticketModel!.queueNo == ticketToSearch.ticketModel!.queueNo; }); log("itemAlreadyAvailableAtIndex: $isFoundAt"); return isFoundAt; } catch (e) { log("Error isItemAlreadyAvailableInList: ${e.toString()}"); return isFoundAt; } } bool isCallingInProgress = false; // Tickets Management List currentTickets = []; List queueTickets = []; void addNewTicket(TicketDetailsModel ticket) { if (!isCallingInProgress) { int index = itemAlreadyAvailableAtIndex(ticketToSearch: ticket, listToSearchIn: currentTickets); if (index != -1) { currentTickets.removeAt(index); } currentTickets.insert(0, ticket); GlobalConfigurationsModel globalConfigurationsModel = getIt.get().globalConfigurationsModel; if (currentTickets.length > globalConfigurationsModel.screenMaxDisplayPatients) { currentTickets.removeLast(); } callTicketOnScreen(ticketData: currentTickets.first.ticketModel); } else { int index = itemAlreadyAvailableAtIndex(ticketToSearch: ticket, listToSearchIn: queueTickets); if (index != -1) { queueTickets.removeAt(index); } queueTickets.add(ticket); log("inQueue Length: ${queueTickets.length}"); } notifyListeners(); } Future testSpeech() async { textToSpeechService.speechTextTest(MockJsonRepo.ticket); } Future callTicketOnScreen({required TicketData? ticketData}) async { if (ticketData == null) return; ScreenConfigViewModel screenConfigViewModel = getIt.get(); GlobalConfigurationsModel globalConfigurationsModel = screenConfigViewModel.globalConfigurationsModel; if (globalConfigurationsModel.qTypeEnum == QTypeEnum.appointment) { screenConfigViewModel.acknowledgeTicketForAppointmentOnly( ticketQueueID: ticketData.id ?? 0, ipAddress: screenConfigViewModel.currentScreenIP, callTypeEnum: ticketData.callTypeEnum, ); } else { screenConfigViewModel.acknowledgeTicket(ticketQueueID: ticketData.id ?? 0); } log("globalConfigurationsModel: ${globalConfigurationsModel.toString()}"); if (true) { isCallingInProgress = true; await audioService.playTone(path: AppAssets.callTone, isMute: !(globalConfigurationsModel.isToneReq)); } else if (globalConfigurationsModel.isVoiceReq) { isCallingInProgress = true; await textToSpeechService.speechText(globalConfigurationsModel: globalConfigurationsModel, ticket: currentTickets.first, isMute: !(globalConfigurationsModel.isVoiceReq)); } else { waitAndCallNextTicketIfAvailable(); } } } // Future callTicketOnScreen({required TicketData? ticketData}) async { // if (ticketData == null) return; // ScreenConfigViewModel screenConfigViewModel = getIt.get(); // GlobalConfigurationsModel globalConfigurationsModel = screenConfigViewModel.globalConfigurationsModel; // if (globalConfigurationsModel.qTypeEnum == QTypeEnum.appointment) { // screenConfigViewModel.acknowledgeTicketForAppointmentOnly( // ticketQueueID: ticketData.id ?? 0, // ipAddress: screenConfigViewModel.currentScreenIP, // callTypeEnum: ticketData.callTypeEnum, // ); // } else { // screenConfigViewModel.acknowledgeTicket(ticketQueueID: ticketData.id ?? 0); // } // if (globalConfigurationsModel.isToneReq) { // isCallingInProgress = true; // await audioService.playTone(path: AppAssets.callTone, isMute: !(globalConfigurationsModel.isToneReq)); // } else if (globalConfigurationsModel.isVoiceReq) { // isCallingInProgress = true; // await textToSpeechService.speechText(globalConfigurationsModel: globalConfigurationsModel, ticket: currentTickets.first, isMute: !(globalConfigurationsModel.isVoiceReq)); // } else { // waitAndCallNextTicketIfAvailable(); // } // }