Completed Kiosk Flow

faiz_kiosk
FaizHashmiCS22 7 months ago
parent 7442e2d36b
commit fcec60e978

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="100px" height="100px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 15H21M3 19H15M3 7H11M3 11H11M19.4 11H16.6C16.0399 11 15.7599 11 15.546 10.891C15.3578 10.7951 15.2049 10.6422 15.109 10.454C15 10.2401 15 9.96005 15 9.4V6.6C15 6.03995 15 5.75992 15.109 5.54601C15.2049 5.35785 15.3578 5.20487 15.546 5.10899C15.7599 5 16.0399 5 16.6 5H19.4C19.9601 5 20.2401 5 20.454 5.10899C20.6422 5.20487 20.7951 5.35785 20.891 5.54601C21 5.75992 21 6.03995 21 6.6V9.4C21 9.96005 21 10.2401 20.891 10.454C20.7951 10.6422 20.6422 10.7951 20.454 10.891C20.2401 11 19.9601 11 19.4 11Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 824 B

@ -59,6 +59,7 @@ class AppAssets {
static String noInternetImage = "assets/images/undraw_connected_world_wuay.png";
static String cloudLogo = "assets/images/cloud_logo.png";
static String languageIcon = "assets/images/language_icon.svg";
static String kioskQueueIcon = "assets/images/kiosk_queue_icon.svg";
//IconPaths
static String vitalSignIcon = "assets/images/vitalsign_icon.svg";
@ -88,7 +89,7 @@ class AppConstants {
static String onlyLetters = "[a-zA-Z &'\"]";
static String onlyDate = "[0-9/]";
static String apiKey = 'EE17D21C7943485D9780223CCE55DCE5';
static String testIP = '10.20.10.30';
static String testIP = '12.4.5.1'; // projectID.QlineType.ScreenType.AnyNumber (1 to 10)
static int thresholdForListUI = 3;
}
@ -96,7 +97,8 @@ class ApiConstants {
static String baseUrl = 'https://ms.hmg.com/nscapi';
static String baseUrlHub = '$baseUrl/PatientCallingHub';
static String baseUrlApi = '$baseUrl/api';
static String baseUrlApiGen = '$baseUrl/api/Gen/';
static String baseUrlApiGen = '$baseUrl/api/Gen';
static String baseUrlApiPatientCall = '$baseUrlApi/PatientCall';
static String createTicket = '$baseUrlApiPatientCall/LAB_PatientCallNo_Get';
static String commonConfigGet = '$baseUrlApiPatientCall/Common_Config_GetByIP';
@ -108,6 +110,7 @@ class ApiConstants {
//Generic
static String createTicketForKiosk = '$baseUrlApiGen/GEN_PatientCallNo_Get';
static String ticketCallRequestUpdateForKiosk = '$baseUrlApiGen/GEN_TicketQueueAck_Insert';
// Signal R Constants

@ -25,7 +25,7 @@ class MyApp extends StatelessWidget {
builder: (context, constraints) {
return OrientationBuilder(builder: (context, orientation) {
SizeConfig().init(constraints, orientation);
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
return MultiProvider(
providers: [

@ -1,5 +1,5 @@
import 'dart:developer';
import 'dart:ui';
import 'package:hmg_qline/models/kiosk_queue_model.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
@ -59,6 +59,7 @@ class GlobalConfigurationsModel {
double? projectLatitude;
double? projectLongitude;
int? cityKey;
List<KioskQueueModel>? kioskQueueList;
GlobalConfigurationsModel({
this.id,
@ -116,6 +117,7 @@ class GlobalConfigurationsModel {
this.projectLatitude,
this.projectLongitude,
this.cityKey,
this.kioskQueueList,
});
GlobalConfigurationsModel.fromJson(Map<String, dynamic> json) {
@ -176,6 +178,9 @@ class GlobalConfigurationsModel {
projectLatitude = json['projectLatitude'] == 0 ? 0.0 : json['projectLatitude'];
projectLongitude = json['projectLongitude'] == 0 ? 0.0 : json['projectLongitude'];
cityKey = json['cityKey'];
if (json['kioskQueue'] != null) {
kioskQueueList = List<KioskQueueModel>.from(json['kioskQueue'].map((kioskQueueJson) => KioskQueueModel.fromJson(kioskQueueJson)));
}
}
}

@ -0,0 +1,56 @@
class KioskQueueModel {
int? id;
int? projectID;
String? projectName;
String? projectNameN;
int? queueID;
String? queueName;
String? queueNameN;
int? kioskID;
String? kioskName;
String? kioskNameN;
String? ipAddress;
bool? isActive;
int? createdBy;
String? createdOn;
dynamic editedBy;
dynamic editedOn;
KioskQueueModel({
this.id,
this.projectID,
this.projectName,
this.projectNameN,
this.queueID,
this.queueName,
this.queueNameN,
this.kioskID,
this.kioskName,
this.kioskNameN,
this.ipAddress,
this.isActive,
this.createdBy,
this.createdOn,
this.editedBy,
this.editedOn,
});
KioskQueueModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
projectID = json['projectID'];
projectName = json['projectName'];
projectNameN = json['projectNameN'];
queueID = json['queueID'];
queueName = json['queueName'];
queueNameN = json['queueNameN'];
kioskID = json['kioskID'];
kioskName = json['kioskName'];
kioskNameN = json['kioskNameN'];
ipAddress = json['ipAddress'];
isActive = json['isActive'];
createdBy = json['createdBy'];
createdOn = json['createdOn'];
editedBy = json['editedBy'];
editedOn = json['editedOn'];
}
}

@ -0,0 +1,22 @@
class KioskPatientTicket {
String? patientCallNo;
int? projectID;
int? ticketQueueID;
int? result;
KioskPatientTicket({
this.patientCallNo,
this.projectID,
this.ticketQueueID,
this.result,
});
factory KioskPatientTicket.fromJson(Map<String, dynamic> json) {
return KioskPatientTicket(
patientCallNo: json['patientCallNo'],
projectID: json['projectID'],
ticketQueueID: json['ticketQueueID'],
result: json['result'],
);
}
}

@ -2,6 +2,7 @@ import 'package:hmg_qline/api/api_client.dart';
import 'package:hmg_qline/constants/app_constants.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_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';
@ -13,7 +14,7 @@ abstract class ScreenDetailsRepo {
Future<GenericRespModel?> createNextTickets({required int ticketNumber});
Future<GenericRespModel?> createTicketFromKiosk({required int queueId});
Future<GenericRespModel?> createTicketFromKiosk({required int projectId, required int queueId});
Future<WidgetsConfigModel?> getScreenConfigurationsByIP({required String ipAddress});
@ -80,20 +81,23 @@ class ScreenDetailsRepoImp implements ScreenDetailsRepo {
}
@override
Future<GenericRespModel?> createTicketFromKiosk({required int queueId}) async {
Future<GenericRespModel?> createTicketFromKiosk({required int projectId, required int queueId}) async {
try {
var params = {
"projectID": "15",
"projectID": "$projectId",
"queueID": "$queueId",
"isVidaPlus": false,
"createdBy": "101",
"isVidaPlus": true,
"apiKey": AppConstants.apiKey,
};
GenericRespModel adsGenericModel = await apiClientInstance.postJsonForObject(
GenericRespModel genericRespModel = await apiClientInstance.postJsonForObject(
(json) => GenericRespModel.fromJson(json),
ApiConstants.createTicketForKiosk,
params,
);
return adsGenericModel;
genericRespModel.data = KioskPatientTicket.fromJson(genericRespModel.data);
return genericRespModel;
} catch (e) {
logger.e(e.toString());
InfoComponents.showToast(e.toString());

@ -36,4 +36,5 @@ enum KioskScreenStateEnums {
languageState,
queueSelectionState,
ticketNoState,
busyState,
}

@ -5,6 +5,8 @@ import 'package:hmg_qline/config/dependency_injection.dart';
import 'package:hmg_qline/constants/app_constants.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_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';
@ -14,6 +16,7 @@ import 'package:hmg_qline/services/connectivity_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
import 'package:hmg_qline/view_models/queuing_view_model.dart';
import 'package:hmg_qline/views/view_helpers/info_components.dart';
class ScreenConfigViewModel extends ChangeNotifier {
final ScreenDetailsRepo screenDetailsRepo;
@ -73,6 +76,13 @@ class ScreenConfigViewModel extends ChangeNotifier {
notifyListeners();
}
KioskPatientTicket? kioskPatientTicket = KioskPatientTicket();
void updateTicketGeneratedFromKiosk(KioskPatientTicket? value) {
kioskPatientTicket = value;
notifyListeners();
}
LanguageEnum currentSelectedKioskLanguage = LanguageEnum.english;
void updateCurrentSelectedKioskLanguage(LanguageEnum value) {
@ -122,9 +132,9 @@ class ScreenConfigViewModel extends ChangeNotifier {
GlobalConfigurationsModel globalConfigurationsModel = GlobalConfigurationsModel();
Future<void> getGlobalConfigurationsByIP() async {
// TODO: TEST ONLY
updateCurrentScreenTypeEnum(ScreenTypeEnum.kioskScreen);
updateCurrentQTypeEnum(QTypeEnum.general);
// // TODO: TEST ONLY
// updateCurrentScreenTypeEnum(ScreenTypeEnum.kioskScreen);
// updateCurrentQTypeEnum(QTypeEnum.general);
GlobalConfigurationsModel? response = await screenDetailsRepo.getGlobalScreenConfigurations(ipAddress: currentScreenIP);
if (response == null) {
@ -132,8 +142,8 @@ class ScreenConfigViewModel extends ChangeNotifier {
return;
}
updateGlobalConfigurationsModel(value: response);
// updateCurrentScreenTypeEnum(globalConfigurationsModel.screenTypeEnum);
// updateCurrentQTypeEnum(globalConfigurationsModel.qTypeEnum);
updateCurrentScreenTypeEnum(globalConfigurationsModel.screenTypeEnum);
updateCurrentQTypeEnum(globalConfigurationsModel.qTypeEnum);
notifyListeners();
}
@ -322,4 +332,19 @@ class ScreenConfigViewModel extends ChangeNotifier {
log("last ticket is: $startTicket ");
}
Future<KioskPatientTicket?> createTicketFromKiosk({required int projectId, required int queueId}) async {
try {
GenericRespModel? response = await screenDetailsRepo.createTicketFromKiosk(projectId: projectId, queueId: queueId);
if (response == null || response.messageStatus != 1) {
logger.e("response null from createTicketFromKiosk");
return null;
}
return response.data;
} catch (e) {
InfoComponents.showToast(e.toString());
logger.i(e.toString());
return null;
}
}
}

@ -153,13 +153,12 @@ Widget noPatientInQueue({required String text, required String fontName, require
}
Widget commonSelectionCardKiosk({required ScreenConfigViewModel screenConfigViewModel, required String title, required String icon, required VoidCallback onTap}) {
log("screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum: ${screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum}");
return InkWell(
onTap: onTap,
child: SizedBox(
child: Container(
constraints: BoxConstraints(minWidth: SizeConfig.getWidthMultiplier() * 30),
padding: const EdgeInsets.all(10),
constraints: BoxConstraints(minWidth: SizeConfig.getWidthMultiplier() * 40),
padding: const EdgeInsets.all(30),
margin: const EdgeInsets.all(10),
decoration: AppColors.configWidgetDecoration,
child: Directionality(

@ -2,6 +2,9 @@ import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/models/generic_response_model.dart';
import 'package:hmg_qline/models/kiosk_queue_model.dart';
import 'package:hmg_qline/models/kiosk_ticket_model.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
@ -78,25 +81,45 @@ class KioskMainScreen extends StatelessWidget {
}
Widget kioskQueueSelectionStateWidget(ScreenConfigViewModel screenConfigViewModel) {
return GridView.builder(
itemCount: 5,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum == ScreenOrientationEnum.portraitUp ||
screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum == ScreenOrientationEnum.portraitDown)
? 3
: 2,
),
itemBuilder: (BuildContext context, int index) {
return Column(mainAxisSize: MainAxisSize.min, children: [
commonSelectionCardKiosk(
screenConfigViewModel: screenConfigViewModel,
title: "New Latest Certificate Generation ${index + 1}",
icon: AppAssets.languageIcon,
onTap: () {
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.ticketNoState);
}),
]);
});
bool isEnglish = screenConfigViewModel.currentSelectedKioskLanguage == LanguageEnum.english;
return Directionality(
textDirection: isEnglish ? TextDirection.ltr : TextDirection.rtl,
child: GridView.builder(
itemCount: screenConfigViewModel.globalConfigurationsModel.kioskQueueList!.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum == ScreenOrientationEnum.portraitUp ||
screenConfigViewModel.globalConfigurationsModel.orientationTypeEnum == ScreenOrientationEnum.portraitDown)
? 2
: 3,
),
itemBuilder: (BuildContext context, int index) {
KioskQueueModel kioskQueueModel = screenConfigViewModel.globalConfigurationsModel.kioskQueueList![index];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
commonSelectionCardKiosk(
screenConfigViewModel: screenConfigViewModel,
title: screenConfigViewModel.currentSelectedKioskLanguage == LanguageEnum.english ? "${kioskQueueModel.queueName}" : "${kioskQueueModel.queueNameN}",
icon: AppAssets.kioskQueueIcon,
onTap: () async {
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.busyState);
KioskPatientTicket? kioskPatientTicket = await screenConfigViewModel.createTicketFromKiosk(
projectId: kioskQueueModel.projectID ?? 0,
queueId: kioskQueueModel.queueID ?? 0,
);
if (kioskPatientTicket == null) {
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.languageState);
return;
}
screenConfigViewModel.updateTicketGeneratedFromKiosk(kioskPatientTicket);
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.ticketNoState);
},
),
],
);
}),
);
}
Widget kioskTicketNumberStateWidget(ScreenConfigViewModel screenConfigViewModel) {
@ -112,18 +135,13 @@ class KioskMainScreen extends StatelessWidget {
fontFamily: isEnglish ? AppStrings.fontNameCairo : AppStrings.fontNamePoppins,
),
const SizedBox(height: 20),
InkWell(
onTap: () {
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.languageState);
},
child: AppText(
isEnglish ? "PHR-45" : "بي اتش ار-٤٥",
fontSize: SizeConfig.getWidthMultiplier() * 10,
fontHeight: 1,
fontWeight: FontWeight.bold,
textDirection: isEnglish ? TextDirection.ltr : TextDirection.rtl,
fontFamily: isEnglish ? AppStrings.fontNameCairo : AppStrings.fontNamePoppins,
),
AppText(
screenConfigViewModel.kioskPatientTicket!.patientCallNo ?? "",
fontSize: SizeConfig.getWidthMultiplier() * 10,
fontHeight: 1,
fontWeight: FontWeight.bold,
textDirection: isEnglish ? TextDirection.ltr : TextDirection.rtl,
fontFamily: isEnglish ? AppStrings.fontNameCairo : AppStrings.fontNamePoppins,
),
const SizedBox(height: 20),
AppText(
@ -134,6 +152,21 @@ class KioskMainScreen extends StatelessWidget {
fontHeight: 1,
fontFamily: isEnglish ? AppStrings.fontNameCairo : AppStrings.fontNamePoppins,
),
const SizedBox(height: 100),
InkWell(
onTap: () {
screenConfigViewModel.updateKioskScreenState(KioskScreenStateEnums.languageState);
},
child: AppText(
isEnglish ? "Go to Main Page" : "اذهب إلى الصفحة الرئيسية",
fontSize: SizeConfig.getWidthMultiplier() * 3,
textAlign: TextAlign.center,
textDecoration: TextDecoration.underline,
textDirection: isEnglish ? TextDirection.ltr : TextDirection.rtl,
fontHeight: 1,
fontFamily: isEnglish ? AppStrings.fontNameCairo : AppStrings.fontNamePoppins,
),
),
],
);
}
@ -141,13 +174,16 @@ class KioskMainScreen extends StatelessWidget {
Widget dataContentKiosk({required BuildContext context}) {
return Padding(
padding: const EdgeInsets.all(10),
child: Consumer(builder: (BuildContext context, ScreenConfigViewModel screenConfigViewModel, Widget? child) {
return switch (screenConfigViewModel.kioskScreenStateEnum) {
KioskScreenStateEnums.languageState => kioskLanguageStateWidget(screenConfigViewModel),
KioskScreenStateEnums.queueSelectionState => kioskQueueSelectionStateWidget(screenConfigViewModel),
KioskScreenStateEnums.ticketNoState => kioskTicketNumberStateWidget(screenConfigViewModel),
};
}),
child: Consumer(
builder: (BuildContext context, ScreenConfigViewModel screenConfigViewModel, Widget? child) {
return switch (screenConfigViewModel.kioskScreenStateEnum) {
KioskScreenStateEnums.languageState => kioskLanguageStateWidget(screenConfigViewModel),
KioskScreenStateEnums.queueSelectionState => kioskQueueSelectionStateWidget(screenConfigViewModel),
KioskScreenStateEnums.ticketNoState => kioskTicketNumberStateWidget(screenConfigViewModel),
KioskScreenStateEnums.busyState => const Center(child: CircularProgressIndicator()),
};
},
),
);
}

@ -47,7 +47,6 @@ class SplashScreen extends StatelessWidget {
// If the data is loaded successfully
if (snapshot.connectionState == ConnectionState.done) {
Future.delayed(const Duration(seconds: 1)).whenComplete(() {
log("context.read<ScreenConfigViewModel>().currentScreenTypeEnum: ${context.read<ScreenConfigViewModel>().currentScreenTypeEnum}");
if (context.read<ScreenConfigViewModel>().currentScreenTypeEnum == ScreenTypeEnum.kioskScreen) {
context.navigateReplaceTo(AppRoutes.kioskMainScreen);
} else {

@ -77,10 +77,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.18.0"
connectivity_plus:
dependency: "direct main"
description:
@ -332,18 +332,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@ -628,7 +628,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
version: "0.0.99"
source_span:
dependency: transitive
description:
@ -665,10 +665,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
@ -681,10 +681,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.2.0"
term_glyph:
dependency: transitive
description:
@ -697,10 +697,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.2"
tuple:
dependency: transitive
description:
@ -761,10 +761,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.2.5"
wakelock_plus:
dependency: "direct main"
description:

Loading…
Cancel
Save