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:intl/intl.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/rss_feed_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 < void > 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 < PatientTicketModel > patientTickets = [ ] ;
List < PatientTicketModel > isQueuePatients = [ ] ;
String currentDeviceIp = " " ;
bool isCallingInProgress = false ;
bool isInternetConnectionAvailable = true ;
bool isApiCallNeeded = false ;
updateInternetConnection ( bool value ) {
isInternetConnectionAvailable = value ;
notifyListeners ( ) ;
}
Future < void > 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 < void > getInfoWidgetsConfigurationsFromServer ( ) async {
WidgetsConfigModel ? widgetsConfigModel = await API . getWidgetConfigsFromServer ( currentDeviceIp , onFailure: ( error ) {
log ( " Api call failed with this error: ${ error . toString ( ) } " ) ;
} ) ;
if ( widgetsConfigModel ! = null ) {
currentWidgetsConfigModel = widgetsConfigModel ;
notifyListeners ( ) ;
}
}
WeathersWidgetModel currentWeathersWidgetModel = WeathersWidgetModel ( ) ;
Future < void > getWeatherDetailsFromServer ( ) async {
WeathersWidgetModel ? weathersWidgetModel = await API . getWeatherDetailsFromServer (
( currentWidgetsConfigModel ! . cityKey ? ? " " ) . toString ( ) ,
onFailure: ( error ) = > log ( " Api call failed with this error: ${ error . toString ( ) } " ) ,
) ;
if ( weathersWidgetModel ! = null ) {
currentWeathersWidgetModel = weathersWidgetModel ;
notifyListeners ( ) ;
}
}
String nextPrayerToShowWithTime = ' ' ;
void getNextPrayerToShow ( ) {
log ( " Checking Namaz time Locally! " ) ;
final current = DateTime . now ( ) ;
if ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . fajr ! ) . isAfter ( current ) ) {
final namazTime = DateFormat ( ' hh:mm a ' ) . format ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . fajr ! ) ) ;
nextPrayerToShowWithTime = " ${ patientCallConfigurations . fajrText } at $ namazTime " ;
notifyListeners ( ) ;
return ;
}
if ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . dhuhr ! ) . isAfter ( current ) ) {
final namazTime = DateFormat ( ' hh:mm a ' ) . format ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . dhuhr ! ) ) ;
nextPrayerToShowWithTime = " ${ patientCallConfigurations . dhuhrText } at $ namazTime " ;
notifyListeners ( ) ;
return ;
}
if ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . asr ! ) . isAfter ( current ) ) {
final namazTime = DateFormat ( ' hh:mm a ' ) . format ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . asr ! ) ) ;
nextPrayerToShowWithTime = " ${ patientCallConfigurations . asrText } at $ namazTime " ;
notifyListeners ( ) ;
return ;
}
if ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . maghrib ! ) . isAfter ( current ) ) {
final namazTime = DateFormat ( ' hh:mm a ' ) . format ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . maghrib ! ) ) ;
nextPrayerToShowWithTime = " ${ patientCallConfigurations . maghribText } at $ namazTime " ;
notifyListeners ( ) ;
return ;
}
if ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . isha ! ) . isAfter ( current ) ) {
final namazTime = DateFormat ( ' hh:mm a ' ) . format ( DateTime . fromMillisecondsSinceEpoch ( currentPrayersWidgetModel . isha ! ) ) ;
nextPrayerToShowWithTime = " ${ patientCallConfigurations . ishaText } at $ namazTime " ;
notifyListeners ( ) ;
return ;
}
}
PrayersWidgetModel currentPrayersWidgetModel = PrayersWidgetModel ( ) ;
Future < void > getPrayerDetailsFromServer ( ) async {
PrayersWidgetModel ? 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 ! = null ) {
currentPrayersWidgetModel = prayersWidgetModel ;
log ( " I got this data from Prayers: ${ prayersWidgetModel . toString ( ) } " ) ;
getNextPrayerToShow ( ) ;
notifyListeners ( ) ;
}
}
RssFeedModel currentRssFeedModel = RssFeedModel ( ) ;
Future < void > getRssFeedDetailsFromServer ( ) async {
RssFeedModel ? rssFeedModel = await API . getRssFeedDetailsFromServer ( languageId: 0 , onFailure: ( error ) = > log ( " Api call failed with this error: ${ error . toString ( ) } " ) ) ;
if ( rssFeedModel ! = null ) {
currentRssFeedModel = rssFeedModel ;
log ( " I got this data from RssFeed: ${ currentRssFeedModel . rssFeed } " ) ;
notifyListeners ( ) ;
}
}
Future < void > getInfoWidgetsDetailsFromServer ( ) async {
if ( currentWidgetsConfigModel = = null ) return ;
await getInfoWidgetsConfigurationsFromServer ( ) . whenComplete ( ( ) async {
if ( currentWidgetsConfigModel ! . isWeatherReq ! ) {
await getWeatherDetailsFromServer ( ) ;
}
if ( currentWidgetsConfigModel ! . isPrayerTimeReq ! ) {
await getPrayerDetailsFromServer ( ) ;
}
if ( currentWidgetsConfigModel ! . isRssFeedReq ! ) {
await getRssFeedDetailsFromServer ( ) ;
}
} ) ;
int currentDate = DateTime . now ( ) . millisecondsSinceEpoch ;
await setLastTimeUpdatedInCache ( lasTimeUpdated: currentDate . toString ( ) ) ;
}
int counter = 0 ;
Future < void > getTheWidgetsConfigurationsEveryMidnight ( ) async {
if ( currentWidgetsConfigModel = = null ) return ;
if ( ! currentWidgetsConfigModel ! . isWeatherReq ! & & ! currentWidgetsConfigModel ! . isPrayerTimeReq ! & & ! currentWidgetsConfigModel ! . isRssFeedReq ! ) {
return ;
}
DateTime current = DateTime . now ( ) ;
Stream timer = Stream . periodic ( const Duration ( minutes: 1 ) , ( i ) {
current = current . add ( const Duration ( minutes: 1 ) ) ;
return current ;
} ) ;
timer . listen ( ( data ) async {
DateTime dateTime = DateTime . parse ( data . toString ( ) ) ;
counter + + ;
log ( " counterValue: $ counter " ) ;
if ( counter = = 60 & & currentWidgetsConfigModel ! . isRssFeedReq ! ) {
await getRssFeedDetailsFromServer ( ) ;
}
if ( currentWidgetsConfigModel ! . isWeatherReq ! ) {
if ( dateTime . day > currentLastTimeUpdated . day ) {
await getWeatherDetailsFromServer ( ) ;
}
}
if ( currentWidgetsConfigModel ! . isPrayerTimeReq ! ) {
if ( dateTime . day > currentLastTimeUpdated . day ) {
await getPrayerDetailsFromServer ( ) ;
}
}
if ( currentWidgetsConfigModel ! . isRssFeedReq ! ) {
if ( dateTime . day > currentLastTimeUpdated . day ) {
await getRssFeedDetailsFromServer ( ) ;
}
}
getNextPrayerToShow ( ) ;
} ) ;
}
Future < void > startSignalHubConnection ( ) async {
if ( ! signalRHelper . getConnectionState ( ) ) {
await getCurrentIP ( ) . whenComplete ( ( ) = > signalRHelper . startSignalRConnection (
currentDeviceIp ,
onUpdateAvailable: onPingReceived ,
onConnect: onConnect ,
onConnecting: onConnecting ,
onDisconnect: onDisconnect ,
) ) ;
}
}
Future < void > 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: patientCallConfigurations . preVoiceText ,
ticketNo: patientTicket . queueNo . trim ( ) . toString ( ) ,
postVoice: postVoice ,
lang: patientCallConfigurations . voiceLanguage = = 1 ? " en-US " : " ar " ,
flutterTts: flutterTts ,
) ;
await voiceCaller ! . startCalling ( patientTicket . queueNo . trim ( ) . toString ( ) ! = patientTicket . callNoStr . trim ( ) . toString ( ) ) ;
voiceCaller = null ;
if ( isQueuePatients . isNotEmpty ) {
isQueuePatients . removeAt ( 0 ) ;
}
} else {
isCallingInProgress = false ;
if ( isApiCallNeeded ) {
Timer ( Duration ( seconds: patientCallConfigurations . concurrentCallDelaySec ) , ( ) async {
await callPatientsAPI ( ) ;
isApiCallNeeded = false ;
} ) ;
}
}
}
Future < void > listenAudioPlayerEvents ( ) async {
audioPlayer . playerStateStream . listen ( ( playerState ) async {
if ( playerState . processingState = = ProcessingState . completed ) {
// isCallingInProgress = false;
if ( currentPatient . isVoiceReq ) return ;
if ( isQueuePatients . isNotEmpty ) {
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 ;
if ( isApiCallNeeded ) {
Timer ( Duration ( seconds: patientCallConfigurations . concurrentCallDelaySec ) , ( ) async {
await callPatientsAPI ( ) ;
isApiCallNeeded = false ;
} ) ;
}
}
} ) ;
flutterTts . setStartHandler ( ( ) {
// isCallingInProgress = true;
} ) ;
flutterTts . setCompletionHandler ( ( ) async {
if ( isQueuePatients . isNotEmpty ) {
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 ;
if ( isApiCallNeeded ) {
Timer ( Duration ( seconds: patientCallConfigurations . concurrentCallDelaySec ) , ( ) async {
await callPatientsAPI ( ) ;
isApiCallNeeded = false ;
} ) ;
}
} ) ;
}
// updatePatientTickets() {
// if (patientTickets.isNotEmpty) {
// List<Tickets> _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 < String ? > 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 < void > setLastTimeUpdatedInCache ( { required String lasTimeUpdated } ) async {
final SharedPreferences prefs = await SharedPreferences . getInstance ( ) ;
await prefs . setString ( " lastTimeUpdated " , lasTimeUpdated ) ;
}
}