You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
queuing_system/lib/home/app_provider.dart

453 lines
16 KiB
Dart

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/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;
log("I got this data: ${widgetsConfigModel.toString()}");
notifyListeners();
}
}
WeathersWidgetModel currentWeathersWidgetModel = WeathersWidgetModel();
Future<void> 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();
}
}
String nextPrayerToShowWithTime = '';
void getNextPrayerToShow() {
log("Checking Namaz time!");
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();
}
}
Future<void> 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<void> getTheWidgetsConfigurationsEveryMidnight() async {
if (currentWidgetsConfigModel == null) return;
if (!currentWidgetsConfigModel!.isWeatherReq! && !currentWidgetsConfigModel!.isPrayerTimeReq!) {
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());
if (currentWidgetsConfigModel!.isWeatherReq!) {
if (dateTime.day > currentLastTimeUpdated.day) {
await getWeatherDetailsFromServer();
}
}
if (currentWidgetsConfigModel!.isPrayerTimeReq!) {
if (dateTime.day > currentLastTimeUpdated.day) {
await getPrayerDetailsFromServer();
}
}
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: "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<void> 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<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);
}
}