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.
526 lines
18 KiB
Dart
526 lines
18 KiB
Dart
import 'dart:developer';
|
|
import 'dart:async';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hmg_qline/config/dependency_injection.dart';
|
|
import 'package:hmg_qline/constants/app_constants.dart';
|
|
import 'package:hmg_qline/main.dart';
|
|
import 'package:hmg_qline/models/generic_response_model.dart';
|
|
import 'package:hmg_qline/models/global_config_model.dart';
|
|
import 'package:hmg_qline/models/kiosk_language_config_model.dart';
|
|
import 'package:hmg_qline/models/kiosk_queue_model.dart';
|
|
import 'package:hmg_qline/models/kiosk_ticket_model.dart';
|
|
import 'package:hmg_qline/models/prayers_widget_model.dart';
|
|
import 'package:hmg_qline/models/rss_feed_model.dart';
|
|
import 'package:hmg_qline/models/weathers_widget_model.dart';
|
|
import 'package:hmg_qline/repositories/screen_details_repo.dart';
|
|
import 'package:hmg_qline/services/cache_service.dart';
|
|
import 'package:hmg_qline/services/connectivity_service.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:hmg_qline/utilities/native_method_handler.dart';
|
|
import 'package:hmg_qline/view_models/queuing_view_model.dart';
|
|
import 'package:hmg_qline/views/view_helpers/info_components.dart';
|
|
import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
|
|
// import 'package:timezone/browser.dart' as tz;
|
|
|
|
class ScreenConfigViewModel extends ChangeNotifier {
|
|
final ScreenDetailsRepo screenDetailsRepo;
|
|
final CacheService cacheService;
|
|
final ConnectivityService connectivityService;
|
|
final LoggerService loggerService;
|
|
final NativeMethodChannelService nativeMethodChannelService;
|
|
|
|
ScreenConfigViewModel({
|
|
required this.screenDetailsRepo,
|
|
required this.cacheService,
|
|
required this.connectivityService,
|
|
required this.loggerService,
|
|
required this.nativeMethodChannelService,
|
|
});
|
|
|
|
Future<void> initializeScreenConfigVM() async {
|
|
await getGlobalConfigurationsByIP();
|
|
await getLastTimeUpdatedFromCache();
|
|
listenNetworkConnectivity();
|
|
getTheWidgetsConfigurationsEveryMidnight();
|
|
}
|
|
|
|
Future<void> onAppResumed() async {
|
|
loggerService.logToFile("[didChangeAppLifecycleState] : [onAppResumed]", type: LogTypeEnum.data);
|
|
}
|
|
|
|
Future<void> onAppPaused() async {
|
|
loggerService.logToFile("[didChangeAppLifecycleState] : [onAppPaused]", type: LogTypeEnum.data);
|
|
|
|
// nativeMethodChannelService.reopenApp();
|
|
nativeMethodChannelService.restartApp();
|
|
runApp(const MyApp());
|
|
}
|
|
|
|
Future<void> waitForIPAndInitializeConfigVM() async {
|
|
while (currentScreenIP == "") {
|
|
await getCurrentScreenIP();
|
|
if (currentScreenIP != "") {
|
|
initializeScreenConfigVM();
|
|
} else {
|
|
await Future.delayed(const Duration(seconds: 2));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool isInternetConnected = true;
|
|
|
|
updateIsInternetConnected(bool value) {
|
|
isInternetConnected = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
bool isHubConnected = true;
|
|
|
|
updateIsHubConnected(bool value) {
|
|
isHubConnected = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
ViewState state = ViewState.idle;
|
|
|
|
void updateViewState(ViewState viewState) {
|
|
state = viewState;
|
|
notifyListeners();
|
|
}
|
|
|
|
updateCurrentScreenRotation(ScreenOrientationEnum value) {
|
|
globalConfigurationsModel.orientationTypeEnum = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
ScreenTypeEnum currentScreenTypeEnum = ScreenTypeEnum.waitingAreaScreen;
|
|
|
|
updateCurrentScreenTypeEnum(ScreenTypeEnum value) {
|
|
currentScreenTypeEnum = value;
|
|
}
|
|
|
|
QTypeEnum currentQTypeEnum = QTypeEnum.lab;
|
|
|
|
updateCurrentQTypeEnum(QTypeEnum value) {
|
|
currentQTypeEnum = value;
|
|
}
|
|
|
|
String currentScreenIP = "";
|
|
|
|
Future<void> getCurrentScreenIP() async {
|
|
if (useTestIP) {
|
|
currentScreenIP = AppConstants.testIP;
|
|
} else {
|
|
currentScreenIP = await connectivityService.getCurrentScreenIP();
|
|
log("currentScreenIP: $currentScreenIP");
|
|
}
|
|
}
|
|
|
|
void listenNetworkConnectivity() {
|
|
return connectivityService.subscribeToConnectivityChange(
|
|
onInternetDisConnected: () {
|
|
updateIsInternetConnected(false);
|
|
updateIsHubConnected(false);
|
|
},
|
|
onInternetConnected: () {
|
|
updateIsInternetConnected(true);
|
|
QueuingViewModel queuingViewModel = getIt.get<QueuingViewModel>();
|
|
queuingViewModel.startHubConnection();
|
|
},
|
|
);
|
|
}
|
|
|
|
GlobalConfigurationsModel globalConfigurationsModel = GlobalConfigurationsModel();
|
|
|
|
Future<void> getGlobalConfigurationsByIP() async {
|
|
GlobalConfigurationsModel? response = await screenDetailsRepo.getGlobalScreenConfigurations(ipAddress: currentScreenIP);
|
|
|
|
if (response == null) {
|
|
loggerService.logError("response was: $response");
|
|
updateViewState(ViewState.error);
|
|
return;
|
|
}
|
|
updateGlobalConfigurationsModel(value: response);
|
|
updateCurrentScreenTypeEnum(globalConfigurationsModel.screenTypeEnum);
|
|
updateCurrentQTypeEnum(globalConfigurationsModel.qTypeEnum);
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
void updateGlobalConfigurationsModel({required var value, bool needNotify = false, bool shouldUpdateNextPrayer = false}) {
|
|
globalConfigurationsModel = value;
|
|
|
|
if (needNotify) {
|
|
notifyListeners();
|
|
}
|
|
if (shouldUpdateNextPrayer) {
|
|
getNextPrayerToShow();
|
|
}
|
|
|
|
getInfoWidgetsDetailsFromServer();
|
|
}
|
|
|
|
Future<void> getInfoWidgetsDetailsFromServer() async {
|
|
if (globalConfigurationsModel.isWeatherReq) {
|
|
await getWeatherDetailsFromServer();
|
|
}
|
|
if (globalConfigurationsModel.isPrayerTimeReq) {
|
|
await getPrayerDetailsFromServer();
|
|
}
|
|
if (globalConfigurationsModel.isRssFeedReq) {
|
|
await getRssFeedDetailsFromServer();
|
|
}
|
|
|
|
int currentDate = DateTime.now().millisecondsSinceEpoch;
|
|
await cacheService.setLastTimeUpdatedInCache(lasTimeUpdated: currentDate.toString());
|
|
}
|
|
|
|
RssFeedModel rssFeedModel = RssFeedModel();
|
|
|
|
Future<void> getRssFeedDetailsFromServer() async {
|
|
RssFeedModel? response = await screenDetailsRepo.getRssFeedDetailsByLanguageID(languageId: 0);
|
|
|
|
if (response == null) {
|
|
return;
|
|
}
|
|
rssFeedModel = response;
|
|
notifyListeners();
|
|
}
|
|
|
|
PrayersWidgetModel prayersWidgetModel = PrayersWidgetModel();
|
|
|
|
Future<void> getPrayerDetailsFromServer() async {
|
|
double testLatitude = 24.722136;
|
|
double testLongitude = 46.774303;
|
|
PrayersWidgetModel? response = await screenDetailsRepo.getPrayerDetailsByLatLong(
|
|
latitude: globalConfigurationsModel.projectLatitude == 0.0 ? testLatitude : globalConfigurationsModel.projectLatitude ?? testLatitude,
|
|
longitude: globalConfigurationsModel.projectLongitude == 0.0 ? testLongitude : globalConfigurationsModel.projectLongitude ?? testLongitude,
|
|
);
|
|
|
|
if (response == null) {
|
|
return;
|
|
}
|
|
|
|
prayersWidgetModel = response;
|
|
getNextPrayerToShow();
|
|
notifyListeners();
|
|
}
|
|
|
|
WeathersWidgetModel weathersWidgetModel = WeathersWidgetModel();
|
|
|
|
Future<void> getWeatherDetailsFromServer() async {
|
|
int testCityKey = 297030;
|
|
WeathersWidgetModel? response = await screenDetailsRepo.getWeatherDetailsByCity(
|
|
cityId: ((globalConfigurationsModel.cityKey == null || globalConfigurationsModel.cityKey == 0) ? testCityKey : globalConfigurationsModel.cityKey).toString(),
|
|
);
|
|
|
|
if (response == null) {
|
|
return;
|
|
}
|
|
weathersWidgetModel = response;
|
|
notifyListeners();
|
|
}
|
|
|
|
String nextPrayerToShowWithTime = '';
|
|
|
|
void getNextPrayerToShow() async {
|
|
final current = DateTime.now();
|
|
log("Checking Namaz time Locally at ${current.toString()} and ${current.timeZoneName} ");
|
|
|
|
if (!isHubConnected) {
|
|
log("Hub is Not Connected!, I will try to reconnect now.");
|
|
QueuingViewModel queuingViewModel = getIt.get<QueuingViewModel>();
|
|
bool? status = await queuingViewModel.startHubConnection();
|
|
if (status != false) {
|
|
updateIsHubConnected(true);
|
|
}
|
|
} else {
|
|
log("Hub is Connected!");
|
|
}
|
|
|
|
// log("Data Before Check : ${prayersWidgetModel.fajr}");
|
|
// log("Data Before Check : ${globalConfigurationsModel.isPrayerTimeReq}");
|
|
|
|
if (globalConfigurationsModel.isPrayerTimeReq && prayersWidgetModel.fajr == null) {
|
|
await getPrayerDetailsFromServer();
|
|
}
|
|
|
|
// log("prayersWidgetModel.dhuhr: ${prayersWidgetModel.dhuhr!}");
|
|
// log("dhuhr: ${prayersWidgetModel.dhuhr!.toDateTimeFromInt()}");
|
|
// log("current: ${DateFormat('yyyy-MM-dd hh:mm a').format(DateTime.now().toLocal())}");
|
|
// log("current: ${DateTime.now().timeZoneName}");
|
|
|
|
if (prayersWidgetModel.fajr != null && prayersWidgetModel.fajr!.toDateTimeFromInt().isAfter(current)) {
|
|
final namazTime = prayersWidgetModel.fajr!.toFormattedDateTimeFromInt();
|
|
nextPrayerToShowWithTime = "${globalConfigurationsModel.fajarText} at $namazTime";
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
if (prayersWidgetModel.dhuhr != null && prayersWidgetModel.dhuhr!.toDateTimeFromInt().isAfter(current)) {
|
|
final namazTime = prayersWidgetModel.dhuhr!.toFormattedDateTimeFromInt();
|
|
nextPrayerToShowWithTime = "${globalConfigurationsModel.dhuhrText} at $namazTime";
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
if (prayersWidgetModel.asr != null && prayersWidgetModel.asr!.toDateTimeFromInt().isAfter(current)) {
|
|
final namazTime = prayersWidgetModel.asr!.toFormattedDateTimeFromInt();
|
|
nextPrayerToShowWithTime = "${globalConfigurationsModel.asarText} at $namazTime";
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
if (prayersWidgetModel.maghrib != null && prayersWidgetModel.maghrib!.toDateTimeFromInt().isAfter(current)) {
|
|
final namazTime = prayersWidgetModel.maghrib!.toFormattedDateTimeFromInt();
|
|
nextPrayerToShowWithTime = "${globalConfigurationsModel.maghribText} at $namazTime";
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
if (prayersWidgetModel.isha != null && prayersWidgetModel.isha!.toDateTimeFromInt().isAfter(current)) {
|
|
final namazTime = prayersWidgetModel.isha!.toFormattedDateTimeFromInt();
|
|
nextPrayerToShowWithTime = "${globalConfigurationsModel.ishaText} at $namazTime";
|
|
notifyListeners();
|
|
return;
|
|
}
|
|
}
|
|
|
|
int counter = 0;
|
|
|
|
Timer? _midnightTimer;
|
|
|
|
Future<void> getTheWidgetsConfigurationsEveryMidnight() async {
|
|
// Cancel any existing timer to avoid multiple timers running
|
|
_midnightTimer?.cancel();
|
|
|
|
if (!(globalConfigurationsModel.isWeatherReq) && !(globalConfigurationsModel.isPrayerTimeReq) && !(globalConfigurationsModel.isRssFeedReq)) {
|
|
return;
|
|
}
|
|
|
|
int counter = 0;
|
|
DateTime lastChecked = DateTime.now();
|
|
|
|
_midnightTimer = Timer.periodic(const Duration(minutes: 5), (timer) async {
|
|
counter++;
|
|
DateTime now = DateTime.now();
|
|
log("counterValue: $counter");
|
|
|
|
// Every hour, update RSS feed if required
|
|
if (counter % 12 == 0 && globalConfigurationsModel.isRssFeedReq) {
|
|
await getRssFeedDetailsFromServer();
|
|
}
|
|
|
|
log("lastChecked: [${lastChecked.day}]");
|
|
log("now: [${now.day}]");
|
|
|
|
// At midnight, update weather and prayer details if required
|
|
if (now.day != lastChecked.day) {
|
|
if (globalConfigurationsModel.isWeatherReq) {
|
|
await getWeatherDetailsFromServer();
|
|
}
|
|
if (globalConfigurationsModel.isPrayerTimeReq) {
|
|
await getPrayerDetailsFromServer();
|
|
}
|
|
lastChecked = now;
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_midnightTimer?.cancel();
|
|
patientIdController.dispose();
|
|
|
|
super.dispose();
|
|
}
|
|
|
|
DateTime currentLastTimeUpdated = DateTime.now();
|
|
|
|
Future<void> getLastTimeUpdatedFromCache() async {
|
|
DateTime? response = await cacheService.getLastTimeUpdatedFromCache();
|
|
if (response != null) {
|
|
currentLastTimeUpdated = response;
|
|
}
|
|
}
|
|
|
|
// *************************** KIOSK FUNCTIONS *************************
|
|
|
|
KioskScreenStateEnums kioskScreenStateEnum = KioskScreenStateEnums.languageState;
|
|
|
|
void updateKioskScreenState(KioskScreenStateEnums state) {
|
|
kioskScreenStateEnum = state;
|
|
notifyListeners();
|
|
}
|
|
|
|
KioskPatientTicket? kioskPatientTicket = KioskPatientTicket();
|
|
|
|
void updateTicketGeneratedFromKiosk(KioskPatientTicket? value) {
|
|
kioskPatientTicket = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
KioskLanguageConfigModel? currentSelectedKioskLanguage;
|
|
|
|
void updateCurrentSelectedKioskLanguageModel(KioskLanguageConfigModel value) {
|
|
currentSelectedKioskLanguage = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
late KioskQueueModel currentSelectedKioskQueueModel;
|
|
|
|
void updateCurrentSelectedKioskQueueModel(KioskQueueModel value) {
|
|
currentSelectedKioskQueueModel = value;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<bool> generateTicketForQueue({required KioskQueueModel kioskQueueModel, int patientId = 0}) async {
|
|
updateKioskScreenState(KioskScreenStateEnums.busyState);
|
|
KioskPatientTicket? kioskPatientTicket = await createTicketFromKiosk(
|
|
projectId: kioskQueueModel.projectID ?? 0,
|
|
queueId: kioskQueueModel.queueID ?? 0,
|
|
patientId: patientId,
|
|
);
|
|
if (kioskPatientTicket == null) {
|
|
updateKioskScreenState(KioskScreenStateEnums.languageState);
|
|
return false;
|
|
}
|
|
updateTicketGeneratedFromKiosk(kioskPatientTicket);
|
|
updateKioskScreenState(KioskScreenStateEnums.ticketNumState);
|
|
return true;
|
|
}
|
|
|
|
Future<void> createTestTickets({required int numOfTicketsToCreate}) async {
|
|
int startTicket = 123457100;
|
|
|
|
for (int i = 0; i < numOfTicketsToCreate; i++) {
|
|
GenericRespModel? response = await screenDetailsRepo.createTestTickets(ticketNumber: startTicket);
|
|
startTicket = startTicket + 1;
|
|
if (response == null || response.messageStatus != 1) {
|
|
log("response null from createNextTickets");
|
|
return;
|
|
}
|
|
}
|
|
|
|
log("last ticket is: $startTicket ");
|
|
}
|
|
|
|
Future<KioskPatientTicket?> createTicketFromKiosk({required int projectId, required int queueId, int patientId = 0}) async {
|
|
try {
|
|
GenericRespModel? response = await screenDetailsRepo.createTicketFromKiosk(
|
|
projectId: projectId,
|
|
queueId: queueId,
|
|
patientId: patientId,
|
|
);
|
|
if (response == null || response.messageStatus != 1) {
|
|
loggerService.logError("response null from createTicketFromKiosk");
|
|
return null;
|
|
}
|
|
return response.data;
|
|
} catch (e) {
|
|
InfoComponents.showToast(e.toString());
|
|
loggerService.logError(e.toString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> acknowledgeTicket({required int ticketQueueID}) async {
|
|
GenericRespModel? response = await screenDetailsRepo.acknowledgeTicket(
|
|
ipAddress: currentScreenIP,
|
|
ticketQueueID: ticketQueueID,
|
|
qTypeEnum: globalConfigurationsModel.qTypeEnum,
|
|
);
|
|
if (response == null || response.messageStatus != 1) {
|
|
loggerService.logError("response null from acknowledgeTicket");
|
|
return;
|
|
} else {
|
|
loggerService.logInfo("response from acknowledgeTicket ${response.data}");
|
|
}
|
|
}
|
|
|
|
Future<void> acknowledgeTicketForAppointmentOnly({required int ticketQueueID, required String ipAddress, required CallTypeEnum callTypeEnum}) async {
|
|
GenericRespModel? response = await screenDetailsRepo.acknowledgeTicketForAppointment(
|
|
ticketId: ticketQueueID,
|
|
ipAddress: ipAddress,
|
|
callTypeEnum: callTypeEnum,
|
|
);
|
|
if (response == null || response.messageStatus != 1) {
|
|
loggerService.logError("response null from acknowledgeTicketForAppointmentOnly");
|
|
return;
|
|
} else {
|
|
loggerService.logInfo("response from acknowledgeTicketForAppointmentOnly ${response.data}");
|
|
}
|
|
}
|
|
|
|
// ***************************** TEXT INPUT PATIENT ID FUNCTIONS *********************
|
|
|
|
final TextEditingController patientIdController = TextEditingController();
|
|
|
|
Future<void> onPatientIdSubmitted(String text) async {
|
|
int? patientId = int.tryParse(text);
|
|
if (patientId != null && patientId > 0) {
|
|
isGeneratingTicket = true;
|
|
await generateTicketForQueue(kioskQueueModel: currentSelectedKioskQueueModel, patientId: patientId);
|
|
patientIdController.clear();
|
|
await Future.delayed(const Duration(seconds: 2)).whenComplete(() => isGeneratingTicket = false);
|
|
}
|
|
}
|
|
|
|
// *************************** QR SCANNER FUNCTIONS *************************
|
|
|
|
Barcode? qrCodeResult;
|
|
QRViewController? qrViewController;
|
|
bool isGeneratingTicket = false;
|
|
|
|
Future<void> flipCamera() async {
|
|
await qrViewController!.flipCamera();
|
|
}
|
|
|
|
void onQRViewCreated({
|
|
required QRViewController controller,
|
|
required VoidCallback onSuccess,
|
|
required VoidCallback onFailure,
|
|
}) async {
|
|
qrViewController = controller;
|
|
|
|
controller.scannedDataStream.listen((scanData) async {
|
|
loggerService.logInfo("Found: ${scanData.code} and isGeneratingTicket: $isGeneratingTicket");
|
|
if (isGeneratingTicket) return;
|
|
await validateAndGenerateTicketFromQR(data: scanData, onFailure: onFailure, onSuccess: onSuccess);
|
|
});
|
|
await flipCamera();
|
|
}
|
|
|
|
Future<void> validateAndGenerateTicketFromQR({required var data, required VoidCallback onSuccess, required VoidCallback onFailure}) async {
|
|
if (data == null) return;
|
|
qrCodeResult = data;
|
|
notifyListeners();
|
|
|
|
final code = qrCodeResult!.code;
|
|
int? patientId = int.tryParse(code ?? '');
|
|
if (patientId != null && patientId > 0) {
|
|
isGeneratingTicket = true;
|
|
bool status = await generateTicketForQueue(kioskQueueModel: currentSelectedKioskQueueModel, patientId: patientId);
|
|
qrCodeResult = null;
|
|
notifyListeners();
|
|
|
|
if (status) {
|
|
log("status: $status");
|
|
onSuccess();
|
|
}
|
|
|
|
await Future.delayed(const Duration(seconds: 2)).whenComplete(() => isGeneratingTicket = false);
|
|
}
|
|
}
|
|
|
|
Future<void> reassemble() async {
|
|
if (qrViewController != null) {
|
|
if (defaultTargetPlatform == TargetPlatform.android) {
|
|
await qrViewController!.pauseCamera();
|
|
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
|
|
await qrViewController!.resumeCamera();
|
|
}
|
|
await qrViewController!.flipCamera();
|
|
}
|
|
}
|
|
}
|