Merge branch 'haroon_dev' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into haroon_dev

# Conflicts:
#	lib/features/book_appointments/book_appointments_view_model.dart
pull/181/head
haroon amjad 2 weeks ago
commit 95b65ed8a5

@ -683,7 +683,7 @@ const DASHBOARD = 'Services/Patients.svc/REST/PatientDashboard';
class ApiConsts { class ApiConsts {
static const maxSmallScreen = 660; static const maxSmallScreen = 660;
static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod;
// static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT

@ -110,7 +110,7 @@ class DateUtil {
} }
static String formatDateToTime(DateTime date) { static String formatDateToTime(DateTime date) {
return DateFormat('hh:mm a').format(date); return DateFormat('hh:mm a', "en-US").format(date);
} }
static String yearMonthDay(DateTime dateTime) { static String yearMonthDay(DateTime dateTime) {
@ -487,7 +487,9 @@ class DateUtil {
} }
static String getFormattedDate(DateTime dateTime, String formattedString) { static String getFormattedDate(DateTime dateTime, String formattedString) {
return DateFormat(formattedString).format(dateTime); String formattedDate = DateFormat(formattedString, "en-US").format(dateTime);
print(formattedDate);
return formattedDate;
} }
static convertISODateToJsonDate(String isoDate) { static convertISODateToJsonDate(String isoDate) {

@ -210,8 +210,8 @@ class RequestUtils {
List<String> names = fullName != null ? fullName.split(" ") : []; List<String> names = fullName != null ? fullName.split(" ") : [];
var dob = appState.getUserRegistrationPayload.dob; var dob = appState.getUserRegistrationPayload.dob;
final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy'); final DateFormat dateFormat1 = DateFormat('MM/dd/yyyy', "en-US");
final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy'); final DateFormat dateFormat2 = DateFormat('dd/MM/yyyy', "en-US");
DateTime gregorianDate = dateFormat2.parse(dob!); DateTime gregorianDate = dateFormat2.parse(dob!);
HijriGregDate hijriDate = HijriGregConverter.gregorianToHijri(gregorianDate); HijriGregDate hijriDate = HijriGregConverter.gregorianToHijri(gregorianDate);
String? date = "${hijriDate.day}/${hijriDate.month}/${hijriDate.year}"; String? date = "${hijriDate.day}/${hijriDate.month}/${hijriDate.year}";

@ -128,7 +128,7 @@ class Utils {
static String convertStringToDateTime(String dateTimeString) { static String convertStringToDateTime(String dateTimeString) {
String timeString = dateTimeString; String timeString = dateTimeString;
// Parse the time string using DateFormat // Parse the time string using DateFormat
DateFormat format = DateFormat.Hms(); // 'Hms' = 'HH:mm:ss' DateFormat format = DateFormat.Hms(["en-US"]); // 'Hms' = 'HH:mm:ss'
DateTime time = format.parse(timeString); DateTime time = format.parse(timeString);
DateTime now = DateTime.now(); DateTime now = DateTime.now();
@ -987,4 +987,17 @@ class Utils {
return isAllowed; return isAllowed;
} }
static String toEnglishNumbers(String input) {
const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
const persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
String result = input;
for (int i = 0; i < 10; i++) {
result = result.replaceAll(arabic[i], english[i]);
result = result.replaceAll(persian[i], english[i]);
}
return result;
}
} }

@ -23,8 +23,7 @@ extension CapExtension on String {
extension EmailValidator on String { extension EmailValidator on String {
Widget get toWidget => Text(this); Widget get toWidget => Text(this);
Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Widget toText8({Color? color, FontWeight? fontWeight, bool isBold = false, int? maxlines, FontStyle? fontStyle, TextOverflow? textOverflow}) => Text(
Text(
this, this,
maxLines: maxlines, maxLines: maxlines,
overflow: textOverflow, overflow: textOverflow,
@ -38,7 +37,8 @@ extension EmailValidator on String {
); );
Widget toText10( Widget toText10(
{Color? color, {bool isEnglishOnly = false,
Color? color,
FontWeight? weight, FontWeight? weight,
bool isBold = false, bool isBold = false,
bool isUnderLine = false, bool isUnderLine = false,
@ -59,19 +59,20 @@ extension EmailValidator on String {
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,
letterSpacing: letterSpacing, letterSpacing: letterSpacing,
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
Widget toText9( Widget toText9(
{Color? color, {Color? color,
FontWeight? weight, FontWeight? weight,
bool isBold = false, bool isBold = false,
bool isUnderLine = false, bool isUnderLine = false,
bool isCenter = false, bool isCenter = false,
int? maxlines, int? maxlines,
FontStyle? fontStyle, FontStyle? fontStyle,
TextOverflow? textOverflow, TextOverflow? textOverflow,
double letterSpacing = 0}) => double letterSpacing = 0}) =>
Text( Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
@ -87,15 +88,7 @@ extension EmailValidator on String {
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
Widget toText11( Widget toText11({Color? color, FontWeight? weight, bool isUnderLine = false, bool isCenter = false, bool isBold = false, int maxLine = 0, double letterSpacing = 0}) => Text(
{Color? color,
FontWeight? weight,
bool isUnderLine = false,
bool isCenter = false,
bool isBold = false,
int maxLine = 0,
double letterSpacing = 0}) =>
Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null, maxLines: (maxLine > 0) ? maxLine : null,
@ -110,7 +103,7 @@ extension EmailValidator on String {
); );
Widget toText12( Widget toText12(
{Color? color, {bool isEnglishOnly = false, Color? color,
bool isUnderLine = false, bool isUnderLine = false,
TextAlign textAlignment = TextAlign.start, TextAlign textAlignment = TextAlign.start,
bool isBold = false, bool isBold = false,
@ -131,6 +124,7 @@ extension EmailValidator on String {
height: height, height: height,
decorationColor: isUnderLine ? AppColors.blackColor : null, decorationColor: isUnderLine ? AppColors.blackColor : null,
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
), ),
); );
@ -176,15 +170,7 @@ extension EmailValidator on String {
), ),
); );
Widget toText13( Widget toText13({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0, FontWeight? weight, double? letterSpacing = 0}) => Text(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
int maxLine = 0,
FontWeight? weight,
double? letterSpacing = 0}) =>
Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
maxLines: (maxLine > 0) ? maxLine : null, maxLines: (maxLine > 0) ? maxLine : null,
@ -197,6 +183,7 @@ extension EmailValidator on String {
); );
Widget toText14({ Widget toText14({
bool isEnglishOnly = false,
Color? color, Color? color,
bool isUnderLine = false, bool isUnderLine = false,
bool isBold = false, bool isBold = false,
@ -219,18 +206,11 @@ extension EmailValidator on String {
height: height, height: height,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
decoration: isUnderLine ? TextDecoration.underline : null, decoration: isUnderLine ? TextDecoration.underline : null,
fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins',
decorationColor: color ?? AppColors.blackColor), decorationColor: color ?? AppColors.blackColor),
); );
Widget toText15( Widget toText15({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, FontWeight? weight, int? maxlines, double? letterSpacing = -1}) => Text(
{Color? color,
bool isUnderLine = false,
bool isBold = false,
bool isCenter = false,
FontWeight? weight,
int? maxlines,
double? letterSpacing = -1}) =>
Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
maxLines: maxlines, maxLines: maxlines,
@ -258,6 +238,7 @@ extension EmailValidator on String {
this, this,
maxLines: maxlines, maxLines: maxlines,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
// locale: Locale('en', 'US'),
style: TextStyle( style: TextStyle(
color: color ?? AppColors.blackColor, color: color ?? AppColors.blackColor,
fontSize: 16.f, fontSize: 16.f,
@ -269,11 +250,10 @@ extension EmailValidator on String {
decorationColor: decorationColor), decorationColor: decorationColor),
); );
Widget toText17({Color? color, bool isBold = false, bool isCenter = false}) => Text( Widget toText17({bool isEnglishOnly = false, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
color: color ?? AppColors.blackColor, fontSize: 17.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
); );
Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text( Widget toText18({Color? color, FontWeight? weight, bool isBold = false, bool isCenter = false, int? maxlines, TextOverflow? textOverflow}) => Text(
@ -281,17 +261,12 @@ extension EmailValidator on String {
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
this, this,
overflow: textOverflow, overflow: textOverflow,
style: TextStyle( style: TextStyle(fontSize: 18.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
fontSize: 18.f,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4),
); );
Widget toText19({Color? color, bool isBold = false}) => Text( Widget toText19({Color? color, bool isBold = false}) => Text(
this, this,
style: TextStyle( style: TextStyle(fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
fontSize: 19.f, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: color ?? AppColors.blackColor, letterSpacing: -0.4),
); );
Widget toText20({ Widget toText20({
@ -301,86 +276,51 @@ extension EmailValidator on String {
}) => }) =>
Text( Text(
this, this,
style: TextStyle( style: TextStyle(fontSize: 20.f, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal), color: color ?? AppColors.blackColor, letterSpacing: -0.4),
fontSize: 20.f,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal),
color: color ?? AppColors.blackColor,
letterSpacing: -0.4),
); );
Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text( Widget toText21({Color? color, bool isBold = false, FontWeight? weight, int? maxlines}) => Text(
this, this,
maxLines: maxlines, maxLines: maxlines,
style: TextStyle( style: TextStyle(color: color ?? AppColors.blackColor, fontSize: 21.f, letterSpacing: -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
color: color ?? AppColors.blackColor,
fontSize: 21.f,
letterSpacing: -1,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
); );
Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text( Widget toText22({Color? color, bool isBold = false, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(height: 1, color: color ?? AppColors.blackColor, fontSize: 22.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
height: 1,
color: color ?? AppColors.blackColor,
fontSize: 22.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
); );
Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text( Widget toText24({Color? color, bool isBold = false, bool isCenter = false, FontWeight? fontWeight, double? letterSpacing}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
height: 23 / 24, height: 23 / 24, color: color ?? AppColors.blackColor, fontSize: 24.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
color: color ?? AppColors.blackColor,
fontSize: 24.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : fontWeight ?? FontWeight.normal),
); );
Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text( Widget toText26({Color? color, bool isBold = false, double? height, bool isCenter = false, FontWeight? weight, double? letterSpacing}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
height: height ?? 23 / 26, height: height ?? 23 / 26, color: color ?? AppColors.blackColor, fontSize: 26.f, letterSpacing: letterSpacing ?? -1, fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
color: color ?? AppColors.blackColor,
fontSize: 26.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: weight ?? (isBold ? FontWeight.bold : FontWeight.normal)),
); );
Widget toText28({Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text( Widget toText28({bool isEnglishOnly = false, Color? color, bool isBold = false, double? height, bool isCenter = false, double? letterSpacing}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(height: height ?? 23 / 28, color: color ?? AppColors.blackColor, fontSize: 28.f, letterSpacing: letterSpacing ?? -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins'),
height: height ?? 23 / 28,
color: color ?? AppColors.blackColor,
fontSize: 28.f,
letterSpacing: letterSpacing ?? -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
); );
Widget toText32({FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text( Widget toText32({bool isEnglishOnly = false, FontWeight? weight, Color? color, bool isBold = false, bool isCenter = false}) => Text(
this, this,
textAlign: isCenter ? TextAlign.center : null, textAlign: isCenter ? TextAlign.center : null,
style: TextStyle( style: TextStyle(
height: 32 / 32, height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 32.f, letterSpacing: -1, fontFamily: isEnglishOnly ? "Poppins" : getIt.get<AppState>().getLanguageCode() == "ar" ? 'GESSTwo' : 'Poppins', fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
color: color ?? AppColors.blackColor,
fontSize: 32.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : weight ?? FontWeight.normal),
); );
Widget toText44({Color? color, bool isBold = false}) => Text( Widget toText44({Color? color, bool isBold = false}) => Text(
this, this,
style: TextStyle( style: TextStyle(height: 32 / 32, color: color ?? AppColors.blackColor, fontSize: 44.f, letterSpacing: -1, fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
height: 32 / 32,
color: color ?? AppColors.blackColor,
fontSize: 44.f,
letterSpacing: -1,
fontWeight: isBold ? FontWeight.bold : FontWeight.normal),
); );
Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) {
@ -416,9 +356,7 @@ extension EmailValidator on String {
} }
bool isValidEmail() { bool isValidEmail() {
return RegExp( return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(this);
} }
String toFormattedDate() { String toFormattedDate() {

@ -75,6 +75,8 @@ class AuthenticationViewModel extends ChangeNotifier {
dobController = TextEditingController(), dobController = TextEditingController(),
nameController = TextEditingController(), nameController = TextEditingController(),
emailController = TextEditingController(); emailController = TextEditingController();
CountryEnum selectedCountrySignup = CountryEnum.saudiArabia; CountryEnum selectedCountrySignup = CountryEnum.saudiArabia;
MaritalStatusTypeEnum? maritalStatus; MaritalStatusTypeEnum? maritalStatus;
GenderTypeEnum? genderType; GenderTypeEnum? genderType;

@ -671,7 +671,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear(); docFreeSlots.clear();
DateTime date; DateTime date;
final DateFormat formatter = DateFormat('HH:mm', "en_US"); final DateFormat formatter = DateFormat('HH:mm');
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd'); final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed; Map<DateTime, List> _eventsParsed;
@ -723,7 +723,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
Future<void> getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async { Future<void> getLiveCareDoctorFreeSlots({bool isBookingForLiveCare = false, Function(dynamic)? onSuccess, Function(String)? onError}) async {
docFreeSlots.clear(); docFreeSlots.clear();
DateTime date; DateTime date;
final DateFormat formatter = DateFormat('HH:mm'); final DateFormat formatter = DateFormat('HH:mm', "en-US");
final DateFormat dateFormatter = DateFormat('yyyy-MM-dd'); final DateFormat dateFormatter = DateFormat('yyyy-MM-dd');
Map<DateTime, List> _eventsParsed; Map<DateTime, List> _eventsParsed;

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart'; import 'package:hmg_patient_app_new/core/common_models/generic_api_model.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/enums.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart'; import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_repo.dart';
@ -17,6 +18,7 @@ import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/get
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/search_e_referral_resp_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/vital_sign_respo_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/resq_models/vital_sign_respo_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart'; import 'package:hmg_patient_app_new/services/navigation_service.dart';
@ -31,8 +33,7 @@ class HmgServicesViewModel extends ChangeNotifier {
final ErrorHandlerService errorHandlerService; final ErrorHandlerService errorHandlerService;
final NavigationService navigationService; final NavigationService navigationService;
HmgServicesViewModel( HmgServicesViewModel({required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
{required this.bookAppointmentsRepo, required this.hmgServicesRepo, required this.errorHandlerService, required this.navigationService});
bool isCmcOrdersLoading = false; bool isCmcOrdersLoading = false;
bool isCmcServicesLoading = false; bool isCmcServicesLoading = false;
@ -55,9 +56,11 @@ class HmgServicesViewModel extends ChangeNotifier {
// Vital Sign PageView Controller // Vital Sign PageView Controller
PageController _vitalSignPageController = PageController(); PageController _vitalSignPageController = PageController();
PageController get vitalSignPageController => _vitalSignPageController; PageController get vitalSignPageController => _vitalSignPageController;
int _vitalSignCurrentPage = 0; int _vitalSignCurrentPage = 0;
int get vitalSignCurrentPage => _vitalSignCurrentPage; int get vitalSignCurrentPage => _vitalSignCurrentPage;
void setVitalSignCurrentPage(int page) { void setVitalSignCurrentPage(int page) {
@ -65,7 +68,6 @@ class HmgServicesViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
// HHC specific lists // HHC specific lists
List<GetCMCAllOrdersResponseModel> hhcOrdersList = []; List<GetCMCAllOrdersResponseModel> hhcOrdersList = [];
List<GetCMCServicesResponseModel> hhcServicesList = []; List<GetCMCServicesResponseModel> hhcServicesList = [];
@ -82,9 +84,8 @@ class HmgServicesViewModel extends ChangeNotifier {
List<SearchEReferralResponseModel> searchReferralList = []; List<SearchEReferralResponseModel> searchReferralList = [];
List<Covid19GetTestProceduresResp> covidTestProcedureList = []; List<Covid19GetTestProceduresResp> covidTestProcedureList = [];
Covid19GetPaymentInfo? covidPaymentInfo; Covid19GetPaymentInfo? covidPaymentInfo;
Future<void> getOrdersList() async {}
Future<void> getOrdersList() async {}
// HHC multiple services selection // HHC multiple services selection
List<GetCMCServicesResponseModel> selectedHhcServices = []; List<GetCMCServicesResponseModel> selectedHhcServices = [];
@ -792,22 +793,20 @@ class HmgServicesViewModel extends ChangeNotifier {
}, },
); );
} }
List<CovidQuestionnaireModel> getQuestionsFromJson() { List<CovidQuestionnaireModel> getQuestionsFromJson() {
final String questionsJson = '''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]'''; final String questionsJson =
'''[ { "id": 1, "questionEN": "Is the test intended for travel?", "questionAR": "هل تجري التحليل بغرض السفر؟", "ans": 2 }, { "id": 2, "questionEN": "Coming from outside KSA within last 2 weeks?", "questionAR": "هل قدمت من خارج المملكة خلال الأسبوعين الماضيين؟", "ans": 2 }, { "id": 3, "questionEN": "Do you currently have fever?", "questionAR": "هل تعاني حاليا من حرارة؟", "ans": 2 }, { "id": 4, "questionEN": "Did you have fever in last 2 weeks?", "questionAR": "هل عانيت من حرارة في الأسبوعين الماضيين؟", "ans": 2 }, { "id": 5, "questionEN": "Do you have a sore throat?", "questionAR": "هل لديك التهاب في الحلق؟", "ans": 2 }, { "id": 6, "questionEN": "Do you have a runny nose?", "questionAR": "هل لديك سيلان بالأنف؟" }, { "id": 7, "questionEN": "Do you have a cough?", "questionAR": "هل لديك سعال؟", "ans": 2 }, { "id": 8, "questionEN": "Do you have shortness of breath?", "questionAR": "هل تعاني من ضيق في التنفس؟", "ans": 2 }, { "id": 9, "questionEN": "Do you have nausea?", "questionAR": "هل تعاني من غثيان؟", "ans": 2 }, { "id": 10, "questionEN": "Do you have vomiting?", "questionAR": "هل تعاني من القيء؟", "ans": 2 }, { "id": 11, "questionEN": "Do you have a headache?", "questionAR": "هل تعاني من صداع في الرأس؟", "ans": 2 }, { "id": 12, "questionEN": "Do you have muscle pain?", "questionAR": "هل تعانين من آلام عضلية؟", "ans": 2 }, { "id": 13, "questionEN": "Do you have joint pain?", "questionAR": "هل تعاني من آلام المفاصل؟", "ans": 2 }, { "id": 14, "questionEN": "Do you have diarrhea?", "questionAR": "هل لديك اسهال؟", "ans": 2 } ]''';
try { try {
final parsed = json.decode(questionsJson) as List<dynamic>; final parsed = json.decode(questionsJson) as List<dynamic>;
return parsed return parsed.map((e) => CovidQuestionnaireModel.fromJson(Map<String, dynamic>.from(e))).toList();
.map((e) => CovidQuestionnaireModel.fromJson(Map<String, dynamic>.from(e)))
.toList();
} catch (_) { } catch (_) {
return <CovidQuestionnaireModel>[]; return <CovidQuestionnaireModel>[];
} }
} }
Future<void> getCovidProcedureList({ Future<void> getCovidProcedureList({
Function(dynamic)? onSuccess, Function(dynamic)? onSuccess,
Function(String)? onError, Function(String)? onError,
}) async { }) async {
@ -816,14 +815,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidTestProcedures(); final result = await hmgServicesRepo.getCovidTestProcedures();
result.fold( result.fold(
(failure) async { (failure) async {
notifyListeners(); notifyListeners();
await errorHandlerService.handleError(failure: failure); await errorHandlerService.handleError(failure: failure);
if (onError != null) { if (onError != null) {
onError(failure.toString()); onError(failure.toString());
} }
}, },
(apiResponse) { (apiResponse) {
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
covidTestProcedureList = apiResponse.data ?? []; covidTestProcedureList = apiResponse.data ?? [];
notifyListeners(); notifyListeners();
@ -840,7 +839,6 @@ class HmgServicesViewModel extends ChangeNotifier {
); );
} }
Future<void> getPaymentInfo({ Future<void> getPaymentInfo({
String? procedureID, String? procedureID,
int? projectID, int? projectID,
@ -852,14 +850,14 @@ class HmgServicesViewModel extends ChangeNotifier {
final result = await hmgServicesRepo.getCovidPaymentInfo(procedureID!, projectID!); final result = await hmgServicesRepo.getCovidPaymentInfo(procedureID!, projectID!);
result.fold( result.fold(
(failure) async { (failure) async {
notifyListeners(); notifyListeners();
await errorHandlerService.handleError(failure: failure); await errorHandlerService.handleError(failure: failure);
if (onError != null) { if (onError != null) {
onError(failure.toString()); onError(failure.toString());
} }
}, },
(apiResponse) { (apiResponse) {
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
covidPaymentInfo = apiResponse.data; covidPaymentInfo = apiResponse.data;
notifyListeners(); notifyListeners();
@ -900,6 +898,8 @@ class HmgServicesViewModel extends ChangeNotifier {
if (apiResponse.messageStatus == 1) { if (apiResponse.messageStatus == 1) {
vitalSignList = apiResponse.data ?? []; vitalSignList = apiResponse.data ?? [];
hasVitalSignDataLoaded = true; hasVitalSignDataLoaded = true;
getIt.get<SymptomsCheckerViewModel>().setSelectedHeight(vitalSignList.first.heightCm);
getIt.get<SymptomsCheckerViewModel>().setSelectedWeight(vitalSignList.first.weightKg);
notifyListeners(); notifyListeners();
if (onSuccess != null) { if (onSuccess != null) {
onSuccess(apiResponse); onSuccess(apiResponse);

@ -84,9 +84,9 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
String? _selectedGender; String? _selectedGender;
DateTime? _dateOfBirth; DateTime? _dateOfBirth;
int? _selectedAge; int? _selectedAge;
double _selectedHeight = 170; num _selectedHeight = 170;
bool _isHeightCm = true; bool _isHeightCm = true;
double _selectedWeight = 60; num _selectedWeight = 60;
bool _isWeightKg = true; bool _isWeightKg = true;
// Getters // Getters
@ -108,11 +108,21 @@ class SymptomsCheckerViewModel extends ChangeNotifier {
_selectedAge = age; _selectedAge = age;
} }
double? get selectedHeight => _selectedHeight; setSelectedHeight(num height) {
_selectedHeight = height;
notifyListeners();
}
setSelectedWeight(num weight) {
_selectedWeight = weight;
notifyListeners();
}
num? get selectedHeight => _selectedHeight;
bool get isHeightCm => _isHeightCm; bool get isHeightCm => _isHeightCm;
double? get selectedWeight => _selectedWeight; num? get selectedWeight => _selectedWeight;
bool get isWeightKg => _isWeightKg; bool get isWeightKg => _isWeightKg;

@ -228,7 +228,7 @@ class MyApp extends StatelessWidget {
return MaterialApp( return MaterialApp(
title: 'Dr. AlHabib', title: 'Dr. AlHabib',
builder: (context, mchild) { builder: (context, mchild) {
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), child: mchild!); return MediaQuery(data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling, alwaysUse24HourFormat: true,), child: mchild!, );
}, },
showSemanticsDebugger: false, showSemanticsDebugger: false,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,

@ -26,6 +26,7 @@ import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'dart:ui' as ui;
class AppointmentCard extends StatelessWidget { class AppointmentCard extends StatelessWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
@ -39,20 +40,20 @@ class AppointmentCard extends StatelessWidget {
final ContactUsViewModel? contactUsViewModel; final ContactUsViewModel? contactUsViewModel;
final BookAppointmentsViewModel bookAppointmentsViewModel; final BookAppointmentsViewModel bookAppointmentsViewModel;
final bool isForRate; final bool isForRate;
const AppointmentCard({
super.key, const AppointmentCard(
required this.patientAppointmentHistoryResponseModel, {super.key,
required this.myAppointmentsViewModel, required this.patientAppointmentHistoryResponseModel,
required this.bookAppointmentsViewModel, required this.myAppointmentsViewModel,
this.isLoading = false, required this.bookAppointmentsViewModel,
this.isFromHomePage = false, this.isLoading = false,
this.isFromMedicalReport = false, this.isFromHomePage = false,
this.isForEyeMeasurements = false, this.isFromMedicalReport = false,
this.isForFeedback = false, this.isForEyeMeasurements = false,
this.medicalFileViewModel, this.isForFeedback = false,
this.contactUsViewModel, this.medicalFileViewModel,
this.isForRate =false this.contactUsViewModel,
}); this.isForRate = false});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -64,11 +65,11 @@ class AppointmentCard extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
isForRate ? SizedBox(): _buildHeader(context, appState), isForRate ? SizedBox() : _buildHeader(context, appState),
SizedBox(height: 16.h), SizedBox(height: 16.h),
_buildDoctorRow(context), _buildDoctorRow(context),
SizedBox(height: 16.h), SizedBox(height: 16.h),
isForRate ? SizedBox(): _buildActionArea(context, appState), isForRate ? SizedBox() : _buildActionArea(context, appState),
], ],
), ),
), ),
@ -101,18 +102,13 @@ class AppointmentCard extends StatelessWidget {
textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor), textColor: isLoading ? AppColors.textColor : (isLiveCare ? AppColors.whiteColor : AppColors.textColor),
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: isLoading labelText:
? 'OutPatient' isLoading ? 'OutPatient' : (appState.isArabic() ? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN! : patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
: (appState.isArabic()
? patientAppointmentHistoryResponseModel.isInOutPatientDescriptionN!
: patientAppointmentHistoryResponseModel.isInOutPatientDescription!),
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1), backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
textColor: AppColors.primaryRedColor, textColor: AppColors.primaryRedColor,
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
AppCustomChipWidget( AppCustomChipWidget(
labelText: isLoading labelText: isLoading ? 'Booked' : AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!),
? 'Booked'
: AppointmentType.getAppointmentStatusType(patientAppointmentHistoryResponseModel.patientStatusType!),
backgroundColor: AppColors.successColor.withValues(alpha: 0.1), backgroundColor: AppColors.successColor.withValues(alpha: 0.1),
textColor: AppColors.successColor, textColor: AppColors.successColor,
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
@ -188,13 +184,17 @@ class AppointmentCard extends StatelessWidget {
? '${(patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").substring(0, 15)}...' ? '${(patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital").substring(0, 15)}...'
: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital") : patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital")
.toShimmer2(isShow: isLoading), .toShimmer2(isShow: isLoading),
AppCustomChipWidget( Directionality(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), textDirection: ui.TextDirection.ltr,
icon: AppAssets.appointment_calendar_icon, child: AppCustomChipWidget(
labelText: isLoading labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
? 'Cardiology' icon: AppAssets.appointment_calendar_icon,
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}", richText: isLoading
).toShimmer2(isShow: isLoading), ? 'Cardiology'.toText10().toShimmer2(isShow: isLoading)
: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)}"
.toText10(isEnglishOnly: true),
),
),
// AppCustomChipWidget( // AppCustomChipWidget(
// labelPadding: EdgeInsetsDirectional.only(start: -2.w, end: 6.w), // labelPadding: EdgeInsetsDirectional.only(start: -2.w, end: 6.w),

@ -12,6 +12,7 @@ import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.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/chip/app_custom_chip_widget.dart';
import 'dart:ui' as ui;
class AppointmentDoctorCard extends StatelessWidget { class AppointmentDoctorCard extends StatelessWidget {
const AppointmentDoctorCard( const AppointmentDoctorCard(
@ -98,13 +99,16 @@ class AppointmentDoctorCard extends StatelessWidget {
labelText: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital", labelText: patientAppointmentHistoryResponseModel.projectName ?? "Habib Hospital",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w), labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
), ),
AppCustomChipWidget( Directionality(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), textDirection: ui.TextDirection.ltr,
icon: AppAssets.doctor_calendar_icon, child: AppCustomChipWidget(
labelText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang( labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),
DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), icon: AppAssets.doctor_calendar_icon,
false, richText: "${DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)} ${DateUtil.formatDateToTimeLang(
)}", DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
false,
)}".toText10(isEnglishOnly: true),
),
), ),
AppCustomChipWidget( AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w), labelPadding: EdgeInsetsDirectional.only(start: -6.w, end: 6.w),

@ -73,6 +73,7 @@ class LoginScreenState extends State<LoginScreen> {
SizedBox(height: 130.h), // Adjusted to sizer unit SizedBox(height: 130.h), // Adjusted to sizer unit
LocaleKeys.welcomeToDrSulaiman.tr(context: context).toText32(isBold: true, color: AppColors.textColor), LocaleKeys.welcomeToDrSulaiman.tr(context: context).toText32(isBold: true, color: AppColors.textColor),
SizedBox(height: 32.h), SizedBox(height: 32.h),
Localizations.override(context: context, locale: Locale('en', 'US'), child: Container()), // Force English locale for this widget
TextInputWidget( TextInputWidget(
labelText: "${LocaleKeys.nationalId.tr(context: context)} / ${LocaleKeys.fileNo.tr(context: context)}", labelText: "${LocaleKeys.nationalId.tr(context: context)} / ${LocaleKeys.fileNo.tr(context: context)}",
hintText: "xxxxxxxxx", hintText: "xxxxxxxxx",
@ -89,6 +90,7 @@ class LoginScreenState extends State<LoginScreen> {
leadingIcon: AppAssets.student_card, leadingIcon: AppAssets.student_card,
errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context), errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context),
hasError: false, hasError: false,
fontFamily: "Poppins",
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
CustomButton( CustomButton(

@ -100,6 +100,7 @@ class _RegisterNew extends State<RegisterNew> {
hintText: "xxxxxxxxx", hintText: "xxxxxxxxx",
controller: authVm.nationalIdController, controller: authVm.nationalIdController,
focusNode: _nationalIdFocusNode, focusNode: _nationalIdFocusNode,
keyboardType: TextInputType.number,
isEnable: true, isEnable: true,
prefix: null, prefix: null,
isAllowRadius: true, isAllowRadius: true,
@ -108,6 +109,7 @@ class _RegisterNew extends State<RegisterNew> {
autoFocus: true, autoFocus: true,
padding: EdgeInsets.symmetric(vertical: 8.h), padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.student_card, leadingIcon: AppAssets.student_card,
fontFamily: "Poppins",
).withVerticalPadding(8), ).withVerticalPadding(8),
Divider(height: 1), Divider(height: 1),
TextInputWidget( TextInputWidget(
@ -125,6 +127,7 @@ class _RegisterNew extends State<RegisterNew> {
selectionType: SelectionTypeEnum.calendar, selectionType: SelectionTypeEnum.calendar,
onCalendarTypeChanged: authVm.onCalenderTypeChange, onCalendarTypeChanged: authVm.onCalenderTypeChange,
onChange: authVm.onDobChange, onChange: authVm.onDobChange,
fontFamily: "Poppins",
).withVerticalPadding(8), ).withVerticalPadding(8),
], ],
), ),

@ -1,4 +1,3 @@
import 'dart:io'; import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@ -185,7 +184,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
children: [ children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true), LocaleKeys.amountBeforeTax.tr(context: context).toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13, Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.amount!.toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"), isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال"),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
Row( Row(
@ -194,7 +194,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor), LocaleKeys.vat15.tr(context: context).toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol( Utils.getPaymentAmountWithSymbol(
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13, immediateLiveCareVM.liveCareImmediateAppointmentFeesList.tax!.toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"), isSaudiCurrency: (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال")),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h), SizedBox(height: 17.h),
@ -203,7 +204,8 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
children: [ children: [
SizedBox(width: 150.h, child: Utils.getPaymentMethods()), SizedBox(width: 150.h, child: Utils.getPaymentMethods()),
Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17, Utils.getPaymentAmountWithSymbol(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total!.toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar"), isSaudiCurrency: (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "sar" ||
immediateLiveCareVM.liveCareImmediateAppointmentFeesList.currency!.toLowerCase() == "ريال")),
], ],
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
(immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0") (immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0" || immediateLiveCareVM.liveCareImmediateAppointmentFeesList.total == "0.0")
@ -214,18 +216,16 @@ class ImmediateLiveCarePaymentDetails extends StatelessWidget {
if (val) { if (val) {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context)); LoaderBottomSheet.showLoader(loadingText: LocaleKeys.confirmingLiveCareRequest.tr(context: context));
await immediateLiveCareVM.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime await immediateLiveCareVM.addNewCallRequestForImmediateLiveCare("${appState.getAuthenticatedUser()!.patientId}${DateTime.now().millisecondsSinceEpoch}");
.now() await immediateLiveCareVM.getPatientLiveCareHistory();
.millisecondsSinceEpoch}"); LoaderBottomSheet.hideLoader();
await immediateLiveCareVM.getPatientLiveCareHistory(); if (immediateLiveCareVM.patientHasPendingLiveCareRequest) {
LoaderBottomSheet.hideLoader(); Navigator.pushAndRemoveUntil(
if (immediateLiveCareVM.patientHasPendingLiveCareRequest) { context,
Navigator.pushAndRemoveUntil( CustomPageRoute(
context, page: LandingNavigation(),
CustomPageRoute( ),
page: LandingNavigation(), (r) => false);
),
(r) => false);
Navigator.of(context).push( Navigator.of(context).push(
CustomPageRoute( CustomPageRoute(
page: ImmediateLiveCarePendingRequestPage(), page: ImmediateLiveCarePendingRequestPage(),

@ -38,7 +38,7 @@ class DoctorCard extends StatelessWidget {
hasShadow: false, hasShadow: false,
), ),
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 14.h,bottom: 20.h), padding: EdgeInsets.only(top: 14.h, bottom: 20.h),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -91,9 +91,7 @@ class DoctorCard extends StatelessWidget {
children: [ children: [
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.55, width: MediaQuery.of(context).size.width * 0.55,
child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}") child: (isLoading ? "Dr John Smith" : "${doctorsListResponseModel.doctorTitle} ${doctorsListResponseModel.name}").toString().toText16(isBold: true, maxlines: 1),
.toString()
.toText16(isBold: true, maxlines: 1),
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
], ],
), ),
@ -135,12 +133,14 @@ class DoctorCard extends StatelessWidget {
).toShimmer2(isShow: isLoading), ).toShimmer2(isShow: isLoading),
bookAppointmentsViewModel.isNearestAppointmentSelected bookAppointmentsViewModel.isNearestAppointmentSelected
? doctorsListResponseModel.nearestFreeSlot != null ? doctorsListResponseModel.nearestFreeSlot != null
? AppCustomChipWidget( ? AppCustomChipWidget(
labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)), // labelText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot)),
backgroundColor: AppColors.successColor, richText: (isLoading ? "Cardiologist" : DateUtil.getDateStringForNearestSlot(doctorsListResponseModel.nearestFreeSlot))
textColor: AppColors.whiteColor, .toText10(isEnglishOnly: true, color: AppColors.whiteColor),
).toShimmer2(isShow: isLoading) backgroundColor: AppColors.successColor,
: SizedBox.shrink() textColor: AppColors.whiteColor,
).toShimmer2(isShow: isLoading)
: SizedBox.shrink()
: SizedBox.shrink(), : SizedBox.shrink(),
], ],
), ),
@ -149,8 +149,7 @@ class DoctorCard extends StatelessWidget {
), ),
Expanded( Expanded(
flex: 1, flex: 1,
child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown) child: Utils.buildSvgWithAssets(icon: AppAssets.doctor_profile_icon, width: 20.h, height: 20.h, fit: BoxFit.scaleDown).toShimmer2(isShow: isLoading),
.toShimmer2(isShow: isLoading),
), ),
], ],
), ),

@ -140,6 +140,7 @@ class PatientInformationStepState extends State<PatientInformationStep> {
controller: _phoneController, controller: _phoneController,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
fontFamily: "Poppins",
onChange: (value) { onChange: (value) {
formManager.updatePatientPhone(value ?? ''); formManager.updatePatientPhone(value ?? '');
}, },

@ -73,6 +73,7 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
hintText: formManager.searchCriteria == 0 ? "Enter Identification Number" : "Enter Referral Number", hintText: formManager.searchCriteria == 0 ? "Enter Identification Number" : "Enter Referral Number",
labelText: formManager.searchCriteria == 0 ? "Identification Number" : "Referral Number", labelText: formManager.searchCriteria == 0 ? "Identification Number" : "Referral Number",
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
fontFamily: "Poppins",
errorMessage: formManager.errors.searchValue, errorMessage: formManager.errors.searchValue,
hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.searchValue), hasError: !ValidationUtils.isNullOrEmpty(formManager.errors.searchValue),
onChange: (value) { onChange: (value) {
@ -94,6 +95,7 @@ class SearchEReferralFormFormState extends State<SearchEReferralFormForm> {
controller: _phoneController, controller: _phoneController,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
fontFamily: "Poppins",
onChange: (value) { onChange: (value) {
formManager.updateSearchPhone(value ?? ''); formManager.updateSearchPhone(value ?? '');
// _validateForm(formManager); // _validateForm(formManager);

@ -98,11 +98,12 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
isBorderAllowed: false, isBorderAllowed: false,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
autoFocus: true, autoFocus: true,
fontSize: 40, fontSize: 40.f,
padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h), padding: EdgeInsets.symmetric(horizontal: 8.h, vertical: 0.h),
focusNode: textFocusNode, focusNode: textFocusNode,
isWalletAmountInput: true, isWalletAmountInput: true,
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
fontFamily: "Poppins",
// leadingIcon: AppAssets.student_card, // leadingIcon: AppAssets.student_card,
), ),
), ),
@ -217,12 +218,11 @@ class _RechargeWalletPageState extends State<RechargeWalletPage> {
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
isEnable: true, isEnable: true,
prefix: null, prefix: null,
autoFocus: true, autoFocus: false,
isAllowRadius: true, isAllowRadius: true,
isBorderAllowed: false, isBorderAllowed: false,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
leadingIcon: AppAssets.notes_icon, leadingIcon: AppAssets.notes_icon,
errorMessage: LocaleKeys.enterValidIDorIqama.tr(context: context),
hasError: false, hasError: false,
), ),
SizedBox(height: 8.h), SizedBox(height: 8.h),

@ -87,7 +87,7 @@ class HabibWalletCard extends StatelessWidget {
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
SizedBox(width: 8.h), SizedBox(width: 8.h),
habibWalletVM.habibWalletAmount.toString().toText32(isBold: true).toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h), habibWalletVM.habibWalletAmount.toString().toText32(isBold: true, isEnglishOnly: true).toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.h, width: 80.h, height: 40.h),
], ],
); );
}), }),

@ -75,10 +75,11 @@ class PatientInsuranceCard extends StatelessWidget {
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.doctor_calendar_icon, icon: AppAssets.doctor_calendar_icon,
labelText: "${LocaleKeys.expiryDate.tr(context: context)} ${DateUtil.formatDateToDate(DateUtil.convertStringToDate(insuranceCardDetailsModel.cardValidTo), false)}", // labelText: "${LocaleKeys.expiryDate.tr(context: context)} ${DateUtil.formatDateToDate(DateUtil.convertStringToDate(insuranceCardDetailsModel.cardValidTo), false)}",
richText: "${LocaleKeys.expiryDate.tr(context: context)} ${DateUtil.formatDateToDate(DateUtil.convertStringToDate(insuranceCardDetailsModel.cardValidTo), false)}".toText10(isEnglishOnly: true),
labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h), labelPadding: EdgeInsetsDirectional.only(start: -4.h, end: 8.h),
), ),
AppCustomChipWidget(labelText: LocaleKeys.patientCardID.tr(namedArgs: {'id': insuranceCardDetailsModel.patientCardID ?? ''}, context: context)), AppCustomChipWidget(richText: LocaleKeys.patientCardID.tr(namedArgs: {'id': insuranceCardDetailsModel.patientCardID ?? ''}, context: context).toText10(isEnglishOnly: true)),
], ],
), ),
SizedBox(height: 10.h), SizedBox(height: 10.h),

@ -250,7 +250,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
icon: AppAssets.file_icon, icon: AppAssets.file_icon,
labelText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}", richText: "${LocaleKeys.fileno.tr(context: context)}: ${appState.getAuthenticatedUser()!.patientId}".toText10(isEnglishOnly: true),
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w), labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
), ),
AppCustomChipWidget( AppCustomChipWidget(
@ -1579,6 +1579,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
weight: FontWeight.w600, weight: FontWeight.w600,
), ),
), ),
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward, width: 18.w, height: 18.h),
], ],
), ),
SizedBox(height: 14.h), SizedBox(height: 14.h),
@ -1601,6 +1602,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
child: value.toText17( child: value.toText17(
isBold: true, isBold: true,
color: AppColors.textColor, color: AppColors.textColor,
isEnglishOnly: true
), ),
), ),
if (unit.isNotEmpty) ...[ if (unit.isNotEmpty) ...[

@ -18,6 +18,8 @@ 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/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'dart:ui' as ui;
class MedicalFileAppointmentCard extends StatelessWidget { class MedicalFileAppointmentCard extends StatelessWidget {
final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel; final PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel;
final MyAppointmentsViewModel myAppointmentsViewModel; final MyAppointmentsViewModel myAppointmentsViewModel;
@ -39,11 +41,12 @@ class MedicalFileAppointmentCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
AppCustomChipWidget( AppCustomChipWidget(
richText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false) richText: Directionality(
.toText12( textDirection: ui.TextDirection.ltr,
color: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, child: DateUtil.formatDateToDate(DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate), false)
fontWeight: FontWeight.w500) .toText12(color: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, fontWeight: FontWeight.w500, isEnglishOnly: true)
.paddingOnly(left: 8.w), .paddingSymmetrical(8.w, 0),
),
icon: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon, icon: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppAssets.appointment_calendar_icon : AppAssets.alarm_clock_icon,
iconColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor, iconColor: AppointmentType.isArrived(patientAppointmentHistoryResponseModel) ? AppColors.textColor : AppColors.primaryRedColor,
iconSize: 16.w, iconSize: 16.w,
@ -71,9 +74,7 @@ class MedicalFileAppointmentCard extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
(patientAppointmentHistoryResponseModel.doctorNameObj ?? "") (patientAppointmentHistoryResponseModel.doctorNameObj ?? "").toText14(isBold: true, maxlines: 1).toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
.toText14(isBold: true, maxlines: 1)
.toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
(patientAppointmentHistoryResponseModel.clinicName ?? "") (patientAppointmentHistoryResponseModel.clinicName ?? "")
.toText12(maxLine: 1, fontWeight: FontWeight.w500, color: AppColors.greyTextColor) .toText12(maxLine: 1, fontWeight: FontWeight.w500, color: AppColors.greyTextColor)
.toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading), .toShimmer2(isShow: myAppointmentsViewModel.isMyAppointmentsLoading),
@ -103,10 +104,8 @@ class MedicalFileAppointmentCard extends StatelessWidget {
// widget.myAppointmentsViewModel.getPatientAppointments(true, false); // widget.myAppointmentsViewModel.getPatientAppointments(true, false);
}); });
}, },
backgroundColor: backgroundColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.15),
AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.15), borderColor: AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
borderColor:
AppointmentType.getNextActionButtonColor(patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction), textColor: AppointmentType.getNextActionTextColor(patientAppointmentHistoryResponseModel.nextAction),
fontSize: 14.f, fontSize: 14.f,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,

@ -24,8 +24,8 @@ class HealthDashboard extends StatefulWidget {
class _HealthDashboardState extends State<HealthDashboard> with SingleTickerProviderStateMixin { class _HealthDashboardState extends State<HealthDashboard> with SingleTickerProviderStateMixin {
late TabController _tabController; late TabController _tabController;
final dateFormat = DateFormat('MMM dd, yyyy'); final dateFormat = DateFormat('MMM dd, yyyy', "en-US");
final timeFormat = DateFormat('hh:mm a'); final timeFormat = DateFormat('hh:mm a', "en-US");
@override @override
void initState() { void initState() {

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/route_extensions.dart'; import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.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/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_model.dart';
import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -39,13 +40,18 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
if (appState.isAuthenticated) { if (appState.isAuthenticated) {
final user = appState.getAuthenticatedUser(); final user = appState.getAuthenticatedUser();
getIt.get<HmgServicesViewModel>().getPatientVitalSign();
if (user == null) return; if (user == null) return;
// Populate gender (gender is int: 1=Male, 2=Female) // Populate gender (gender is int: 1=Male, 2=Female)
// Use internal keys (male/female) for storage // Use internal keys (male/female) for storage
if (user.gender != null) { if (user.gender != null) {
String genderKey = user.gender == 1 ? "male" : user.gender == 2 ? "female" : "other"; String genderKey = user.gender == 1
? "male"
: user.gender == 2
? "female"
: "other";
viewModel.setGender(genderKey); viewModel.setGender(genderKey);
} }
@ -64,13 +70,14 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
// If not authenticated or fields are empty, user will fill them manually // If not authenticated or fields are empty, user will fill them manually
} }
_buildEditInfoTile({ Widget _buildEditInfoTile({
required String leadingIcon, required String leadingIcon,
required String title, required String title,
required String subTitle, required String subTitle,
required VoidCallback onTap, required VoidCallback onTap,
required String trailingIcon, required String trailingIcon,
required BuildContext context, required BuildContext context,
required HmgServicesViewModel hmgServicesVM,
Color? iconColor, Color? iconColor,
}) { }) {
return InkWell( return InkWell(
@ -92,7 +99,9 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
title.toText14(weight: FontWeight.w500), title.toText14(weight: FontWeight.w500),
subTitle.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500), subTitle
.toText12(color: AppColors.primaryRedColor, fontWeight: FontWeight.w500)
.toShimmer2(isShow: (leadingIcon == AppAssets.rulerIcon || leadingIcon == AppAssets.weightScale) && hmgServicesVM.isVitalSignLoading),
], ],
), ),
], ],
@ -155,25 +164,20 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
return Scaffold( return Scaffold(
backgroundColor: AppColors.bgScaffoldColor, backgroundColor: AppColors.bgScaffoldColor,
body: Consumer<SymptomsCheckerViewModel>( body: Consumer2<SymptomsCheckerViewModel, HmgServicesViewModel>(
builder: (context, viewModel, child) { builder: (context, viewModel, hmgServicesVM, child) {
// Check if any field is empty // Check if any field is empty
bool hasEmptyFields = viewModel.selectedGender == null || bool hasEmptyFields = viewModel.selectedGender == null || viewModel.selectedAge == null || viewModel.selectedHeight == null || viewModel.selectedWeight == null;
viewModel.selectedAge == null ||
viewModel.selectedHeight == null ||
viewModel.selectedWeight == null;
// Get display values // Get display values
String genderText = _getLocalizedGender(viewModel.selectedGender, context); String genderText = _getLocalizedGender(viewModel.selectedGender, context);
// Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB) // Show age calculated from DOB (prefer viewModel's age, fallback to calculated from user's DOB)
int? displayAge = viewModel.selectedAge ?? userAgeFromDOB; int? displayAge = viewModel.selectedAge ?? userAgeFromDOB;
String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context); String ageText = displayAge != null ? "$displayAge ${LocaleKeys.years.tr(context: context)}" : LocaleKeys.notSet.tr(context: context);
String heightText = viewModel.selectedHeight != null
? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" String heightText = viewModel.selectedHeight != null ? "${viewModel.selectedHeight!.round()} ${viewModel.isHeightCm ? 'cm' : 'ft'}" : LocaleKeys.notSet.tr(context: context);
: LocaleKeys.notSet.tr(context: context);
String weightText = viewModel.selectedWeight != null String weightText = viewModel.selectedWeight != null ? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}" : LocaleKeys.notSet.tr(context: context);
? "${viewModel.selectedWeight!.round()} ${viewModel.isWeightKg ? 'kg' : 'lbs'}"
: LocaleKeys.notSet.tr(context: context);
return Column( return Column(
children: [ children: [
@ -196,53 +200,53 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
), ),
SizedBox(height: 32.h), SizedBox(height: 32.h),
_buildEditInfoTile( _buildEditInfoTile(
context: context, context: context,
leadingIcon: AppAssets.genderIcon, leadingIcon: AppAssets.genderIcon,
title: LocaleKeys.gender.tr(context: context), title: LocaleKeys.gender.tr(context: context),
subTitle: genderText, subTitle: genderText,
onTap: () { onTap: () {
viewModel.setUserInfoPage(0, isSinglePageEdit: true); viewModel.setUserInfoPage(0, isSinglePageEdit: true);
context.navigateWithName(AppRoutes.userInfoFlowManager); context.navigateWithName(AppRoutes.userInfoFlowManager);
}, },
trailingIcon: AppAssets.edit_icon, trailingIcon: AppAssets.edit_icon,
), hmgServicesVM: hmgServicesVM),
_getDivider(), _getDivider(),
_buildEditInfoTile( _buildEditInfoTile(
context: context, context: context,
leadingIcon: AppAssets.calendarGrey, leadingIcon: AppAssets.calendarGrey,
title: LocaleKeys.age.tr(context: context), title: LocaleKeys.age.tr(context: context),
subTitle: ageText, subTitle: ageText,
iconColor: AppColors.greyTextColor, iconColor: AppColors.greyTextColor,
onTap: () { onTap: () {
viewModel.setUserInfoPage(1, isSinglePageEdit: true); viewModel.setUserInfoPage(1, isSinglePageEdit: true);
context.navigateWithName(AppRoutes.userInfoFlowManager); context.navigateWithName(AppRoutes.userInfoFlowManager);
}, },
trailingIcon: AppAssets.edit_icon, trailingIcon: AppAssets.edit_icon,
), hmgServicesVM: hmgServicesVM),
_getDivider(), _getDivider(),
_buildEditInfoTile( _buildEditInfoTile(
context: context, context: context,
leadingIcon: AppAssets.rulerIcon, leadingIcon: AppAssets.rulerIcon,
title: LocaleKeys.height.tr(context: context), title: LocaleKeys.height.tr(context: context),
subTitle: heightText, subTitle: heightText,
onTap: () { onTap: () {
viewModel.setUserInfoPage(2, isSinglePageEdit: true); viewModel.setUserInfoPage(2, isSinglePageEdit: true);
context.navigateWithName(AppRoutes.userInfoFlowManager); context.navigateWithName(AppRoutes.userInfoFlowManager);
}, },
trailingIcon: AppAssets.edit_icon, trailingIcon: AppAssets.edit_icon,
), hmgServicesVM: hmgServicesVM),
_getDivider(), _getDivider(),
_buildEditInfoTile( _buildEditInfoTile(
context: context, context: context,
leadingIcon: AppAssets.weightScale, leadingIcon: AppAssets.weightScale,
title: LocaleKeys.weight.tr(context: context), title: LocaleKeys.weight.tr(context: context),
subTitle: weightText, subTitle: weightText,
onTap: () { onTap: () {
viewModel.setUserInfoPage(3, isSinglePageEdit: true); viewModel.setUserInfoPage(3, isSinglePageEdit: true);
context.navigateWithName(AppRoutes.userInfoFlowManager); context.navigateWithName(AppRoutes.userInfoFlowManager);
}, },
trailingIcon: AppAssets.edit_icon, trailingIcon: AppAssets.edit_icon,
), hmgServicesVM: hmgServicesVM),
], ],
), ),
), ),
@ -292,6 +296,7 @@ class _UserInfoSelectionPageState extends State<UserInfoSelectionPage> {
text: LocaleKeys.yesItIs.tr(context: context), text: LocaleKeys.yesItIs.tr(context: context),
icon: AppAssets.tickIcon, icon: AppAssets.tickIcon,
iconColor: hasEmptyFields ? AppColors.greyTextColor : AppColors.whiteColor, iconColor: hasEmptyFields ? AppColors.greyTextColor : AppColors.whiteColor,
isDisabled: getIt.get<HmgServicesViewModel>().isVitalSignLoading || hasEmptyFields,
onPressed: hasEmptyFields onPressed: hasEmptyFields
? () {} // Empty function for disabled state ? () {} // Empty function for disabled state
: () => context.navigateWithName(AppRoutes.organSelectorPage), : () => context.navigateWithName(AppRoutes.organSelectorPage),

@ -158,7 +158,7 @@ class HeightSelectionPage extends StatelessWidget {
enableSound: true, enableSound: true,
minValue: minValue, minValue: minValue,
maxValue: maxValue, maxValue: maxValue,
initialHeight: viewModel.selectedHeight ?? 100, initialHeight: (viewModel.selectedHeight ?? 100).toDouble(),
isCm: viewModel.isHeightCm, isCm: viewModel.isHeightCm,
onHeightChanged: (newHeight) { onHeightChanged: (newHeight) {
log("height: $newHeight"); log("height: $newHeight");

@ -150,7 +150,7 @@ class WeightSelectionPage extends StatelessWidget {
enableSound: true, enableSound: true,
minValue: minValue, minValue: minValue,
maxValue: maxValue, maxValue: maxValue,
initialWeight: viewModel.selectedWeight!, initialWeight: (viewModel.selectedWeight ?? 70).toDouble(),
isKg: isKg, isKg: isKg,
onWeightChanged: (newWeight) { onWeightChanged: (newWeight) {
log("weight: $newWeight"); log("weight: $newWeight");

@ -148,6 +148,7 @@ class _VitalSignDetailsPageState extends State<VitalSignDetailsPage> {
isBold: true, isBold: true,
color: scheme.iconFg, color: scheme.iconFg,
letterSpacing: -2, letterSpacing: -2,
isEnglishOnly: true
), ),
), ),
SizedBox(width: 4.h), SizedBox(width: 4.h),

@ -3,6 +3,8 @@ import 'dart:ui';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart'; 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';
import 'package:hmg_patient_app_new/core/utils/size_utils.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/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
@ -330,6 +332,9 @@ class _VitalSignPageState extends State<VitalSignPage> {
weight: FontWeight.w600, weight: FontWeight.w600,
), ),
), ),
Utils.buildSvgWithAssets(
icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward,
width: 18.w, height: 18.h),
], ],
), ),
SizedBox(height: 14.h), SizedBox(height: 14.h),
@ -353,6 +358,7 @@ class _VitalSignPageState extends State<VitalSignPage> {
value.toText17( value.toText17(
isBold: true, isBold: true,
color: AppColors.textColor, color: AppColors.textColor,
isEnglishOnly: true
), ),
if (unit.isNotEmpty) ...[ if (unit.isNotEmpty) ...[
SizedBox(width: 3.w), SizedBox(width: 3.w),

@ -158,9 +158,10 @@ class GenericBottomSheetState extends State<GenericBottomSheet> {
prefix: widget.isForEmail ? null : widget.countryCode, prefix: widget.isForEmail ? null : widget.countryCode,
isBorderAllowed: false, isBorderAllowed: false,
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
fontSize: 13, fontSize: 18.f,
isCountryDropDown: widget.isEnableCountryDropdown, isCountryDropDown: widget.isEnableCountryDropdown,
leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone, leadingIcon: widget.isForEmail ? AppAssets.email : AppAssets.smart_phone,
fontFamily: "Poppins",
) )
: SizedBox(), : SizedBox(),
], ],

@ -100,7 +100,7 @@ class CustomCountryDropdownState extends State<CustomCountryDropdown> {
children: [ children: [
Text( Text(
selectedCountry!.countryCode, selectedCountry!.countryCode,
style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5), style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"),
), ),
SizedBox(width: 4.h), SizedBox(width: 4.h),
if (widget.isEnableTextField) if (widget.isEnableTextField)
@ -111,7 +111,7 @@ class CustomCountryDropdownState extends State<CustomCountryDropdown> {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: TextField( child: TextField(
focusNode: textFocusNode, focusNode: textFocusNode,
style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5), style: TextStyle(fontSize: 12.f, fontWeight: FontWeight.w600, letterSpacing: -0.4, height: 1.5, fontFamily: "Poppins"),
decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none, contentPadding: EdgeInsets.zero), decoration: InputDecoration(hintText: "", isDense: true, border: InputBorder.none, contentPadding: EdgeInsets.zero),
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onChanged: widget.onPhoneNumberChanged, onChanged: widget.onPhoneNumberChanged,

@ -54,6 +54,7 @@ class FamilyFileAddWidget extends StatelessWidget {
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
autoFocus: true, autoFocus: true,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
fontFamily: "Poppins",
padding: EdgeInsets.symmetric(vertical: 8.h), padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.student_card, leadingIcon: AppAssets.student_card,
).paddingOnly(top: 8.h, bottom: 8.h), ).paddingOnly(top: 8.h, bottom: 8.h),
@ -69,6 +70,7 @@ class FamilyFileAddWidget extends StatelessWidget {
isAllowLeadingIcon: true, isAllowLeadingIcon: true,
autoFocus: true, autoFocus: true,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
fontFamily: "Poppins",
padding: EdgeInsets.symmetric(vertical: 8.h), padding: EdgeInsets.symmetric(vertical: 8.h),
leadingIcon: AppAssets.smart_phone, leadingIcon: AppAssets.smart_phone,
).paddingOnly(top: 8.h, bottom: 4.h), ).paddingOnly(top: 8.h, bottom: 4.h),

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart'; import 'package:hijri_gregorian_calendar/hijri_gregorian_calendar.dart';
import 'package:hmg_patient_app_new/core/app_assets.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_export.dart';
@ -11,6 +12,7 @@ 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/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart'; import 'package:hmg_patient_app_new/widgets/dropdown/country_dropdown_widget.dart';
import 'package:hmg_patient_app_new/widgets/time_picker_widget.dart'; import 'package:hmg_patient_app_new/widgets/time_picker_widget.dart';
import 'dart:ui' as ui;
class TextInputWidget extends StatelessWidget { class TextInputWidget extends StatelessWidget {
final String labelText; final String labelText;
@ -48,6 +50,8 @@ class TextInputWidget extends StatelessWidget {
final bool? isHideSwitcher; final bool? isHideSwitcher;
final bool? isArrowTrailing; final bool? isArrowTrailing;
final String? fontFamily;
// final List<Country> countryList; // final List<Country> countryList;
// final Function(Country)? onCountryChange; // final Function(Country)? onCountryChange;
@ -86,6 +90,7 @@ class TextInputWidget extends StatelessWidget {
this.maxLines = 6, this.maxLines = 6,
this.isHideSwitcher, this.isHideSwitcher,
this.isArrowTrailing, this.isArrowTrailing,
this.fontFamily,
// this.countryList = const [], // this.countryList = const [],
// this.onCountryChange, // this.onCountryChange,
}); });
@ -226,11 +231,8 @@ class TextInputWidget extends StatelessWidget {
initialDate: DateTime.now(), initialDate: DateTime.now(),
showCalendarToggle: isHideSwitcher == true ? false : true, showCalendarToggle: isHideSwitcher == true ? false : true,
fontFamily: appState.getLanguageCode() == "ar" ? "GESSTwo" : "Poppins", fontFamily: appState.getLanguageCode() == "ar" ? "GESSTwo" : "Poppins",
okWidget: okWidget: Padding(padding: EdgeInsets.only(right: 8.h), child: Utils.buildSvgWithAssets(icon: AppAssets.confirm, width: 24.h, height: 24.h)),
Padding(padding: EdgeInsets.only(right: 8.h), child: Utils.buildSvgWithAssets(icon: AppAssets.confirm, width: 24.h, height: 24.h)), cancelWidget: Padding(padding: EdgeInsets.only(right: 8.h), child: Utils.buildSvgWithAssets(icon: AppAssets.cancel, iconColor: Colors.white, width: 24.h, height: 24.h)),
cancelWidget: Padding(
padding: EdgeInsets.only(right: 8.h),
child: Utils.buildSvgWithAssets(icon: AppAssets.cancel, iconColor: Colors.white, width: 24.h, height: 24.h)),
onCalendarTypeChanged: (bool value) { onCalendarTypeChanged: (bool value) {
isGregorian = value; isGregorian = value;
}); });
@ -300,50 +302,103 @@ class TextInputWidget extends StatelessWidget {
Widget _buildTextField(BuildContext context) { Widget _buildTextField(BuildContext context) {
double fontS = fontSize ?? 14.f; double fontS = fontSize ?? 14.f;
return TextField( return Builder(
enabled: isEnable, builder: (context) {
scrollPadding: EdgeInsets.zero, return Localizations.override(
keyboardType: isMultiline ? TextInputType.multiline : keyboardType, context: context,
controller: controller, locale: const Locale('en', 'US'), // Force English locale for TextField
readOnly: isReadOnly, child: TextField(
textAlignVertical: TextAlignVertical.top, hintLocales: const [Locale('en', 'US')],
textAlign: TextAlign.left, enabled: isEnable,
textDirection: TextDirection.ltr, scrollPadding: EdgeInsets.zero,
onChanged: onChange, keyboardType: isMultiline ? TextInputType.multiline : keyboardType,
focusNode: focusNode ?? _focusNode, controller: controller,
autofocus: autoFocus, readOnly: isReadOnly,
textInputAction: TextInputAction.done, textAlignVertical: TextAlignVertical.top,
cursorHeight: isWalletAmountInput! ? 40.h : 20.h, textAlign: TextAlign.left,
onTapOutside: (event) { textDirection: TextDirection.ltr,
FocusManager.instance.primaryFocus?.unfocus(); onChanged: onChange,
focusNode: focusNode ?? _focusNode,
autofocus: autoFocus,
textInputAction: TextInputAction.done,
cursorHeight: isWalletAmountInput! ? 40.h : 20.h,
onTapOutside: (event) {
FocusManager.instance.primaryFocus?.unfocus();
},
onSubmitted: onSubmitted,
minLines: isMultiline ? minLines : 1,
maxLines: isMultiline ? maxLines : 1,
style: TextStyle(
fontSize: fontS,
height: isMultiline ? 1.2 : (isWalletAmountInput! ? 1 / 4 : 0),
fontWeight: FontWeight.w500,
color: AppColors.textColor,
letterSpacing: -1,
// fontFamily: keyboardType == TextInputType.number ? getIt.get<AppState>().isArabic() ? 'GESSTwo' : 'Poppins' : 'Poppins',
fontFamily: fontFamily,
locale: const Locale('en', 'US'), // Force English locale for text style
),
decoration: InputDecoration(
isDense: true,
hintText: hintText,
hintStyle: TextStyle(fontSize: 14.f, height: 21 / 16, fontWeight: FontWeight.w500, color: hintColor != null ? AppColors.textColor : Color(0xff898A8D), letterSpacing: -0.75),
prefixIconConstraints: BoxConstraints(minWidth: 30.h),
prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, weight: FontWeight.w500),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
);
}, },
onSubmitted: onSubmitted,
minLines: isMultiline ? minLines : 1,
maxLines: isMultiline ? maxLines : 1,
style: TextStyle(
fontSize: fontS,
height: isMultiline ? 1.2 : (isWalletAmountInput! ? 1 / 4 : 0),
fontWeight: FontWeight.w500,
color: AppColors.textColor,
letterSpacing: -1,
),
decoration: InputDecoration(
isDense: true,
hintText: hintText,
hintStyle: TextStyle(
fontSize: 14.f,
height: 21 / 16,
fontWeight: FontWeight.w500,
color: hintColor != null ? AppColors.textColor : Color(0xff898A8D),
letterSpacing: -0.75),
prefixIconConstraints: BoxConstraints(minWidth: 30.h),
prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, weight: FontWeight.w500),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
); );
// TextField(
// hintLocales: const [Locale('en', 'US')],
// enabled: isEnable,
// scrollPadding: EdgeInsets.zero,
// keyboardType: isMultiline ? TextInputType.multiline : keyboardType,
// controller: controller,
// readOnly: isReadOnly,
// textAlignVertical: TextAlignVertical.top,
// textAlign: TextAlign.left,
// textDirection: TextDirection.ltr,
// onChanged: onChange,
// focusNode: focusNode ?? _focusNode,
// autofocus: autoFocus,
// textInputAction: TextInputAction.done,
// cursorHeight: isWalletAmountInput! ? 40.h : 20.h,
// onTapOutside: (event) {
// FocusManager.instance.primaryFocus?.unfocus();
// },
// onSubmitted: onSubmitted,
// minLines: isMultiline ? minLines : 1,
// maxLines: isMultiline ? maxLines : 1,
// style: TextStyle(
// fontSize: fontS,
// height: isMultiline ? 1.2 : (isWalletAmountInput! ? 1 / 4 : 0),
// fontWeight: FontWeight.w500,
// color: AppColors.textColor,
// letterSpacing: -1,
// ),
// decoration: InputDecoration(
// isDense: true,
// hintText: hintText,
// hintStyle: TextStyle(
// fontSize: 14.f,
// height: 21 / 16,
// fontWeight: FontWeight.w500,
// color: hintColor != null ? AppColors.textColor : Color(0xff898A8D),
// letterSpacing: -0.75),
// prefixIconConstraints: BoxConstraints(minWidth: 30.h),
// prefixIcon: prefix == null ? null : "+${prefix!}".toText14(letterSpacing: -1, color: AppColors.textColor, weight: FontWeight.w500),
// contentPadding: EdgeInsets.zero,
// border: InputBorder.none,
// focusedBorder: InputBorder.none,
// enabledBorder: InputBorder.none,
// ),
// );
} }
_buildTrailingIconForSearch(BuildContext context) { _buildTrailingIconForSearch(BuildContext context) {

Loading…
Cancel
Save