import 'dart:developer'; import 'package:flutter_tts/flutter_tts.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/services/logger_service.dart'; import 'package:hmg_qline/utilities/enums.dart'; import 'package:hmg_qline/utilities/extensions.dart'; import 'package:logger/logger.dart'; abstract class TextToSpeechService { Future speechText({ required TicketDetailsModel ticket, required GlobalConfigurationsModel globalConfigurationsModel, bool isMute = false, }); Future speechTextTest(TicketData ticket); void listenToTextToSpeechEvents({required Function() onVoiceCompleted}); } class TextToSpeechServiceImp implements TextToSpeechService { FlutterTts textToSpeechInstance; LoggerService loggerService; TextToSpeechServiceImp({required this.textToSpeechInstance, required this.loggerService}); double volume = 1.0; double pitch = 0.6; double speech = 0.4; @override Future speechTextTest(TicketData ticket) async { const ttsGoogleEngine = 'com.google.android.tts'; LanguageEnum langEnum = ticket.voiceLanguageEnum; List engines = await textToSpeechInstance.getEngines; if (engines.contains(ttsGoogleEngine)) { await textToSpeechInstance.setEngine(ttsGoogleEngine); } textToSpeechInstance.setVolume(1.0); textToSpeechInstance.setSpeechRate(speech); if (langEnum == LanguageEnum.arabic) { try { await textToSpeechInstance.setLanguage(LanguageEnum.arabic.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } } else if (langEnum == LanguageEnum.english) { try { await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } } String preVoice = ticket.ticketNoText; String postVoice = ticket.postVoiceText; if (preVoice.isNotEmpty) { preVoice = '$preVoice..'; } String ticketNo = ticket.queueNo!.trim().toString(); log("areLanguagesInstalled: ${await textToSpeechInstance.areLanguagesInstalled(["en-US", "ar-SA"])}"); log("lang: $langEnum"); log("preVoice: $preVoice"); log("postVoice: $postVoice"); log("ticketNo: $ticketNo"); String patientAlpha = ""; String patientNumeric = ""; String clinicName = ""; bool isClinicNameAdded = (ticket.queueNo != ticket.callNoStr); if (isClinicNameAdded) { var queueNo = ""; var clinic = ticketNo.split(" "); if (clinic.length > 1) { clinicName = clinic[0]; queueNo = clinic[1]; } else { queueNo = ticketNo; } var queueNoArray = queueNo.split("-"); if (queueNoArray.length > 2) { patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}"; patientNumeric = queueNoArray[2]; } else { patientAlpha = queueNoArray[0]; patientNumeric = queueNoArray[1]; } } else { var queueNoArray = ticketNo.split("-"); if (queueNoArray.length > 2) { patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}"; patientNumeric = queueNoArray[2]; } else { patientAlpha = queueNoArray[0]; patientNumeric = queueNoArray[1]; } } patientAlpha = patientAlpha.split('').join(' .. '); String roomNo = ""; log("I will now all this:{ $preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo } "); if (langEnum == LanguageEnum.english) { await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo"); return; } if (isNeedToBreakVoiceForArabic) { await textToSpeechInstance.awaitSpeakCompletion(true); isSpeechCompleted = false; if (preVoice.isNotEmpty) { await textToSpeechInstance.speak("$preVoice "); } try { await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } await textToSpeechInstance.speak("$patientAlpha .. $patientNumeric"); try { await textToSpeechInstance.setLanguage(langEnum.enumToString()); } catch (e) { log("error setting language langEnum: ${e.toString()}"); } await textToSpeechInstance.speak("$postVoice $roomNo").whenComplete(() { isSpeechCompleted = true; }); } else { await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo"); } } @override Future speechText({ required TicketDetailsModel ticket, required GlobalConfigurationsModel globalConfigurationsModel, bool isMute = false, }) async { log("ticketdata i got: ${ticket.ticketModel.toString()}"); const ttsGoogleEngine = 'com.google.android.tts'; LanguageEnum langEnum = ticket.ticketModel!.voiceLanguageEnum; List engines = await textToSpeechInstance.getEngines; if (engines.contains(ttsGoogleEngine)) { await textToSpeechInstance.setEngine(ttsGoogleEngine); } if (isMute) { textToSpeechInstance.setVolume(0.0); } else { textToSpeechInstance.setVolume(1.0); } if (langEnum == LanguageEnum.arabic) { try { await textToSpeechInstance.setLanguage(LanguageEnum.arabic.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } } else if (langEnum == LanguageEnum.english) { try { await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } } String preVoice = ticket.ticketModel!.ticketNoText; String postVoice = ''; if (globalConfigurationsModel.qTypeEnum == QTypeEnum.appointment) { postVoice = ticket.ticketModel!.callTypeEnum.getCallTextFromCallType(ticket.ticketModel!); } else { postVoice = ticket.ticketModel!.postVoiceText; } String roomNo = ''; if (globalConfigurationsModel.qTypeEnum != QTypeEnum.appointment && ticket.ticketModel!.roomNo != null && ticket.ticketModel!.roomNo!.isNotEmpty) { roomNo = ".. ${ticket.ticketModel!.roomNo.toString()}"; } if (preVoice.isNotEmpty) { preVoice = '$preVoice..'; } String ticketNo = ticket.ticketModel!.queueNo!.trim().toString(); log("areLanguagesInstalled: ${await textToSpeechInstance.areLanguagesInstalled(["en-US", "ar-SA"])}"); log("lang: $langEnum"); log("preVoice: $preVoice"); log("postVoice: $postVoice"); log("ticketNo: $ticketNo"); String patientAlpha = ""; String patientNumeric = ""; String clinicName = ""; bool isClinicNameAdded = (ticket.ticketModel?.queueNo != ticket.ticketModel?.callNoStr); if (isClinicNameAdded) { var queueNo = ""; var clinic = ticketNo.split(" "); if (clinic.length > 1) { clinicName = clinic[0]; queueNo = clinic[1]; } else { queueNo = ticketNo; } var queueNoArray = queueNo.split("-"); if (queueNoArray.length > 2) { patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}"; patientNumeric = queueNoArray[2]; } else { patientAlpha = queueNoArray[0]; patientNumeric = queueNoArray[1]; } } else { var queueNoArray = ticketNo.split("-"); if (queueNoArray.length > 2) { patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}"; patientNumeric = queueNoArray[2]; } else { patientAlpha = queueNoArray[0]; patientNumeric = queueNoArray[1]; } } patientAlpha = patientAlpha.split('').join(' .. '); log("I will now all this:{ $preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo } "); if (langEnum == LanguageEnum.english) { await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo"); return; } if (isNeedToBreakVoiceForArabic) { await textToSpeechInstance.awaitSpeakCompletion(true); isSpeechCompleted = false; if (preVoice.isNotEmpty) { await textToSpeechInstance.speak("$preVoice "); } try { await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString()); } catch (e) { log("error setting language english: ${e.toString()}"); } await textToSpeechInstance.speak("$patientAlpha .. $patientNumeric"); try { await textToSpeechInstance.setLanguage(langEnum.enumToString()); } catch (e) { log("error setting language langEnum: ${e.toString()}"); } await textToSpeechInstance.speak("$postVoice $roomNo").whenComplete(() { isSpeechCompleted = true; }); } else { await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo"); } } @override void listenToTextToSpeechEvents({required Function() onVoiceCompleted}) { textToSpeechInstance.setCompletionHandler(onVoiceCompleted); textToSpeechInstance.setErrorHandler((message) { loggerService.logInfo("setErrorHandler: $message\nCompleting the voice for now"); isSpeechCompleted = true; onVoiceCompleted(); }); textToSpeechInstance.setPauseHandler(() { loggerService.logInfo("setPauseHandler"); }); textToSpeechInstance.setCancelHandler(() { loggerService.logInfo("setCancelHandler"); }); } }