appointment reminder & weather

dev_aamir
aamir-csol 1 day ago
parent 7bf69c52f0
commit 2b0f8b45b0

@ -39,7 +39,7 @@
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"
tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- Gallery/Photo permissions for Android 13+ (API 33+) -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
@ -52,7 +52,6 @@
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove" /> <!-- <uses-permission android:name="android.permission.INTERNET" /> -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" tools:node="remove" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

@ -0,0 +1,9 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00439 1.5C9.41861 1.5 9.75439 1.83579 9.75439 2.25V4.50003L10.1913 4.50001C10.323 4.49992 10.4848 4.4998 10.6171 4.51636L10.6196 4.51667C10.7144 4.5285 11.1465 4.58237 11.3522 5.00657C11.5585 5.43169 11.332 5.80679 11.283 5.88795L11.0287 6.23932C10.8077 6.52119 10.5034 6.90703 10.2181 7.20028C10.0757 7.34661 9.91277 7.49754 9.73959 7.61668C9.58565 7.72258 9.323 7.87503 9 7.87503C8.677 7.87503 8.41436 7.72258 8.26041 7.61668C8.08723 7.49754 7.92428 7.34661 7.78191 7.20028C7.49659 6.90703 7.19231 6.52118 6.97134 6.23931L6.71698 5.88795C6.66799 5.80679 6.44154 5.43169 6.64776 5.00657C6.85353 4.58237 7.28556 4.5285 7.38039 4.51667L7.3829 4.51636C7.51523 4.49981 7.67697 4.49992 7.8087 4.50001L8.25439 4.50003V2.25C8.25439 1.83579 8.59018 1.5 9.00439 1.5Z" fill="#2E3039"/>
<path d="M14.3028 8.50787C14.5957 8.21498 14.5957 7.7401 14.3028 7.44721C14.0099 7.15432 13.535 7.15432 13.2421 7.44721L12.4466 8.2427C12.1537 8.5356 12.1537 9.01047 12.4466 9.30336C12.7395 9.59626 13.2144 9.59626 13.5073 9.30336L14.3028 8.50787Z" fill="#2E3039"/>
<path d="M4.75778 7.44767C4.46489 7.15478 3.99002 7.15478 3.69712 7.44767C3.40423 7.74057 3.40423 8.21544 3.69712 8.50833L4.49262 9.30383C4.78551 9.59672 5.26039 9.59672 5.55328 9.30383C5.84617 9.01094 5.84617 8.53606 5.55328 8.24317L4.75778 7.44767Z" fill="#2E3039"/>
<path d="M2.25 12.0005C1.83579 12.0005 1.5 12.3363 1.5 12.7505C1.5 13.1648 1.83579 13.5005 2.25 13.5005H3.375C3.78921 13.5005 4.125 13.1648 4.125 12.7505C4.125 12.3363 3.78921 12.0005 3.375 12.0005H2.25Z" fill="#2E3039"/>
<path d="M14.625 12.0005C14.2108 12.0005 13.875 12.3363 13.875 12.7505C13.875 13.1648 14.2108 13.5005 14.625 13.5005H15.75C16.1642 13.5005 16.5 13.1648 16.5 12.7505C16.5 12.3363 16.1642 12.0005 15.75 12.0005H14.625Z" fill="#2E3039"/>
<path d="M16.5 15.75C16.5 16.1642 16.1642 16.5 15.75 16.5L2.25 16.5C1.83579 16.5 1.5 16.1642 1.5 15.75C1.5 15.3358 1.83579 15 2.25 15L15.75 15C16.1642 15 16.5 15.3358 16.5 15.75Z" fill="#2E3039"/>
<path d="M9 9C6.92893 9 5.25 10.6789 5.25 12.75C5.25 13.1642 5.58579 13.5 6 13.5H12C12.4142 13.5 12.75 13.1642 12.75 12.75C12.75 10.6789 11.0711 9 9 9Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -0,0 +1,9 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00439 7.87503C9.41861 7.87503 9.75439 7.53924 9.75439 7.12503L9.75439 4.875L10.1913 4.87501C10.323 4.87511 10.4848 4.87522 10.6171 4.85867L10.6196 4.85836C10.7144 4.84653 11.1465 4.79266 11.3522 4.36846C11.5585 3.94334 11.332 3.56824 11.283 3.48708L11.0287 3.13571C10.8077 2.85384 10.5034 2.468 10.2181 2.17474C10.0757 2.02841 9.91277 1.87749 9.73959 1.75835C9.58565 1.65245 9.323 1.5 9 1.5C8.677 1.5 8.41436 1.65245 8.26041 1.75835C8.08723 1.87749 7.92428 2.02841 7.78191 2.17474C7.49658 2.468 7.19231 2.85385 6.97134 3.13572L6.71698 3.48708C6.66799 3.56823 6.44154 3.94334 6.64776 4.36846C6.85353 4.79265 7.28556 4.84653 7.38039 4.85836L7.38291 4.85867C7.51523 4.87522 7.67697 4.87511 7.8087 4.87501L8.25439 4.875L8.25439 7.12503C8.25439 7.53924 8.59018 7.87503 9.00439 7.87503Z" fill="#2E3039"/>
<path d="M14.3028 8.5079C14.5957 8.215 14.5957 7.74013 14.3028 7.44724C14.0099 7.15434 13.535 7.15434 13.2421 7.44724L12.4466 8.24273C12.1537 8.53563 12.1537 9.0105 12.4466 9.30339C12.7395 9.59629 13.2144 9.59629 13.5073 9.30339L14.3028 8.5079Z" fill="#2E3039"/>
<path d="M4.75778 7.4477C4.46489 7.15481 3.99002 7.15481 3.69712 7.4477C3.40423 7.74059 3.40423 8.21547 3.69712 8.50836L4.49262 9.30386C4.78551 9.59675 5.26039 9.59675 5.55328 9.30386C5.84617 9.01096 5.84617 8.53609 5.55328 8.2432L4.75778 7.4477Z" fill="#2E3039"/>
<path d="M2.25 12.0006C1.83579 12.0006 1.5 12.3364 1.5 12.7506C1.5 13.1648 1.83579 13.5006 2.25 13.5006H3.375C3.78921 13.5006 4.125 13.1648 4.125 12.7506C4.125 12.3364 3.78921 12.0006 3.375 12.0006H2.25Z" fill="#2E3039"/>
<path d="M14.625 12.0006C14.2108 12.0006 13.875 12.3364 13.875 12.7506C13.875 13.1648 14.2108 13.5006 14.625 13.5006H15.75C16.1642 13.5006 16.5 13.1648 16.5 12.7506C16.5 12.3364 16.1642 12.0006 15.75 12.0006H14.625Z" fill="#2E3039"/>
<path d="M16.5 15.75C16.5 16.1642 16.1642 16.5 15.75 16.5L2.25 16.5C1.83579 16.5 1.5 16.1642 1.5 15.75C1.5 15.3358 1.83579 15 2.25 15L15.75 15C16.1642 15 16.5 15.3358 16.5 15.75Z" fill="#2E3039"/>
<path d="M9 9.00003C6.92893 9.00003 5.25 10.679 5.25 12.75C5.25 13.1642 5.58579 13.5 6 13.5H12C12.4142 13.5 12.75 13.1642 12.75 12.75C12.75 10.679 11.0711 9.00003 9 9.00003Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -64,6 +64,8 @@ import 'package:hmg_patient_app_new/features/todo_section/todo_section_repo.dart
import 'package:hmg_patient_app_new/features/todo_section/todo_section_view_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_repo.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
import 'package:hmg_patient_app_new/features/weather/weather_repo.dart';
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
import 'package:hmg_patient_app_new/features/health_trackers/health_trackers_view_model.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/cache_service.dart';
@ -164,6 +166,7 @@ class AppDependencies {
getIt.registerLazySingleton<SymptomsCheckerRepo>(() => SymptomsCheckerRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<BloodDonationRepo>(() => BloodDonationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<WaterMonitorRepo>(() => WaterMonitorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<WeatherRepo>(() => WeatherRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MyInvoicesRepo>(() => MyInvoicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<HealthTrackersRepo>(() => HealthTrackersRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MonthlyReportRepo>(() => MonthlyReportRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
@ -299,6 +302,8 @@ class AppDependencies {
getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton<WeatherMonitorViewModel>(() => WeatherMonitorViewModel(weatherRepo: getIt(), errorHandlerService: getIt(), locationUtils: getIt()));
//commenting this because its already define there was on run time error because of this.
getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(myInvoicesRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));

@ -41,6 +41,7 @@ class MedicalFileViewModel extends ChangeNotifier {
List<SickLeaveList> patientSickLeavesViewList = [];
bool isSickLeavesSortByClinic = true;
// bool isSickLeavesDataNeedsReloading = true;
List<GetAllergiesResponseModel> patientAllergiesList = [];
@ -165,13 +166,13 @@ class MedicalFileViewModel extends ChangeNotifier {
setIsPatientSickLeaveListLoading(bool val) {
// if (val && isSickLeavesDataNeedsReloading) {
patientSickLeaveList.clear();
patientSickLeavesByClinic.clear();
patientSickLeavesByHospital.clear();
patientSickLeavesViewList.clear();
patientSickLeavePDFBase64 = "";
isSickLeavesSortByClinic = true;
isPatientSickLeaveListLoading = val;
patientSickLeaveList.clear();
patientSickLeavesByClinic.clear();
patientSickLeavesByHospital.clear();
patientSickLeavesViewList.clear();
patientSickLeavePDFBase64 = "";
isSickLeavesSortByClinic = true;
isPatientSickLeaveListLoading = val;
// }
notifyListeners();
}
@ -774,4 +775,6 @@ class MedicalFileViewModel extends ChangeNotifier {
},
);
}
}

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/utils/calender_utils_new.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
@ -1109,4 +1110,108 @@ class MyAppointmentsViewModel extends ChangeNotifier {
},
);
}
/// Creates a reminder for the appointment
/// Shows a bottom sheet to select reminder time and creates calendar event
Future<void> createReminder({
required BuildContext context,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
try {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
DateTime endDate = DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate);
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
patientAppointmentHistoryResponseModel.doctorNameObj ?? "",
"${patientAppointmentHistoryResponseModel.appointmentNo}",
"",
"",
title: "Appointment with ${patientAppointmentHistoryResponseModel.doctorNameObj}",
description: "${patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () {
setAppointmentReminder(true, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(true);
}
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
bool isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title: "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${patientAppointmentHistoryResponseModel.appointmentNo}",
description: "Appointment Reminder with ${patientAppointmentHistoryResponseModel.doctorNameObj} in ${patientAppointmentHistoryResponseModel.projectName}",
scheduleDateTime: DateUtil.convertStringToDate(patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${patientAppointmentHistoryResponseModel.appointmentNo}",
location: '',
reminderMinutes: selectedIndex,
);
setAppointmentReminder(isEventAddedOrRemoved, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(isEventAddedOrRemoved);
}
},
);
} catch (e) {
if (onError != null) {
onError(e.toString());
}
}
}
/// Deletes the reminder for the appointment
/// Removes the calendar event associated with the appointment
Future<void> deleteReminder({
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
try {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
bool isEventRemoved = await calender.checkAndRemove(
id: "${patientAppointmentHistoryResponseModel.appointmentNo}",
);
// Update the reminder status (inverted because we're removing)
setAppointmentReminder(!isEventRemoved, patientAppointmentHistoryResponseModel);
if (onSuccess != null) {
onSuccess(isEventRemoved);
}
} catch (e) {
if (onError != null) {
onError(e.toString());
}
}
}
/// Toggle reminder for an appointment
/// Creates or deletes reminder based on the current state
Future<void> toggleReminder({
required BuildContext context,
required bool shouldCreateReminder,
required PatientAppointmentHistoryResponseModel patientAppointmentHistoryResponseModel,
Function(bool)? onSuccess,
Function(String)? onError,
}) async {
if (shouldCreateReminder) {
await createReminder(
context: context,
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
onSuccess: onSuccess,
onError: onError,
);
} else {
await deleteReminder(
patientAppointmentHistoryResponseModel: patientAppointmentHistoryResponseModel,
onSuccess: onSuccess,
onError: onError,
);
}
}
}

@ -0,0 +1,257 @@
import 'dart:convert';
class GetCityInfoList {
CategoriesNames? categoriesNames;
String? category;
String? categoryValue;
int? cityId;
String? cityName;
String? cityNameN;
ColorName? colorName;
String? createdOn;
String? id;
int? iniceId;
bool? isOrderEmpty;
bool? isValuesReversed;
bool? language;
double? latitude;
double? longitude;
String? name;
int? orderNum;
double? temperature;
String? value;
GetCityInfoList({
this.categoriesNames,
this.category,
this.categoryValue,
this.cityId,
this.cityName,
this.cityNameN,
this.colorName,
this.createdOn,
this.id,
this.iniceId,
this.isOrderEmpty,
this.isValuesReversed,
this.language,
this.latitude,
this.longitude,
this.name,
this.orderNum,
this.temperature,
this.value,
});
factory GetCityInfoList.fromRawJson(String str) => GetCityInfoList.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetCityInfoList.fromJson(Map<String, dynamic> json) {
ColorName? parseColorName(dynamic value) {
if (value == null) return null;
try {
return colorNameValues.map[value.toString()];
} catch (e) {
print("Unknown color name: $value");
return null;
}
}
CategoriesNames? parseCategoriesNames(dynamic value) {
if (value == null) return null;
try {
return CategoriesNames.fromJson(value as Map<String, dynamic>);
} catch (e) {
print("Error parsing CategoriesNames: $e");
return null;
}
}
return GetCityInfoList(
categoriesNames: parseCategoriesNames(json["CategoriesNames"]),
category: json["Category"],
categoryValue: json["CategoryValue"],
cityId: json["CityID"],
cityName: json["CityName"],
cityNameN: json["CityNameN"],
colorName: parseColorName(json["ColorName"]),
createdOn: json["CreatedOn"],
id: json["ID"],
iniceId: json["IniceID"],
isOrderEmpty: json["IsOrderEmpty"],
isValuesReversed: json["IsValuesReversed"],
language: json["Language"],
latitude: json["Latitude"]?.toDouble(),
longitude: json["Longitude"]?.toDouble(),
name: json["Name"],
orderNum: json["OrderNum"],
temperature: json["Temperature"]?.toDouble(),
value: json["Value"],
);
}
Map<String, dynamic> toJson() => {
"CategoriesNames": categoriesNames?.toJson(),
"Category": category,
"CategoryValue": categoryValue,
"CityID": cityId,
"CityName": cityName,
"CityNameN": cityNameN,
"ColorName": colorNameValues.reverse[colorName],
"CreatedOn": createdOn,
"ID": id,
"IniceID": iniceId,
"IsOrderEmpty": isOrderEmpty,
"IsValuesReversed": isValuesReversed,
"Language": language,
"Latitude": latitude,
"Longitude": longitude,
"Name": name,
"OrderNum": orderNum,
"Temperature": temperature,
"Value": value,
};
}
class CategoriesNames {
Category1? category1;
Category2? category2;
Category3? category3;
Category4? category4;
Category5? category5;
CategoriesNames({
this.category1,
this.category2,
this.category3,
this.category4,
this.category5,
});
factory CategoriesNames.fromRawJson(String str) => CategoriesNames.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory CategoriesNames.fromJson(Map<String, dynamic> json) {
T? parseEnum<T>(dynamic value, EnumValues<T> enumValues, String enumName) {
if (value == null) return null;
try {
return enumValues.map[value.toString()];
} catch (e) {
print("Unknown $enumName value: $value");
return null;
}
}
return CategoriesNames(
category1: parseEnum(json["Category1"], category1Values, "Category1"),
category2: parseEnum(json["Category2"], category2Values, "Category2"),
category3: parseEnum(json["Category3"], category3Values, "Category3"),
category4: parseEnum(json["Category4"], category4Values, "Category4"),
category5: parseEnum(json["Category5"], category5Values, "Category5"),
);
}
Map<String, dynamic> toJson() => {
"Category1": category1Values.reverse[category1],
"Category2": category2Values.reverse[category2],
"Category3": category3Values.reverse[category3],
"Category4": category4Values.reverse[category4],
"Category5": category5Values.reverse[category5],
};
}
enum Category1 {
AT_EXTREME_RISK,
CATEGORY1_EXTREME,
EXTREME,
POOR
}
final category1Values = EnumValues({
"At Extreme Risk": Category1.AT_EXTREME_RISK,
"Extreme\u000d\n": Category1.CATEGORY1_EXTREME,
"Extreme": Category1.EXTREME,
"Poor": Category1.POOR
});
enum Category2 {
AT_HIGH_RISK,
CATEGORY2_VERY_HIGH,
FAIR,
VERY_HIGH
}
final category2Values = EnumValues({
"At High Risk": Category2.AT_HIGH_RISK,
"Very High\u000d\n": Category2.CATEGORY2_VERY_HIGH,
"Fair": Category2.FAIR,
"Very High": Category2.VERY_HIGH
});
enum Category3 {
AT_RISK,
CATEGORY3_HIGH,
GOOD,
HIGH
}
final category3Values = EnumValues({
"At Risk": Category3.AT_RISK,
"High\u000d\n": Category3.CATEGORY3_HIGH,
"Good": Category3.GOOD,
"High": Category3.HIGH
});
enum Category4 {
CATEGORY4_MODERATE,
MODERATE,
NEUTRAL,
VERY_GOOD
}
final category4Values = EnumValues({
"Moderate\u000d\n": Category4.CATEGORY4_MODERATE,
"Moderate": Category4.MODERATE,
"Neutral": Category4.NEUTRAL,
"Very Good": Category4.VERY_GOOD
});
enum Category5 {
BENEFICIAL,
CATEGORY5_LOW,
EXCELLENT,
LOW
}
final category5Values = EnumValues({
"Beneficial": Category5.BENEFICIAL,
"Low\u000d\n": Category5.CATEGORY5_LOW,
"Excellent": Category5.EXCELLENT,
"Low": Category5.LOW
});
enum ColorName {
GREEN,
ORANGE,
RED
}
final colorNameValues = EnumValues({
"green": ColorName.GREEN,
"orange": ColorName.ORANGE,
"red": ColorName.RED
});
class EnumValues<T> {
Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
reverseMap = map.map((k, v) => MapEntry(v, k));
return reverseMap;
}
}

@ -0,0 +1,72 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/weather/models/waether_cities_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class WeatherRepo {
Future<Either<Failure, GenericApiModel<List<GetCityInfoList>>>> getCityInfo();
}
class WeatherRepoImp implements WeatherRepo {
final ApiClient apiClient;
final LoggerService loggerService;
WeatherRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<GetCityInfoList>>>> getCityInfo() async {
Map<String, dynamic> request = {};
try {
GenericApiModel<List<GetCityInfoList>>? apiResponse;
Failure? failure;
await apiClient.post(
WEATHER_INDICATOR,
body: request,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
loggerService.logInfo("Weather API Response: $response");
final list = response['GetCityInfo_List'];
if (list == null || list.isEmpty) {
loggerService.logInfo("Weather API returned empty or null list");
// Return empty list if no city info
apiResponse = GenericApiModel<List<GetCityInfoList>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: [],
);
return;
}
loggerService.logInfo("Parsing ${list.length} city info items");
final cityInfoList = list.map((item) => GetCityInfoList.fromJson(item as Map<String, dynamic>)).toList().cast<GetCityInfoList>();
apiResponse = GenericApiModel<List<GetCityInfoList>>(
messageStatus: messageStatus,
statusCode: statusCode,
errorMessage: null,
data: cityInfoList,
);
} catch (e) {
loggerService.logError("Error parsing weather data: $e");
failure = DataParsingFailure(e.toString());
}
},
);
if (failure != null) return Left(failure!);
if (apiResponse == null) return Left(ServerFailure("Unknown error"));
return Right(apiResponse!);
} catch (e) {
return Left(UnknownFailure(e.toString()));
}
}
}

@ -0,0 +1,55 @@
import 'package:flutter/cupertino.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/features/weather/models/waether_cities_model.dart';
import 'package:hmg_patient_app_new/features/weather/weather_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
class WeatherMonitorViewModel extends ChangeNotifier {
WeatherRepo weatherRepo;
ErrorHandlerService errorHandlerService;
LocationUtils locationUtils;
WeatherMonitorViewModel({required this.weatherRepo, required this.errorHandlerService, required this.locationUtils});
final List<GetCityInfoList> _cityInfoList = [];
bool isLoading = false;
List<GetCityInfoList> get cityInfoList => _cityInfoList;
Future<void> fetchCityInfoList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
isLoading = true;
_cityInfoList.clear();
locationUtils.getLocation(
isShowConfirmDialog: true,
onSuccess: (position) async {
final result = await weatherRepo.getCityInfo();
result.fold(
(failure) async {
isLoading = false;
notifyListeners();
await errorHandlerService.handleError(failure: failure);
if (onError != null) {
onError(failure.toString());
}
},
(apiResponse) {
isLoading = false;
if (apiResponse.messageStatus == 2) {
notifyListeners();
if (onError != null) {
onError(apiResponse.errorMessage ?? "Unknown error");
}
} else if (apiResponse.messageStatus == 1) {
final cities = apiResponse.data ?? [];
_cityInfoList.addAll(cities);
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
});
}
}

@ -10,6 +10,7 @@ import 'package:flutter/services.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/utils.dart';
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/features/ask_doctor/ask_doctor_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
@ -242,6 +243,9 @@ void main() async {
),
ChangeNotifierProvider<ServicesPriceListViewModel>(
create: (_) => getIt.get<ServicesPriceListViewModel>(),
) ,
ChangeNotifierProvider<WeatherMonitorViewModel>(
create: (_) => getIt.get<WeatherMonitorViewModel>(),
)
], child: MyApp()),
), // Wrap your app

@ -7,7 +7,6 @@ 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_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/calender_utils_new.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/penguin_method_channel.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
@ -196,11 +195,13 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
showCommonBottomSheetWithoutHeight(context,
child: Utils.getErrorWidget(loadingText: err.toString()),
callBackFunc: () {},
title: "", isCloseButtonVisible: true, isDismissible: false, isFullScreen: false);
title: "",
isCloseButtonVisible: true,
isDismissible: false,
isFullScreen: false);
});
}),
callBackFunc: () {},
@ -359,22 +360,24 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
],
),
SizedBox(height: 8.h),
bookAppointmentsViewModel.appointmentNearestGateResponseModel != null ? Wrap(
direction: Axis.horizontal,
spacing: 8.w,
runSpacing: 8.h,
children: [
AppCustomChipWidget(
labelText: bookAppointmentsVM.isAppointmentNearestGateLoading
? "Floor: Ground Floor"
bookAppointmentsViewModel.appointmentNearestGateResponseModel != null
? Wrap(
direction: Axis.horizontal,
spacing: 8.w,
runSpacing: 8.h,
children: [
AppCustomChipWidget(
labelText: bookAppointmentsVM.isAppointmentNearestGateLoading
? "Floor: Ground Floor"
: "${LocaleKeys.floor.tr(context: context)}: ${getIt.get<AppState>().isArabic() ? bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocationN : bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocation}",
).toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
AppCustomChipWidget(
labelText:
AppCustomChipWidget(
labelText:
"${LocaleKeys.nearestGate.tr(context: context)}: ${getIt.get<AppState>().isArabic() ? bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumberN : bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumber}")
.toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
],
) : SizedBox.shrink(),
],
)
: SizedBox.shrink(),
],
),
),
@ -405,53 +408,40 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
// activeTrackColor: AppColors.successColor.withValues(alpha: .15),
value: widget.patientAppointmentHistoryResponseModel.hasReminder!,
onChanged: (newValue) async {
CalenderUtilsNew calender = CalenderUtilsNew.instance;
bool isEventAddedOrRemoved = false;
if(newValue == true){
DateTime startDate = DateTime.now();
DateTime endDate = DateUtil.convertStringToDate(widget
.patientAppointmentHistoryResponseModel.appointmentDate);
BottomSheetUtils().showReminderBottomSheet(
context,
endDate,
widget.patientAppointmentHistoryResponseModel.doctorNameObj??"",
"${widget.patientAppointmentHistoryResponseModel.appointmentNo}"??"",
"",
"",
title: "Appointment with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj}",
description:
"${widget.patientAppointmentHistoryResponseModel.doctorNameObj} will be having an appointment on ${widget.patientAppointmentHistoryResponseModel.appointmentDate}",
onSuccess: () {
setState(() {
myAppointmentsViewModel.setAppointmentReminder(newValue, widget.patientAppointmentHistoryResponseModel);
});
},
isMultiAllowed: true,
onMultiDateSuccess: (int selectedIndex) async {
isEventAddedOrRemoved = await calender.createOrUpdateEvent(
title:
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} on ${DateUtil.convertStringToDate(widget.patientAppointmentHistoryResponseModel.appointmentDate)}, Appointment #${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
description:
"Appointment Reminder with ${widget.patientAppointmentHistoryResponseModel.doctorNameObj} in ${widget.patientAppointmentHistoryResponseModel.projectName}",
scheduleDateTime: DateUtil.convertStringToDate(widget
.patientAppointmentHistoryResponseModel.appointmentDate),
eventId: "${widget.patientAppointmentHistoryResponseModel.appointmentNo}",
location: '',
reminderMinutes: selectedIndex
);
setState(() {
myAppointmentsViewModel.setAppointmentReminder(isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
},
);
}else {
isEventAddedOrRemoved = await calender.checkAndRemove( id:"${widget.patientAppointmentHistoryResponseModel.appointmentNo}", );
setState(() {
myAppointmentsViewModel.setAppointmentReminder(!isEventAddedOrRemoved, widget.patientAppointmentHistoryResponseModel);
});
}
await myAppointmentsViewModel.toggleReminder(
context: context,
shouldCreateReminder: newValue,
patientAppointmentHistoryResponseModel: widget.patientAppointmentHistoryResponseModel,
onSuccess: (result) {
showCommonBottomSheet(
context,
child: Utils.getSuccessWidget(
loadingText: newValue ? LocaleKeys.reminderSuccess.tr(context: context) : LocaleKeys.reminderCancelSuccess.tr(context: context),
),
callBackFunc: (str) {},
title: "",
isCloseButtonVisible: false,
isDismissible: true,
isFullScreen: false,
isAutoDismiss: true,
height: ResponsiveExtension.screenHeight * 0.3,
);
},
onError: (error) {
setState(() {
// Revert the switch if there was an error
widget.patientAppointmentHistoryResponseModel.hasReminder = !newValue;
});
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.notice.tr(context: context),
child: Utils.getErrorWidget(loadingText: error),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
},
),
],
@ -471,106 +461,116 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
),
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
shrinkWrap: true,
children: [
MedicalFileCard(
label: LocaleKeys.labResults.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.lab_result_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingLabResults.tr(context: context));
await labViewModel.getLabResultsByAppointmentNo(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
doctorName: widget.patientAppointmentHistoryResponseModel.doctorNameObj!,
clinicName: widget.patientAppointmentHistoryResponseModel.clinicName!,
projectName: widget.patientAppointmentHistoryResponseModel.projectName!,
appointmentDate: widget.patientAppointmentHistoryResponseModel.appointmentDate!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
}),
MedicalFileCard(
label: "${LocaleKeys.radiology.tr(context: context)} ${LocaleKeys.radiologySubtitle.tr(context: context)}",
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.radiology_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingRadiologyResults.tr(context: context));
await radiologyViewModel.getPatientRadiologyOrdersByAppointment(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
}),
MedicalFileCard(
label: LocaleKeys.prescriptions.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.prescription_item_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentPrescriptions.tr(context: context));
await prescriptionsViewModel.getPrescriptionDetails(
getPrescriptionRequestModel(),
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (val.data.isNotEmpty) {
PatientPrescriptionsResponseModel patientPrescriptionsResponseModel = PatientPrescriptionsResponseModel(
doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL,
doctorName: widget.patientAppointmentHistoryResponseModel.doctorNameObj,
appointmentDate: widget.patientAppointmentHistoryResponseModel.appointmentDate,
clinicDescription: widget.patientAppointmentHistoryResponseModel.clinicName,
decimalDoctorRate: widget.patientAppointmentHistoryResponseModel.decimalDoctorRate,
name: widget.patientAppointmentHistoryResponseModel.projectName,
isHomeMedicineDeliverySupported: val.data.first.isHomeMedicineDeliverySupported ?? false,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
setupID: widget.patientAppointmentHistoryResponseModel.setupID,
isInOutPatient: widget.patientAppointmentHistoryResponseModel.isInOutPatient,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
episodeID: widget.patientAppointmentHistoryResponseModel.episodeID,
dischargeNo: 0,
shrinkWrap: true,
children: [
MedicalFileCard(
label: LocaleKeys.labResults.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.lab_result_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingLabResults.tr(context: context));
await labViewModel.getLabResultsByAppointmentNo(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
doctorName: widget.patientAppointmentHistoryResponseModel.doctorNameObj!,
clinicName: widget.patientAppointmentHistoryResponseModel.clinicName!,
projectName: widget.patientAppointmentHistoryResponseModel.projectName!,
appointmentDate: widget.patientAppointmentHistoryResponseModel.appointmentDate!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
Navigator.of(context).push(
CustomPageRoute(
page: PrescriptionDetailPage(
isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel),
),
},
);
}),
MedicalFileCard(
label: "${LocaleKeys.radiology.tr(context: context)} ${LocaleKeys.radiologySubtitle.tr(context: context)}",
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.radiology_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingRadiologyResults.tr(context: context));
await radiologyViewModel.getPatientRadiologyOrdersByAppointment(
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
} else {
},
);
}),
MedicalFileCard(
label: LocaleKeys.prescriptions.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.prescription_item_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() async {
LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointmentPrescriptions.tr(context: context));
await prescriptionsViewModel.getPrescriptionDetails(
getPrescriptionRequestModel(),
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
if (val.data.isNotEmpty) {
PatientPrescriptionsResponseModel patientPrescriptionsResponseModel = PatientPrescriptionsResponseModel(
doctorImageURL: widget.patientAppointmentHistoryResponseModel.doctorImageURL,
doctorName: widget.patientAppointmentHistoryResponseModel.doctorNameObj,
appointmentDate: widget.patientAppointmentHistoryResponseModel.appointmentDate,
clinicDescription: widget.patientAppointmentHistoryResponseModel.clinicName,
decimalDoctorRate: widget.patientAppointmentHistoryResponseModel.decimalDoctorRate,
name: widget.patientAppointmentHistoryResponseModel.projectName,
isHomeMedicineDeliverySupported: val.data.first.isHomeMedicineDeliverySupported ?? false,
projectID: widget.patientAppointmentHistoryResponseModel.projectID,
clinicID: widget.patientAppointmentHistoryResponseModel.clinicID,
doctorID: widget.patientAppointmentHistoryResponseModel.doctorID,
setupID: widget.patientAppointmentHistoryResponseModel.setupID,
isInOutPatient: widget.patientAppointmentHistoryResponseModel.isInOutPatient,
appointmentNo: widget.patientAppointmentHistoryResponseModel.appointmentNo,
episodeID: widget.patientAppointmentHistoryResponseModel.episodeID,
dischargeNo: 0,
);
Navigator.of(context).push(
CustomPageRoute(
page: PrescriptionDetailPage(isFromAppointments: true, prescriptionsResponseModel: patientPrescriptionsResponseModel),
),
);
} else {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
}
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr(context: context)),
@ -578,40 +578,29 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
isFullScreen: false,
isCloseButtonVisible: true,
);
}
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: LocaleKeys.noPrescriptionsForAppointment.tr(context: context)),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
);
// Navigator.of(context).push(
// CustomPageRoute(
// page: VaccineListPage(),
// ),
// );
}),
MedicalFileCard(
label: LocaleKeys.doctorResponses.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.ask_doctor_medical_file_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() {
getIt.get<AskDoctorViewModel>().initAskDoctorViewModel();
getIt.get<AskDoctorViewModel>().getDoctorResponses();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorResponsePage(),
),
);
},
);
// Navigator.of(context).push(
// CustomPageRoute(
// page: VaccineListPage(),
// ),
// );
}),
MedicalFileCard(
label: LocaleKeys.doctorResponses.tr(context: context),
textColor: AppColors.blackColor,
backgroundColor: AppColors.whiteColor,
svgIcon: AppAssets.ask_doctor_medical_file_icon,
isLargeText: true,
iconSize: 36.w,
).onPress(() {
getIt.get<AskDoctorViewModel>().initAskDoctorViewModel();
getIt.get<AskDoctorViewModel>().getDoctorResponses();
Navigator.of(context).push(
CustomPageRoute(
page: DoctorResponsePage(),
),
);
}),
myAppointmentsVM.isAppointmentRatedResponseLoading
? MedicalFileCard(
@ -882,8 +871,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 ||
widget.patientAppointmentHistoryResponseModel.nextAction == 20)
if (widget.patientAppointmentHistoryResponseModel.nextAction == 15 || widget.patientAppointmentHistoryResponseModel.nextAction == 20)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -891,10 +879,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleKeys.amountBeforeTax.tr(context: context).toText18(isBold: true),
Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true),
AppColors.blackColor,
13,
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShare!.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
),
@ -902,9 +887,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: LocaleKeys.upcomingPaymentNow
.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
Expanded(child: LocaleKeys.upcomingPaymentNow.tr(context: context).toText12(isBold: true, color: AppColors.greyTextColor)),
"VAT 15%(${widget.patientAppointmentHistoryResponseModel.patientTaxAmount})".toText14(isBold: true, color: AppColors.greyTextColor, letterSpacing: -0.64),
],
),
@ -919,10 +902,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Utils.getPaymentAmountWithSymbol(
widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true),
AppColors.blackColor,
17,
Utils.getPaymentAmountWithSymbol(widget.patientAppointmentHistoryResponseModel.patientShareWithTax!.toString().toText24(isBold: true), AppColors.blackColor, 17,
isSaudiCurrency: true),
],
),
@ -945,11 +925,11 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
borderColor: AppColors.primaryRedColor,
textColor: Colors.white,
fontSize: 16.f,
fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h,
icon: AppAssets.add_icon,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 50.h,
icon: AppAssets.add_icon,
iconColor: Colors.white,
iconSize: 18.h,
).paddingSymmetrical(16.h, 24.h)
@ -959,8 +939,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
handleAppointmentNextAction(widget.patientAppointmentHistoryResponseModel.nextAction);
},
backgroundColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction),
borderColor:
AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
borderColor: AppointmentType.getNextActionButtonColor(widget.patientAppointmentHistoryResponseModel.nextAction).withOpacity(0.01),
textColor: widget.patientAppointmentHistoryResponseModel.nextAction == 15 ? AppColors.textColor : Colors.white,
fontSize: 16.f,
fontWeight: FontWeight.w600,
@ -1121,8 +1100,7 @@ class _AppointmentDetailsPageState extends State<AppointmentDetailsPage> {
myAppointmentsViewModel.initAppointmentsViewModel();
myAppointmentsViewModel.getPatientAppointments(true, false);
Navigator.of(context).pop();
}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isAutoDismiss: true, isCloseButtonVisible: true, isDismissible: false, isFullScreen: false,
isSuccessDialog: true);
}, title: "", height: ResponsiveExtension.screenHeight * 0.3, isAutoDismiss: true, isCloseButtonVisible: true, isDismissible: false, isFullScreen: false, isSuccessDialog: true);
});
// LoaderBottomSheet.hideLoader();
case 15:

@ -90,12 +90,14 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
.toString()
.toText16(isBold: true, maxlines: 1),
SizedBox(width: 12.w),
(bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL != null && bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL!.isNotEmpty )? Image.network(
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
width: 20.h,
height: 15.h,
fit: BoxFit.cover,
) : SizedBox.shrink(),
(bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL != null && bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL!.isNotEmpty)
? Image.network(
bookAppointmentsViewModel.selectedDoctor.nationalityFlagURL ?? "https://hmgwebservices.com/Images/flag/SAU.png",
width: 20.h,
height: 15.h,
fit: BoxFit.cover,
)
: SizedBox.shrink(),
],
),
SizedBox(height: 2.h),
@ -162,7 +164,9 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
runSpacing: 4.h,
children: [
AppCustomChipWidget(labelText: "${appState.getAuthenticatedUser()!.age} ${LocaleKeys.yearsOld.tr(context: context)}"),
AppCustomChipWidget(labelText: "${LocaleKeys.gender.tr(context: context)}: ${appState.getAuthenticatedUser()?.gender == 1 ? LocaleKeys.malE.tr(context: context) : LocaleKeys.femaleGender.tr(context: context)}"),
AppCustomChipWidget(
labelText:
"${LocaleKeys.gender.tr(context: context)}: ${appState.getAuthenticatedUser()?.gender == 1 ? LocaleKeys.malE.tr(context: context) : LocaleKeys.femaleGender.tr(context: context)}"),
],
),
],
@ -191,19 +195,19 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
bookAppointmentsViewModel.appointmentNearestGateResponseModel != null
? Wrap(
direction: Axis.horizontal,
spacing: 8.w,
runSpacing: 8.h,
children: [
AppCustomChipWidget(
labelText: bookAppointmentsVM.isAppointmentNearestGateLoading
? "Floor: Ground Floor"
spacing: 8.w,
runSpacing: 8.h,
children: [
AppCustomChipWidget(
labelText: bookAppointmentsVM.isAppointmentNearestGateLoading
? "Floor: Ground Floor"
: "${LocaleKeys.floor.tr(context: context)} ${getIt.get<AppState>().isArabic() ? bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocationN : bookAppointmentsViewModel.appointmentNearestGateResponseModel!.clinicLocation}",
).toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
AppCustomChipWidget(
labelText:
AppCustomChipWidget(
labelText:
"${LocaleKeys.nearestGate.tr(context: context)} ${getIt.get<AppState>().isArabic() ? bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumberN : bookAppointmentsVM.appointmentNearestGateResponseModel!.nearestGateNumber}")
.toShimmer2(isShow: bookAppointmentsVM.isAppointmentNearestGateLoading),
],
],
)
: SizedBox.shrink(),
],
@ -329,23 +333,16 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
// LoaderBottomSheet.showLoader(loadingText: LocaleKeys.appointmentSuccess.tr());
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()),
callBackFunc: () {
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(false);
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
},
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()), callBackFunc: () {
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(false);
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
}, isFullScreen: false, isCloseButtonVisible: false, isAutoDismiss: true);
});
});
} else {
@ -368,23 +365,48 @@ class _ReviewAppointmentPageState extends State<ReviewAppointmentPage> {
}, onSuccess: (apiResp) async {
LoaderBottomSheet.hideLoader();
await Future.delayed(Duration(milliseconds: 50)).then((value) async {
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h),
callBackFunc: () {
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(false);
Navigator.pushAndRemoveUntil(
context,
CustomPageRoute(
page: LandingNavigation(),
),
(r) => false);
showCommonBottomSheetWithoutHeight(context, child: Utils.getSuccessWidget(loadingText: LocaleKeys.appointmentSuccess.tr()).paddingSymmetrical(0.h, 24.h), callBackFunc: () async {
bookAppointmentsViewModel.setIsLiveCareSchedule(false);
bookAppointmentsViewModel.setIsPatientRescheduleAppointment(false);
bool newValue = true;
await myAppointmentsViewModel.toggleReminder(
context: context,
shouldCreateReminder: newValue,
patientAppointmentHistoryResponseModel: apiResp.patientAppointmentHistoryResponseModel,
onSuccess: (result) {
showCommonBottomSheet(
context,
child: Utils.getSuccessWidget(
loadingText: newValue ? LocaleKeys.reminderSuccess.tr(context: context) : LocaleKeys.reminderCancelSuccess.tr(context: context),
),
callBackFunc: (str) {
Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
},
title: "",
isCloseButtonVisible: false,
isDismissible: true,
isFullScreen: false,
isAutoDismiss: true,
height: ResponsiveExtension.screenHeight * 0.3,
);
},
onError: (error) {
setState(() {
apiResp.patientAppointmentHistoryResponseModel.hasReminder = !newValue;
});
showCommonBottomSheetWithoutHeight(
context,
title: LocaleKeys.notice.tr(context: context),
child: Utils.getErrorWidget(loadingText: error),
callBackFunc: () {
Navigator.pushAndRemoveUntil(context, CustomPageRoute(page: LandingNavigation()), (r) => false);
},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
isFullScreen: false,
isCloseButtonVisible: false,
isAutoDismiss: true
);
);
}, isFullScreen: false, isCloseButtonVisible: false, isAutoDismiss: true);
});
});
}

@ -6,6 +6,7 @@ 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';
import 'package:hmg_patient_app_new/core/enums.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
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/string_extensions.dart';
@ -19,6 +20,7 @@ import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/hmg_s
import 'package:hmg_patient_app_new/features/hospital/hospital_selection_view_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_model.dart';
import 'package:hmg_patient_app_new/features/weather/weather_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/blood_donation_page.dart';
import 'package:hmg_patient_app_new/presentation/book_appointment/book_appointment_page.dart';
@ -47,47 +49,46 @@ import '../../core/dependencies.dart' show getIt;
import '../../features/qr_parking/qr_parking_view_model.dart';
import '../emergency_services/call_ambulance/widgets/HospitalBottomSheetBody.dart';
class ServicesPage extends StatelessWidget {
class ServicesPage extends StatefulWidget {
bool showBackIcon;
ServicesPage({super.key, this.showBackIcon = true});
@override
State<ServicesPage> createState() => _ServicesPageState();
}
class _ServicesPageState extends State<ServicesPage> {
late BloodDonationViewModel bloodDonationViewModel;
late MedicalFileViewModel medicalFileViewModel;
late WeatherMonitorViewModel weatherVM;
late final List<HmgServicesComponentModel> hmgServices = [
HmgServicesComponentModel(11, LocaleKeys.emergencyServices.tr(), "", AppAssets.emergency_services_icon, bgColor: AppColors.primaryRedColor, true, route: null, onTap: () async {
// if (getIt.get<AppState>().isAuthenticated) {
// getIt.get<EmergencyServicesViewModel>().flushData();
// getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
// showLoader: false,
// );
// getIt.get<EmergencyServicesViewModel>().getRRTOrders(
// showLoader: false,
// );
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
),
);
// getIt.get<EmergencyServicesViewModel>().flushData();
// getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
// showLoader: false,
// );
// getIt.get<EmergencyServicesViewModel>().getRRTOrders(
// showLoader: false,
// );
Navigator.of(getIt.get<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
),
);
// } else {
// await getIt.get<AuthenticationViewModel>().onLoginPressed();
// }
}),
HmgServicesComponentModel(
11,
LocaleKeys.bookAppointment.tr(),
"",
AppAssets.appointment_calendar_icon,
bgColor: AppColors.bookAppointment,
true,
route: null,
onTap: () {
getIt.get<BookAppointmentsViewModel>().onTabChanged(0);
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(CustomPageRoute(page: BookAppointmentPage()));
}
),
HmgServicesComponentModel(11, LocaleKeys.bookAppointment.tr(), "", AppAssets.appointment_calendar_icon, bgColor: AppColors.bookAppointment, true, route: null, onTap: () {
getIt.get<BookAppointmentsViewModel>().onTabChanged(0);
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(CustomPageRoute(page: BookAppointmentPage()));
}),
HmgServicesComponentModel(5, LocaleKeys.completeCheckup.tr(), "", AppAssets.comprehensiveCheckup, bgColor: AppColors.bgGreenColor, true, route: null, onTap: () async {
if (getIt.get<AppState>().isAuthenticated) {
getIt.get<NavigationService>().pushPageRoute(AppRoutes.comprehensiveCheckupPage);
@ -164,33 +165,31 @@ class ServicesPage extends StatelessWidget {
}
}),
HmgServicesComponentModel(
3,
LocaleKeys.bloodDonation.tr(context: getIt.get<NavigationService>().navigatorKey.currentContext!),
"".needTranslation,
AppAssets.blood_donation_icon,
bgColor: AppColors.bloodDonationCardColor,
true,
route: null,
onTap: () {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: BloodDonationPage(),
),
);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.bloodDonation.tr(),
serviceHeader: LocaleKeys.bloodDonationServiceHeader.tr(),
serviceDescription: LocaleKeys.bloodDonationServiceDescription.tr(),
serviceImage: AppAssets.bloodDonationService),
),
);
}
3,
LocaleKeys.bloodDonation.tr(context: getIt.get<NavigationService>().navigatorKey.currentContext!),
"".needTranslation,
AppAssets.blood_donation_icon,
bgColor: AppColors.bloodDonationCardColor,
true,
route: null, onTap: () {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: BloodDonationPage(),
),
);
} else {
Navigator.of(getIt<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: ServiceInfoPage(
serviceName: LocaleKeys.bloodDonation.tr(),
serviceHeader: LocaleKeys.bloodDonationServiceHeader.tr(),
serviceDescription: LocaleKeys.bloodDonationServiceDescription.tr(),
serviceImage: AppAssets.bloodDonationService),
),
);
}
),
}),
HmgServicesComponentModel(
113,
LocaleKeys.servicePriceList.tr(context: getIt.get<NavigationService>().navigatorKey.currentContext!),
@ -375,21 +374,100 @@ class ServicesPage extends StatelessWidget {
),
];
@override
void initState() {
// TODO: implement initState
super.initState();
weatherVM = getIt<WeatherMonitorViewModel>();
weatherVM.fetchCityInfoList();
}
@override
Widget build(BuildContext context) {
bloodDonationViewModel = Provider.of<BloodDonationViewModel>(context);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context);
hmgServices.removeWhere((element) => Utils.havePrivilege(element.action) == false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: CollapsingListView(
title: LocaleKeys.exploreServices.tr(),
isLeading: showBackIcon,
isLeading: widget.showBackIcon,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Flexible(
child: Container(
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false),
child: Column(
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: "assets/images/svg/cloudyweather.svg", width: 64.w, height: 64.w).onPress(() {
// locationUtils?.getCurrentLocation();
print(getIt.get<AppState>().userLat);
print(getIt.get<AppState>().userLong);
}),
SizedBox(width: 12.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"August 19, 2025 - Tuesday, 11:25 ".toText12(fontWeight: FontWeight.w500, color: AppColors.greyTextColor),
SizedBox(
height: 4.w,
),
"Cloudy 38oC".toText16(isBold: true, weight: FontWeight.w600),
SizedBox(
height: 4.w,
),
"Health tips based on current weather".toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w500)
],
),
],
),
SizedBox(height: 16.w),
Container(
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.lightGrayBGColor,
borderRadius: 10.r,
hasShadow: false,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Utils.buildSvgWithAssets(icon: "assets/images/svg/morning.svg", width: 24.w, height: 24.h),
SizedBox(width: 4.w),
DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true),
],
),
SizedBox(width: 25.w),
DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true),
SizedBox(width: 25.w),
Row(
children: [
Utils.buildSvgWithAssets(icon: "assets/images/svg/evening.svg", width: 24.w, height: 24.h),
SizedBox(width: 4.w),
DateTime.now().toLocal().toString().substring(11, 16).toText14(isBold: true),
],
),
],
).expanded,
).paddingSymmetrical(0.w, 8.w)
],
),
),
)
],
).paddingSymmetrical(24.w, 0.w),
SizedBox(height: 16.h),
LocaleKeys.medicalAndCareServices.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),
@ -440,173 +518,176 @@ class ServicesPage extends StatelessWidget {
),
),
SizedBox(height: 24.h),
getIt.get<AppState>().isAuthenticated ? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.personalServices.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.habibWallet.tr().toText14(isBold: true, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(num.parse(NumberFormat.decimalPattern().format(habibWalletVM.habibWalletAmount)), isExpanded: false, letterSpacing: -1)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h);
})
: LocaleKeys.loginToViewWalletBalance.tr().toText12(isBold: true, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.recharge_icon,
iconSize: 24.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
isBold: true,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage()));
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
SizedBox(width: 16.w),
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.services_medical_file_icon, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.medicalFile.tr().toText16(isBold: true, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
getIt.get<AppState>().isAuthenticated
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.personalServices.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),
Row(
children: [
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.wallet, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.habibWallet.tr().toText14(isBold: true, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Consumer<HabibWalletViewModel>(builder: (context, habibWalletVM, child) {
return Utils.getPaymentAmountWithSymbol2(num.parse(NumberFormat.decimalPattern().format(habibWalletVM.habibWalletAmount)),
isExpanded: false, letterSpacing: -1)
.toShimmer2(isShow: habibWalletVM.isWalletAmountLoading, radius: 12.r, width: 80.w, height: 24.h);
})
: LocaleKeys.loginToViewWalletBalance.tr().toText12(isBold: true, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.recharge_icon,
iconSize: 24.w,
iconColor: AppColors.infoColor,
textColor: AppColors.infoColor,
text: LocaleKeys.recharge.tr(),
borderWidth: 0.w,
isBold: true,
borderColor: Colors.transparent,
backgroundColor: Color(0xff45A2F8).withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
Navigator.of(context).push(CustomPageRoute(page: RechargeWalletPage()));
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(CustomPageRoute(page: HabibWalletPage()));
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Wrap(
spacing: -12.h,
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 32.h,
width: 32.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
)
: LocaleKeys.loginToViewMedicalFile.tr().toText12(isBold: true, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.add_icon,
iconSize: 24.h,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
isBold: true,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: MedicalFilePage(),
),
SizedBox(width: 16.w),
Expanded(
child: Container(
height: 183.h,
width: 183.h,
padding: EdgeInsets.all(16.w),
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.r,
hasShadow: false,
),
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
],
).paddingSymmetrical(24.w, 0),
],
) : SizedBox(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
spacing: 8.w,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.services_medical_file_icon, width: 40.w, height: 40.h, applyThemeColor: false),
LocaleKeys.medicalFile.tr().toText16(isBold: true, maxlines: 2).expanded,
Utils.buildSvgWithAssets(icon: getIt.get<AppState>().isArabic() ? AppAssets.arrow_back : AppAssets.arrow_forward),
],
),
Spacer(),
getIt.get<AppState>().isAuthenticated
? Wrap(
spacing: -12.h,
// runSpacing: 0.h,
children: [
Utils.buildImgWithAssets(
icon: AppAssets.babyGirlImg,
height: 32.h,
width: 32.w,
border: 1,
fit: BoxFit.contain,
borderRadius: 50.r,
),
Utils.buildImgWithAssets(
icon: AppAssets.femaleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
Utils.buildImgWithAssets(
icon: AppAssets.maleImg,
height: 32.h,
width: 32.w,
border: 1,
borderRadius: 50.r,
fit: BoxFit.contain,
),
],
)
: LocaleKeys.loginToViewMedicalFile.tr().toText12(isBold: true, maxLine: 2),
Spacer(),
getIt.get<AppState>().isAuthenticated
? CustomButton(
height: 40.h,
icon: AppAssets.add_icon,
iconSize: 24.h,
iconColor: AppColors.primaryRedColor,
textColor: AppColors.primaryRedColor,
text: LocaleKeys.addMember.tr(),
borderWidth: 0.w,
isBold: true,
borderColor: Colors.transparent,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.08),
padding: EdgeInsets.all(8.w),
fontSize: 14.f,
onPressed: () {
DialogService dialogService = getIt.get<DialogService>();
medicalFileViewModel.clearAuthValues();
dialogService.showAddFamilyFileSheet(
label: LocaleKeys.addFamilyMember.tr(),
message: LocaleKeys.pleaseFillBelowFieldToAddNewFamilyMember.tr(),
onVerificationPress: () {
medicalFileViewModel.addFamilyFile(otpTypeEnum: OTPTypeEnum.sms);
});
},
)
: SizedBox.shrink(),
],
).onPress(() async {
if (getIt.get<AppState>().isAuthenticated) {
Navigator.of(context).push(
CustomPageRoute(
page: MedicalFilePage(),
),
);
} else {
await getIt.get<AuthenticationViewModel>().onLoginPressed();
}
}),
),
),
],
).paddingSymmetrical(24.w, 0),
],
)
: SizedBox(),
SizedBox(height: 24.h),
LocaleKeys.healthTools.tr().toText18(isBold: true).paddingSymmetrical(24.w, 0),
SizedBox(height: 16.h),

Loading…
Cancel
Save