Symptoms checker flow updates and Design Fixes on Fold

pull/301/head
faizatflutter 9 hours ago
parent 7b1684c455
commit 63fd82407e

@ -17,7 +17,6 @@ import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:http/http.dart' as http;
abstract class ApiClient {
static final NavigationService _navigationService = getIt.get<NavigationService>();
@ -209,7 +208,7 @@ class ApiClientImp implements ApiClient {
// body['PatientOutSA'] = 0;
// body['SessionID'] = "45786230487560q";
//VIP Patient: 1181868
//VIP Patient: 1181868body:
// body['IdentificationNo'] = "2235558844";
// body['MobileNo'] = "966533147722";
@ -244,6 +243,7 @@ class ApiClientImp implements ApiClient {
http.Response response;
try {
response = await http.post(Uri.parse(url.trim()), body: requestBody, headers: headers);
debugPrint("response: ${response.body}", wrapWidth: 2048);
} on SocketException catch (e) {
final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
onFailure(message, -1, failureType: ConnectivityFailure(message));

@ -11,8 +11,14 @@ class ApiConsts {
static String baseUrl = 'https://hmgwebservices.com/'; // HIS API URL PROD
static String rcBaseUrl = 'https://rc.hmg.com/'; // dRC API URL PROD
static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // dRC API URL PROD
static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD
static String hmgPharmacyApiBaseUrl = 'https://hmgpharmacyapi.hmg.com/'; // symptoms API URL PROD
static String symptomsCheckerApiUAT = '${hmgPharmacyApiBaseUrl}symptomsapi/api/SymptomChecker'; // dRC API URL PROD
static String symptomsCheckerApiLive = '${hmgPharmacyApiBaseUrl}symptomsapi_live/api/SymptomChecker'; // dRC API URL PROD
static String symptomsCheckerApi = '${hmgPharmacyApiBaseUrl}symptomsapi_live/api/SymptomChecker'; // dRC API URL PROD
// Symptoms Checker Credentials
static String symptomsCheckerUsername = 'mobile_user';
static String symptomsCheckerPassword = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92';
static var payFortEnvironment = FortEnvironment.production;
static var applePayMerchantId = "merchant.com.hmgwebservices";
@ -25,6 +31,7 @@ class ApiConsts {
static String GET_TAMARA_PAYMENT_STATUS = 'https://mdlaboratories.com/tamaralive/api/OnlineTamara/order_status?orderid=';
static String QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
// static String QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
static String CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
@ -47,6 +54,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/';
QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiLive;
symptomsCheckerUsername = 'mobile_user';
symptomsCheckerPassword = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92';
break;
case AppEnvironmentTypeEnum.dev:
baseUrl = "https://uat.hmgwebservices.com/";
@ -59,6 +70,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
case AppEnvironmentTypeEnum.uat:
baseUrl = "https://uat.hmgwebservices.com/";
@ -71,6 +86,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
case AppEnvironmentTypeEnum.preProd:
baseUrl = "https://webservices.hmg.com/";
@ -83,6 +102,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/';
QLINE_URL = "https://qline.hmg.com/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
case AppEnvironmentTypeEnum.qa:
baseUrl = "https://uat.hmgwebservices.com/";
@ -95,6 +118,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
case AppEnvironmentTypeEnum.staging:
baseUrl = "https://uat.hmgwebservices.com/";
@ -107,6 +134,10 @@ class ApiConsts {
rcBaseUrl = 'https://rc.hmg.com/uat/';
QLINE_URL = "https://ms.hmg.com/nscapi/api/PatientCall/PatientInQueue_Detail";
CHAT_URL = "https://chat.hmg.com/geneysChat/Index.aspx?RequestedId=";
symptomsCheckerApi = symptomsCheckerApiUAT;
symptomsCheckerUsername = 'guest_user';
symptomsCheckerPassword = '123456';
break;
}
}
@ -189,7 +220,6 @@ class ApiConsts {
static final createEReferral = "Services/Patients.svc/REST/CreateEReferral";
static final getEReferrals = "Services/Patients.svc/REST/GetEReferrals";
//WATER CONSUMPTION
static String h2oGetUserProgress = "Services/H2ORemainder.svc/REST/H2O_GetUserProgress";
static String h2oInsertUserActivity = "Services/H2ORemainder.svc/REST/H2O_InsertUserActivity";
@ -235,6 +265,7 @@ class ApiConsts {
static String getPatientBloodGroup = "services/PatientVarification.svc/REST/BloodDonation_GetBloodGroupDetails";
static String getPatientBloodAgreement = "Services/PatientVarification.svc/REST/CheckUserAgreementForBloodDonation";
static String getPatientBloodTypeNew = "Services/Patients.svc/REST/HIS_GetPatientBloodType_New";
// static String getAiOverViewLabOrders = "Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
// static String getAiOverViewLabOrder = "Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
@ -806,7 +837,8 @@ var GET_CUSTOMER_INFO = "VerifyCustomer";
//Pharmacy
var GET_PHARMACY_CATEGORISE = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_PHARMACY_CATEGORISE =
'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=0';
var GET_OFFERS_CATEGORISE = 'discountcategories';
var GET_OFFERS_PRODUCTS = 'offerproducts/';
var GET_CATEGORISE_PARENT = 'categories?fields=id,name,namen,description,image,localized_names,display_order,parent_category_id,is_leaf&parent_id=';
@ -834,7 +866,7 @@ var FILTERED_PRODUCTS = 'products?categoryids=';
var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoctors";
// var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments";
var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC ='Services/Patients.svc/REST/GetAllInvoices';
var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = 'Services/Patients.svc/REST/GetAllInvoices';
var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo";
var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental";

@ -17,6 +17,7 @@ abstract class SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
required String userName,
required String password,
String? fileNo,
});
Future<Either<Failure, GenericApiModel<BodySymptomResponseModel>>> getBodySymptomsByName({
@ -70,8 +71,17 @@ class SymptomsCheckerRepoImp implements SymptomsCheckerRepo {
Future<Either<Failure, GenericApiModel<SymptomsUserDetailsResponseModel>>> getUserDetails({
required String userName,
required String password,
String? fileNo,
}) async {
Map<String, dynamic> body = {"userName": userName, "password": password};
Map<String, dynamic> body = {
"userName": userName,
"password": password,
};
// Add fileNo only if provided (user is logged in)
if (fileNo != null && fileNo.isNotEmpty) {
body["fileNo"] = fileNo;
}
try {
GenericApiModel<SymptomsUserDetailsResponseModel>? apiResponse;

@ -76,6 +76,10 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
final List<Map<String, String>> _triageEvidenceList = []; // Store triage evidence with proper format
int _triageQuestionCount = 0; // Track number of triage questions answered
// For type=1 questions: single selection across all items
String? _selectedSingleItemId; // Store which item was selected
int? _selectedSingleChoiceIndex; // Store which choice was selected
// Selected risk factors tracking
final Set<String> _selectedRiskFactorIds = {};
@ -170,12 +174,35 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
return _selectedTriageChoicesByItemId[itemId];
}
/// Check if current question type is single selection (type=1)
bool get isTriageQuestionSingleSelection => currentTriageQuestion?.type == 1;
/// Check if current question type is multi-item selection (type=2)
bool get isTriageQuestionMultiItem => currentTriageQuestion?.type == 2;
/// For type=1 questions: check if a specific item-choice combination is selected
bool isTriageSingleOptionSelected(String itemId, int choiceIndex) {
return _selectedSingleItemId == itemId && _selectedSingleChoiceIndex == choiceIndex;
}
/// Get selected item ID for type=1 questions
String? get selectedSingleItemId => _selectedSingleItemId;
/// Get selected choice index for type=1 questions
int? get selectedSingleChoiceIndex => _selectedSingleChoiceIndex;
/// Check if all items in current question have been answered
bool get areAllTriageItemsAnswered {
if (currentTriageQuestion?.items == null || currentTriageQuestion!.items!.isEmpty) {
return false;
}
// Type 1: Single selection mode - check if any option is selected
if (isTriageQuestionSingleSelection) {
return _selectedSingleItemId != null && _selectedSingleChoiceIndex != null;
}
// Type 2: Multi-item selection mode - check if all items have answers
// Check if we have an answer for each item
for (var item in currentTriageQuestion!.items!) {
if (item.id != null && !_selectedTriageChoicesByItemId.containsKey(item.id)) {
@ -277,7 +304,7 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
}
}
toggleZoomOut(){
toggleZoomOut() {
if (_currentZoomScale > _minZoomScale) {
_currentZoomScale = (_currentZoomScale - _zoomStep).clamp(_minZoomScale, _maxZoomScale);
notifyListeners();
@ -846,7 +873,21 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
/// Select a choice for a specific item (for multi-item questions)
void selectTriageChoiceForItem(String itemId, int choiceIndex) {
_selectedTriageChoicesByItemId[itemId] = choiceIndex;
// Type 1: Single selection mode - only one option can be selected across all items
if (isTriageQuestionSingleSelection) {
// If same option clicked again, deselect it
if (_selectedSingleItemId == itemId && _selectedSingleChoiceIndex == choiceIndex) {
_selectedSingleItemId = null;
_selectedSingleChoiceIndex = null;
} else {
// Select new option, clear previous selection
_selectedSingleItemId = itemId;
_selectedSingleChoiceIndex = choiceIndex;
}
} else {
// Type 2: Multi-item selection mode - each item can have one selected option
_selectedTriageChoicesByItemId[itemId] = choiceIndex;
}
notifyListeners();
}
@ -854,6 +895,8 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
void resetTriageChoice() {
_selectedTriageChoiceIndex = null;
_selectedTriageChoicesByItemId.clear();
_selectedSingleItemId = null;
_selectedSingleChoiceIndex = null;
_triageQuestionCount++; // Increment question count
notifyListeners();
}
@ -1018,12 +1061,17 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
Future<void> getSymptomsUserDetails({
required String userName,
required String password,
String? fileNo,
Function()? onSuccess,
Function(String)? onError,
}) async {
isBodySymptomsLoading = true;
notifyListeners();
final result = await symptomsCheckerRepo.getUserDetails(userName: userName, password: password);
final result = await symptomsCheckerRepo.getUserDetails(
userName: userName,
password: password,
fileNo: fileNo,
);
result.fold(
(failure) async {

@ -1,6 +1,5 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' show NumberFormat;
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
@ -13,8 +12,8 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_vie
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/appointment_calendar.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/widgets/doctor_rating_details.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
@ -56,7 +55,9 @@ class DoctorProfilePage extends StatelessWidget {
doctorID: viewModel.doctorsProfileResponseModel.doctorID ?? 0,
isActive: viewModel.isFavouriteDoctor,
onSuccess: (response) {
Utils.showToast(viewModel.isFavouriteDoctor ? LocaleKeys.doctorAddedToFavourite.tr(context: context) : LocaleKeys.doctorRemovedFromFavourite.tr(context: context));
Utils.showToast(viewModel.isFavouriteDoctor
? LocaleKeys.doctorAddedToFavourite.tr(context: context)
: LocaleKeys.doctorRemovedFromFavourite.tr(context: context));
// Successfully added/removed favorite - refresh the favorites list
getIt.get<MyAppointmentsViewModel>().refreshFavouriteDoctors();
},
@ -75,7 +76,7 @@ class DoctorProfilePage extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// SizedBox(height: 24.h),
isFoldable ? SizedBox(height: 24.h) : SizedBox.shrink(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -87,18 +88,21 @@ class DoctorProfilePage extends StatelessWidget {
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100),
).circle(100.r),
SizedBox(width: 8.h),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 220.h,
child: ("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
.toString()
.toText24(isBold: true),
width: isFoldable ? 250.w : 220.w,
child:
("${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorTitleForProfile} ${bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName}")
.toString()
.toText24(isBold: true),
),
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty ? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first : "")
(bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.isNotEmpty
? bookAppointmentsViewModel.doctorsProfileResponseModel.specialty!.first
: "")
.toString()
.toText18(isBold: true, color: AppColors.primaryRedColor),
],
@ -137,12 +141,16 @@ class DoctorProfilePage extends StatelessWidget {
children: [
Column(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
Utils.buildSvgWithAssets(
icon: AppAssets.doctor_profile_rating_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h),
LocaleKeys.ratings.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate
.toString()
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
bookAppointmentsViewModel.doctorsProfileResponseModel.decimalDoctorRate.toString().toText16(
isBold: true,
color: AppColors.textColor,
isUnderLine: true,
decorationColor: AppColors.textColor,
fontFamily: "Poppins"),
],
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
@ -158,11 +166,18 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(width: 36.w),
Column(
children: [
Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
Utils.buildSvgWithAssets(
icon: AppAssets.doctor_profile_reviews_icon, width: 48.w, height: 48.h, fit: BoxFit.contain, applyThemeColor: false),
SizedBox(height: 16.h),
LocaleKeys.reviews.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor),
NumberFormat.decimalPattern().format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0)
.toText16(isBold: true, color: AppColors.textColor, isUnderLine: true, decorationColor: AppColors.textColor, fontFamily: "Poppins"),
NumberFormat.decimalPattern()
.format(bookAppointmentsViewModel.doctorsProfileResponseModel.noOfPatientsRate ?? 0)
.toText16(
isBold: true,
color: AppColors.textColor,
isUnderLine: true,
decorationColor: AppColors.textColor,
fontFamily: "Poppins"),
],
).onPress(() {
bookAppointmentsViewModel.getDoctorRatingDetails();
@ -182,92 +197,97 @@ class DoctorProfilePage extends StatelessWidget {
SizedBox(height: 16.h),
LocaleKeys.information.tr(context: context).toText14(isBold: true, color: AppColors.textColor),
SizedBox(height: 6.h),
(bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "").trim().toText12(isBold: true, color: AppColors.greyTextColor),
(bookAppointmentsViewModel.doctorsProfileResponseModel.doctorProfileInfo ?? "")
.trim()
.toText12(isBold: true, color: AppColors.greyTextColor),
SizedBox(height: 24.h),
],
).paddingSymmetrical(24.h, 0.h),
),
),
),
isDoctorAllowedToBook ? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true,
),
child: CustomButton(
text: LocaleKeys.viewAvailableAppointments.tr(),
onPressed: () async {
bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName;
bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL;
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL = bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL;
bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription;
bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName;
isDoctorAllowedToBook
? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: true,
),
child: CustomButton(
text: LocaleKeys.viewAvailableAppointments.tr(),
onPressed: () async {
bookAppointmentsViewModel.selectedDoctor.speciality = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.specialityN = bookAppointmentsViewModel.doctorsProfileResponseModel.specialty;
bookAppointmentsViewModel.selectedDoctor.name = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorName;
bookAppointmentsViewModel.selectedDoctor.doctorImageURL = bookAppointmentsViewModel.doctorsProfileResponseModel.doctorImageURL;
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL =
bookAppointmentsViewModel.doctorsProfileResponseModel.nationalityFlagURL;
bookAppointmentsViewModel.selectedDoctor.clinicName = bookAppointmentsViewModel.doctorsProfileResponseModel.clinicDescription;
bookAppointmentsViewModel.selectedDoctor.projectName = bookAppointmentsViewModel.doctorsProfileResponseModel.projectName;
LoaderBottomSheet.showLoader();
bookAppointmentsViewModel.isLiveCareSchedule
? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots(
isBookingForLiveCare: true,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.pickADate.tr(),
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
})
: await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.pickADate.tr() ,
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 16,
isBold: true,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.calendar,
iconColor: Colors.white,
iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h),
) : SizedBox.shrink(),
LoaderBottomSheet.showLoader();
bookAppointmentsViewModel.isLiveCareSchedule
? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots(
isBookingForLiveCare: true,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.pickADate.tr(),
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
})
: await bookAppointmentsViewModel.getDoctorFreeSlots(
isBookingForLiveCare: false,
onSuccess: (dynamic respData) async {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
title: LocaleKeys.pickADate.tr(),
context,
child: AppointmentCalendar(),
isFullScreen: false,
isCloseButtonVisible: true,
callBackFunc: () {},
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
backgroundColor: AppColors.primaryRedColor,
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 16,
isBold: true,
borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h,
icon: AppAssets.calendar,
iconColor: Colors.white,
iconSize: 20.h,
).paddingSymmetrical(24.h, 24.h),
)
: SizedBox.shrink(),
],
),
);

@ -319,9 +319,9 @@ class _AppointmentCalendarState extends State<AppointmentCalendar> {
if (bookAppointmentsViewModel.isWaitingAppointmentAvailable && DateUtils.isSameDay(dateStart, DateTime.now())) {
dayEvents.add(TimeSlot(isoTime: LocaleKeys.waitingAppointment.tr(context: context), start: DateTime.now(), end: DateTime.now(), vidaDate: ""));
}
freeSlots.forEach((v) {
for (var v in freeSlots) {
if (v.start == dateStartObj) dayEvents.add(v);
});
}
selectedButtonIndex = 0;
List<Map<String, dynamic>> timeList = [];
for (var i = 0; i < dayEvents.length; i++) {

@ -1,9 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/select_clinic_page.dart';
@ -19,7 +17,6 @@ import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/ibw.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/ovulation.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/triglycerides.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
@ -27,11 +24,11 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
class HealthCalculatorDetailedPage extends StatefulWidget {
HealthCalculatorsTypeEnum calculatorType;
int? clinicID;
int? calculationID;
final HealthCalculatorsTypeEnum calculatorType;
final int? clinicID;
final int? calculationID;
HealthCalculatorDetailedPage({super.key, required this.calculatorType, this.clinicID, this.calculationID});
const HealthCalculatorDetailedPage({super.key, required this.calculatorType, this.clinicID, this.calculationID});
@override
State<HealthCalculatorDetailedPage> createState() => _HealthCalculatorDetailedPageState();
@ -52,8 +49,8 @@ class _HealthCalculatorDetailedPageState extends State<HealthCalculatorDetailedP
widget.calculatorType == HealthCalculatorsTypeEnum.triglycerides
? SizedBox()
: Container(
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, customBorder: BorderRadius.only(topLeft: Radius.circular(24.r), topRight: Radius.circular(24.r))),
padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.h),
child: CustomButton(
text: widget.calculatorType == HealthCalculatorsTypeEnum.bloodSugar ||
@ -131,36 +128,6 @@ class _HealthCalculatorDetailedPageState extends State<HealthCalculatorDetailedP
: {'result': provider.triglyceridesResult ?? result, 'clinicId': widget.clinicID, 'calculationID': widget.calculationID};
break;
}
// switch (widget.calculatorType) {
// case HealthCalculatorsTypeEnum.bmi:
// calculatedResult = provider.bmiResultMap ?? result;
// break;
// case HealthCalculatorsTypeEnum.calories:
// case HealthCalculatorsTypeEnum.bmr:
// calculatedResult = provider.caloriesResultMap ?? result;
// break;
// case HealthCalculatorsTypeEnum.idealBodyWeight:
// calculatedResult = provider.ibwResultMap ?? result;
// break;
// case HealthCalculatorsTypeEnum.bodyFat:
// calculatedResult = provider.bodyFatResultMap ?? result;
// break;
// case HealthCalculatorsTypeEnum.crabsProteinFat:
// calculatedResult = provider.macrosResultMap ?? result;
// break;
// case HealthCalculatorsTypeEnum.ovulation:
// calculatedResult = provider.ovulationResult ?? result;
// break;
// case HealthCalculatorsTypeEnum.deliveryDueDate:
// calculatedResult = provider.deliveryResult ?? result;
// break;
// case HealthCalculatorsTypeEnum.bloodSugar:
// calculatedResult = provider.bloodSugarResult ?? result;
// case HealthCalculatorsTypeEnum.bloodCholesterol:
// calculatedResult = provider.bloodCholesterolResult ?? result;
// case HealthCalculatorsTypeEnum.triglycerides:
// calculatedResult = provider.triglyceridesResult ?? result;
// }
},
).paddingSymmetrical(20.w, 24.h),
);
@ -172,58 +139,69 @@ class _HealthCalculatorDetailedPageState extends State<HealthCalculatorDetailedP
switch (widget.calculatorType) {
case HealthCalculatorsTypeEnum.bmi:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: BMIWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.calories:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: CaloriesWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.bmr:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: BMRWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.idealBodyWeight:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: IdealBodyWeightWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.bodyFat:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: BodyFatWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.crabsProteinFat:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: CrabsWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.ovulation:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: OvulationWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.deliveryDueDate:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: DeliveryDueDWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.bloodSugar:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: BloodSugarWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.bloodCholesterol:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: BloodCholesterolWidget(onChange: onCalculate),
);
case HealthCalculatorsTypeEnum.triglycerides:
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
decoration:
RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, customBorder: BorderRadius.all(Radius.circular(24.r))),
child: TriglyceridesWidget(onChange: onCalculate),
);
}

@ -11,16 +11,15 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_detailed_page.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/widgets/health_card.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/expandable_list_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
class HealthCalculatorsPage extends StatefulWidget {
HealthCalConEnum type;
final HealthCalConEnum type;
HealthCalculatorsPage({super.key, required this.type});
const HealthCalculatorsPage({super.key, required this.type});
@override
State<HealthCalculatorsPage> createState() => _HealthCalculatorsPageState();
@ -34,9 +33,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
@override
Widget build(BuildContext context) {
DialogService dialogService = getIt.get<DialogService>();
return CollapsingListView(
isLeading: Navigator.canPop(context),
isLeading: Navigator.canPop(context),
title: widget.type == HealthCalConEnum.calculator ? LocaleKeys.healthCalculators.tr(context: context) : LocaleKeys.healthConverters.tr(),
child: widget.type == HealthCalConEnum.calculator
? CustomExpandableList(
@ -58,7 +56,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
),
],
theme: ExpandableListTheme.custom(
defaultTrailingIcon: Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor),
defaultTrailingIcon:
Utils.buildSvgWithAssets(icon: AppAssets.arrow_down, height: 22.h, width: 22.w, iconColor: AppColors.textColor),
),
).paddingSymmetrical(16.w, 0.0)
// ? Column(
@ -129,7 +128,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.bloodSugar, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
Utils.buildSvgWithAssets(
icon: AppAssets.bloodSugar, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
SizedBox(width: 12.w),
Flexible(
child: Column(
@ -149,7 +149,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
),
],
).paddingAll(16.w))
@ -166,7 +167,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.bloodCholestrol, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
Utils.buildSvgWithAssets(
icon: AppAssets.bloodCholestrol, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
SizedBox(width: 12.w),
Flexible(
child: Column(
@ -181,7 +183,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
SizedBox(width: 12.w),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
),
],
).paddingAll(16.w))
@ -198,7 +201,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.triglycerides, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
Utils.buildSvgWithAssets(
icon: AppAssets.triglycerides, height: 40.h, width: 40.w, fit: BoxFit.none, applyThemeColor: false),
SizedBox(width: 12.w),
Flexible(
child: Column(
@ -213,7 +217,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
SizedBox(width: 12.w),
Transform.flip(
flipX: getIt.get<AppState>().isArabic(),
child: Utils.buildSvgWithAssets(icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
child: Utils.buildSvgWithAssets(
icon: AppAssets.arrowRight, width: 24.w, height: 24.h, fit: BoxFit.contain, iconColor: AppColors.textColor),
),
],
).paddingAll(16.w))
@ -247,7 +252,8 @@ class _HealthCalculatorsPageState extends State<HealthCalculatorsPage> {
page: HealthCalculatorDetailedPage(
calculatorType: type == HealthCalculatorEnum.general ? generalHealthServices[index].type : womenHealthServices[index].type,
clinicID: type == HealthCalculatorEnum.general ? generalHealthServices[index].clinicID : womenHealthServices[index].clinicID,
calculationID: type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID,
calculationID:
type == HealthCalculatorEnum.general ? generalHealthServices[index].calculationID : womenHealthServices[index].calculationID,
),
),
);
@ -341,5 +347,14 @@ class HealthComponentModel {
int? clinicID;
int? calculationID;
HealthComponentModel({required this.title, this.subTitle, required this.icon, this.iconColor, this.bgColor, this.textColor, required this.type, this.clinicID, this.calculationID});
HealthComponentModel(
{required this.title,
this.subTitle,
required this.icon,
this.iconColor,
this.bgColor,
this.textColor,
required this.type,
this.clinicID,
this.calculationID});
}

@ -1,14 +1,14 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
class BloodCholesterolWidget extends StatefulWidget {
final Function(dynamic result)? onChange;
@ -107,7 +107,7 @@ class _BloodCholesterolWidgetState extends State<BloodCholesterolWidget> {
],
),
_buildInputField(
label:LocaleKeys.mmol.tr(),
label: LocaleKeys.mmol.tr(),
hint: "3.1",
controller: _mmolController,
focusNode: _mmolFocus,
@ -123,7 +123,7 @@ class _BloodCholesterolWidgetState extends State<BloodCholesterolWidget> {
Utils.buildSvgWithAssets(icon: AppAssets.globe, width: 18.w, height: 18.w),
SizedBox(width: 12.w),
Expanded(
child:LocaleKeys.convertBloodcholesterolInfo.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
child: LocaleKeys.convertBloodcholesterolInfo.tr(context: context).toText12(isBold: true, color: AppColors.inputLabelTextColor),
),
],
).paddingSymmetrical(0.w, 16.w),
@ -149,29 +149,26 @@ class _BloodCholesterolWidgetState extends State<BloodCholesterolWidget> {
isBold: true,
color: AppColors.inputLabelTextColor,
),
SizedBox(
height: 40.h,
child: TextField(
controller: controller,
focusNode: focusNode,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
maxLines: 1,
onChanged: onChanged,
cursorHeight: 35.h,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isCollapsed: true,
hintText: hint,
hintStyle: const TextStyle(color: Colors.grey),
),
style: TextStyle(
fontSize: 32.f,
fontWeight: FontWeight.bold,
color: Colors.black87,
height: 1.h,
),
TextField(
controller: controller,
focusNode: focusNode,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
maxLines: 1,
onChanged: onChanged,
cursorHeight: 35.h,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isCollapsed: true,
hintText: hint,
hintStyle: const TextStyle(color: Colors.grey),
),
style: TextStyle(
fontSize: 32.f,
fontWeight: FontWeight.bold,
color: Colors.black87,
height: 1.h,
),
),
],

@ -1,14 +1,14 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:provider/provider.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/health_calculators_and_converts/health_calculator_view_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';
class TriglyceridesWidget extends StatefulWidget {
final Function(dynamic result)? onChange;
@ -91,7 +91,6 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
provider.onTriglyceridesMgdlChanged(value);
},
).paddingOnly(top: 16.h),
Row(
children: [
const Expanded(
@ -111,7 +110,6 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
}),
],
),
_buildInputField(
label: LocaleKeys.mmol,
hint: "1.7",
@ -122,9 +120,7 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
provider.onTriglyceridesMmolChanged(value);
},
).paddingOnly(bottom: 16.h),
const Divider(height: 1, color: Color(0xFFEEEEEE)),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -135,12 +131,10 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
),
SizedBox(width: 12.w),
Expanded(
child:
LocaleKeys.triglycerideInfo.tr()
.toText12(
isBold: true,
color: AppColors.inputLabelTextColor,
),
child: LocaleKeys.triglycerideInfo.tr().toText12(
isBold: true,
color: AppColors.inputLabelTextColor,
),
),
],
).paddingSymmetrical(0.w, 16.w),
@ -165,27 +159,23 @@ class _TriglyceridesWidgetState extends State<TriglyceridesWidget> {
isBold: true,
color: AppColors.inputLabelTextColor,
),
SizedBox(
height: 40.h,
child: TextField(
controller: controller,
focusNode: focusNode,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
onChanged: onChanged,
cursorHeight: 35.h,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isCollapsed: true,
hintText: hint,
hintStyle: const TextStyle(color: Colors.grey),
),
style: TextStyle(
fontSize: 32.f,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
TextField(
controller: controller,
focusNode: focusNode,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: onChanged,
cursorHeight: 35.h,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
isCollapsed: true,
hintText: hint,
hintStyle: const TextStyle(color: Colors.grey),
),
style: TextStyle(
fontSize: 32.f,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
],

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_export.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
@ -46,13 +47,13 @@ class _OrganSelectorPageState extends State<OrganSelectorPage> {
Future<void> _checkAndShowTutorial() async {
// final hasSeenTutorial = cacheService.getBool(key: CacheConst.organSelectorTutorialShown) ?? false;
// if (!hasSeenTutorial) {
// Show tutorial after a short delay to ensure the screen is fully built
await Future.delayed(const Duration(milliseconds: 500));
if (mounted) {
setState(() {
_showTutorial = true;
});
}
// Show tutorial after a short delay to ensure the screen is fully built
await Future.delayed(const Duration(milliseconds: 500));
if (mounted) {
setState(() {
_showTutorial = true;
});
}
// }
}
@ -74,12 +75,17 @@ class _OrganSelectorPageState extends State<OrganSelectorPage> {
loadingText: LocaleKeys.pleaseWait.tr(context: context),
);
final String userName = 'guest_user';
final String password = '123456';
// Get fileNo if user is logged in
String? fileNo;
if (_appState.isAuthenticated) {
final user = _appState.getAuthenticatedUser();
fileNo = user?.patientId.toString();
}
await viewModel.getSymptomsUserDetails(
userName: userName,
password: password,
userName: ApiConsts.symptomsCheckerUsername,
password: ApiConsts.symptomsCheckerPassword,
fileNo: fileNo,
onSuccess: () {
LoaderBottomSheet.hideLoader();
context.navigateWithName(AppRoutes.symptomsSelectorPage);

@ -175,20 +175,44 @@ class _TriagePageState extends State<TriagePage> {
return;
}
// Collect all evidence from all items
for (var item in currentQuestion.items!) {
final itemId = item.id ?? "";
if (itemId.isEmpty) continue;
final selectedChoiceIndex = viewModel.getTriageChoiceForItem(itemId);
if (selectedChoiceIndex == null) continue;
if (item.choices != null && selectedChoiceIndex < item.choices!.length) {
final selectedChoice = item.choices![selectedChoiceIndex];
final choiceId = selectedChoice.id ?? "";
if (choiceId.isNotEmpty) {
viewModel.addTriageEvidence(itemId, choiceId);
// Collect evidence based on question type
if (viewModel.isTriageQuestionSingleSelection) {
// Type 1: Single selection - only one evidence entry
final selectedItemId = viewModel.selectedSingleItemId;
final selectedChoiceIndex = viewModel.selectedSingleChoiceIndex;
if (selectedItemId != null && selectedChoiceIndex != null) {
// Find the item and choice
for (var item in currentQuestion.items!) {
if (item.id == selectedItemId) {
if (item.choices != null && selectedChoiceIndex < item.choices!.length) {
final selectedChoice = item.choices![selectedChoiceIndex];
final choiceId = selectedChoice.id ?? "";
if (choiceId.isNotEmpty) {
viewModel.addTriageEvidence(selectedItemId, choiceId);
}
}
break;
}
}
}
} else {
// Type 2: Multi-item selection - collect evidence from all items
for (var item in currentQuestion.items!) {
final itemId = item.id ?? "";
if (itemId.isEmpty) continue;
final selectedChoiceIndex = viewModel.getTriageChoiceForItem(itemId);
if (selectedChoiceIndex == null) continue;
if (item.choices != null && selectedChoiceIndex < item.choices!.length) {
final selectedChoice = item.choices![selectedChoiceIndex];
final choiceId = selectedChoice.id ?? "";
if (choiceId.isNotEmpty) {
viewModel.addTriageEvidence(itemId, choiceId);
}
}
}
}
@ -390,7 +414,10 @@ class _TriagePageState extends State<TriagePage> {
SizedBox(height: 8.h),
// Choices for this item
...List.generate(choices.length, (choiceIndex) {
bool selected = viewModel.getTriageChoiceForItem(itemId) == choiceIndex;
// Check selection based on question type
bool selected = viewModel.isTriageQuestionSingleSelection
? viewModel.isTriageSingleOptionSelected(itemId, choiceIndex)
: viewModel.getTriageChoiceForItem(itemId) == choiceIndex;
return _buildOptionItem(itemId, choiceIndex, selected, choices[choiceIndex].label ?? "");
}),
@ -468,18 +495,12 @@ class _TriagePageState extends State<TriagePage> {
text: TextSpan(
text: "${LocaleKeys.possibleSymptom.tr(context: context)} ",
style: TextStyle(
color: AppColors.greyTextColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'),
color: AppColors.greyTextColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'),
children: [
TextSpan(
text: suggestedCondition,
style: TextStyle(
color: AppColors.textColor,
fontWeight: FontWeight.w600,
fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'),
color: AppColors.textColor, fontWeight: FontWeight.w600, fontSize: 14.f, fontFamily: isArabic ? 'CairoArabic' : 'Poppins'),
),
],
),

@ -53,9 +53,10 @@ class HeightSelectionPage extends StatelessWidget {
child: Text(
'CM',
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 14.f,
color: viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), fontFamily: "Poppins"),
fontWeight: FontWeight.w700,
fontSize: 14.f,
color: viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6),
fontFamily: "Poppins"),
),
),
),
@ -74,9 +75,10 @@ class HeightSelectionPage extends StatelessWidget {
child: Text(
'FT',
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 14.f,
color: !viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6), fontFamily: "Poppins"),
fontWeight: FontWeight.w700,
fontSize: 14.f,
color: !viewModel.isHeightCm ? AppColors.primaryRedColor : AppColors.textColor.withValues(alpha: 0.6),
fontFamily: "Poppins"),
),
),
),
@ -128,10 +130,7 @@ class HeightSelectionPage extends StatelessWidget {
TextSpan(
text:
viewModel.isHeightCm ? viewModel.selectedHeight?.round().toString() : viewModel.selectedHeight?.toStringAsFixed(1),
style: TextStyle(
fontSize: 90.f,
color: AppColors.textColor,
height: 1, fontFamily: "Poppins"),
style: TextStyle(fontSize: 90.f, color: AppColors.textColor, height: 1, fontFamily: "Poppins"),
),
TextSpan(
text: viewModel.isHeightCm ? 'cm' : 'ft',
@ -142,7 +141,7 @@ class HeightSelectionPage extends StatelessWidget {
),
],
),
).paddingOnly(bottom: 100.h, left: 20.w);
).paddingOnly(bottom: 100.h, left: isFoldable ? 40.w : 20.w);
},
),
),

@ -131,12 +131,11 @@ class _HeightScaleState extends State<HeightScale> {
child: Text(
widget.isCm ? height.round().toString() : height.toStringAsFixed(1),
style: TextStyle(
fontSize: 11.f,
color: AppColors.greyTextColor,
fontSize: 11.f,
color: AppColors.greyTextColor,
fontWeight: FontWeight.w600,
height: 1,
fontFamily: "Poppins"
),
height: isFoldable ? 0.5 : 1,
fontFamily: "Poppins"),
textAlign: TextAlign.right,
),
)

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
@ -24,8 +25,6 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:provider/provider.dart';
import 'dart:ui' as ui;
class AncillaryOrderDetailsList extends StatefulWidget {
final int appointmentNoVida;
final int orderNo;
@ -653,13 +652,15 @@ class _AncillaryOrderDetailsListState extends State<AncillaryOrderDetailsList> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 200.h,
width: isFoldable ? 220.w : 200.w,
child: Utils.getPaymentMethods(),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.getPaymentAmountWithSymbol(NumberFormat.decimalPattern().format(_getTotalAmount()).toText24(isBold: true, isEnglishOnly: true), AppColors.blackColor, 17, isSaudiCurrency: true),
Utils.getPaymentAmountWithSymbol(
NumberFormat.decimalPattern().format(_getTotalAmount()).toText24(isBold: true, isEnglishOnly: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
),
],
@ -695,40 +696,5 @@ class _AncillaryOrderDetailsListState extends State<AncillaryOrderDetailsList> {
],
).paddingOnly(left: 16.h, top: 24.h, right: 16.h, bottom: 0.h),
);
// Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// SizedBox(height: 16.h),
// _buildSummarySection(orderData),
// SizedBox(height: 16.h),
// CustomButton(
// borderWidth: 0,
// backgroundColor: AppColors.infoLightColor,
// text: "Proceed to Payment".needTranslation,
// onPressed: () {
// // Navigate to payment page with selected procedures
// Navigator.of(context).push(
// CustomPageRoute(
// page: AncillaryOrderPaymentPage(
// appointmentNoVida: widget.appointmentNoVida,
// orderNo: widget.orderNo,
// projectID: widget.projectID,
// selectedProcedures: selectedProcedures,
// totalAmount: _getTotalAmount(),
// appointmentDate: orderData.appointmentDate,
// ),
// ),
// );
// },
// isDisabled: !isButtonEnabled,
// textColor: AppColors.whiteColor,
// borderRadius: 12.r,
// borderColor: Colors.transparent,
// padding: EdgeInsets.symmetric(vertical: 16.h),
// ),
// SizedBox(height: 22.h),
// ],
// ).paddingSymmetrical(24.w, 0);
}
}

@ -115,7 +115,8 @@ class CollapsingListView extends StatelessWidget {
margin: EdgeInsets.fromLTRB(24.w, 0, 24.w, 0),
child: Transform.flip(
flipX: appState.isArabic(),
child: Utils.buildSvgWithAssets(icon: isClose ? AppAssets.close_bottom_nav_trans : AppAssets.arrow_back_new, width: 24.h, height: 24.h),
child: Utils.buildSvgWithAssets(
icon: isClose ? AppAssets.close_bottom_nav_trans : AppAssets.arrow_back_new, width: 24.h, height: 24.h),
),
).onPress(() {
if (leadingCallback != null) {
@ -288,7 +289,8 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
return Container(
// height: (widget.preferredSize.height - _fontSize / 2).h,
height: 56.h,
alignment: isRtl ? (widget.showBack ? Alignment.topRight : Alignment.centerRight) : (widget.showBack ? Alignment.topLeft : Alignment.centerLeft),
alignment:
isRtl ? (widget.showBack ? Alignment.topRight : Alignment.centerRight) : (widget.showBack ? Alignment.topLeft : Alignment.centerLeft),
padding: EdgeInsets.fromLTRB(24.w, 0, 24.w, 0),
child: Row(
spacing: 4.h,
@ -304,19 +306,38 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
),
).expanded,
...[
if (widget.logout != null) actionButton(context, t, title: LocaleKeys.logout.tr(context: context), icon: AppAssets.logout).onPress(widget.logout!),
if (widget.report != null) actionButton(context, t, title: LocaleKeys.feedback.tr(context: context), icon: AppAssets.report_icon).onPress(widget.report!),
if (widget.history != null) actionButton(context, t, title: LocaleKeys.history.tr(context: context), icon: AppAssets.insurance_history_icon).onPress(widget.history!),
if (widget.instructions != null) actionButton(context, t, title: LocaleKeys.instructions.tr(context: context), icon: AppAssets.requests).onPress(widget.instructions!),
if (widget.requests != null) actionButton(context, t, title: LocaleKeys.requests.tr(context: context), icon: AppAssets.insurance_history_icon).onPress(widget.requests!),
if (widget.sendEmail != null) actionButton(context, t, title: LocaleKeys.sendEmail.tr(context: context), icon: AppAssets.email).onPress(widget.sendEmail!),
if (widget.doctorResponse != null) actionButton(context, t, title: LocaleKeys.doctorResponses.tr(context: context), icon: AppAssets.doctorResponseIcon).onPress(widget.doctorResponse!),
if (widget.logout != null)
actionButton(context, t, title: LocaleKeys.logout.tr(context: context), icon: AppAssets.logout).onPress(widget.logout!),
if (widget.report != null)
actionButton(context, t, title: LocaleKeys.feedback.tr(context: context), icon: AppAssets.report_icon).onPress(widget.report!),
if (widget.history != null)
actionButton(context, t, title: LocaleKeys.history.tr(context: context), icon: AppAssets.insurance_history_icon)
.onPress(widget.history!),
if (widget.instructions != null)
actionButton(context, t, title: LocaleKeys.instructions.tr(context: context), icon: AppAssets.requests).onPress(widget.instructions!),
if (widget.requests != null)
actionButton(context, t, title: LocaleKeys.requests.tr(context: context), icon: AppAssets.insurance_history_icon)
.onPress(widget.requests!),
if (widget.sendEmail != null)
actionButton(context, t, title: LocaleKeys.sendEmail.tr(context: context), icon: AppAssets.email).onPress(widget.sendEmail!),
if (widget.doctorResponse != null)
actionButton(context, t, title: LocaleKeys.doctorResponses.tr(context: context), icon: AppAssets.doctorResponseIcon)
.onPress(widget.doctorResponse!),
if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!),
if (widget.aiOverview != null) actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true).onPress(widget.aiOverview!),
if (widget.downloadReport != null) actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download).onPress(widget.downloadReport!),
if (widget.viewImage != null) actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download).onPress(widget.viewImage!),
if (widget.location != null) actionButton(context, t, title: LocaleKeys.sortByLocation.tr(context: context), icon: AppAssets.location).onPress(widget.location!),
if (widget.downloadInvoice != null) actionButton(context, t, title: LocaleKeys.downloadInvoice.tr(context: context), icon: AppAssets.download).onPress(widget.downloadInvoice!),
if (widget.aiOverview != null)
actionButton(context, t, title: LocaleKeys.aiOverView.tr(context: context), icon: AppAssets.aiOverView, isAiButton: true)
.onPress(widget.aiOverview!),
if (widget.downloadReport != null)
actionButton(context, t, title: LocaleKeys.downloadReport.tr(context: context), icon: AppAssets.download)
.onPress(widget.downloadReport!),
if (widget.viewImage != null)
actionButton(context, t, title: LocaleKeys.viewRadiologyImage.tr(context: context), icon: AppAssets.download)
.onPress(widget.viewImage!),
if (widget.location != null)
actionButton(context, t, title: LocaleKeys.sortByLocation.tr(context: context), icon: AppAssets.location).onPress(widget.location!),
if (widget.downloadInvoice != null)
actionButton(context, t, title: LocaleKeys.downloadInvoice.tr(context: context), icon: AppAssets.download)
.onPress(widget.downloadInvoice!),
if (widget.trailing != null) widget.trailing!,
]
],
@ -330,9 +351,10 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
duration: Duration(milliseconds: 150),
child: Center(
child: Container(
height: 40.h,
height: isFoldable ? 50.h : 40.h,
padding: EdgeInsets.all(8.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 8.r, side: BorderSide(width: 1, color: AppColors.borderGrayColor)),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, borderRadius: 8.r, side: BorderSide(width: 1, color: AppColors.borderGrayColor)),
child: ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => AppColors.aiLinearGradient.createShader(bounds),
@ -365,7 +387,7 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
: AnimatedSize(
duration: Duration(milliseconds: 150),
child: Container(
height: 40.h,
height: isFoldable ? 50.h : 40.h,
padding: EdgeInsets.all(8.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.secondaryLightRedColor,

Loading…
Cancel
Save