Compare commits

...

6 Commits

Author SHA1 Message Date
khansultan1 ba0a2a2a58 Merge pull request 'dev_sultan' (#290) from dev_sultan into master
Reviewed-on: #290
12 hours ago
Sultan khan caa9da2cce Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan
# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/generated/locale_keys.g.dart
#	lib/presentation/book_appointment/livecare/immediate_livecare_payment_details.dart
12 hours ago
Sultan khan efa7a39978 no message 12 hours ago
Sultan khan e70f7aa7e3 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 15 hours ago
Sultan khan 46fda4e59d Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 19 hours ago
Sultan khan 41f971fd01 Merge branch 'master' of http://34.17.182.140/Haroon6138/HMG_Patient_App_New into dev_sultan 20 hours ago

@ -1808,7 +1808,7 @@
"followUsOn": "تابعنا على:", "followUsOn": "تابعنا على:",
"followUsOnX": "تابعنا على X", "followUsOnX": "تابعنا على X",
"likeUsOnFB": "سجل إعجابك بنا على فيسبوك", "likeUsOnFB": "سجل إعجابك بنا على فيسبوك",
"watchUsOnYoutube": "شاهدنا على إنستغرام", "watchUsOnYoutube": "شاهدنا على يوتيوب",
"connectOnLinkedin": "تواصل معنا على لينكد إن", "connectOnLinkedin": "تواصل معنا على لينكد إن",
"riskFactorPageTitle": "اعراض تشعر بها", "riskFactorPageTitle": "اعراض تشعر بها",
"bloodDonationService": "التبرع \n بالدم", "bloodDonationService": "التبرع \n بالدم",
@ -1827,4 +1827,15 @@
"ancillaryOrdersListNew": "طلبات غير مكتملة", "ancillaryOrdersListNew": "طلبات غير مكتملة",
"medicalReportNew": "التقارير الطبية", "medicalReportNew": "التقارير الطبية",
"livecarePendingReuqestNew": "انتظار الطبيب" "livecarePendingReuqestNew": "انتظار الطبيب"
"medicinesAnalysis": "تحليل الأدوية",
"importantWarnings": "تحذيرات مهمة",
"medicineInteractions": "تفاعلات الأدوية",
"followUpNeeded": "المتابعة المطلوبة",
"benefit": "الفائدة",
"commonSideEffects": "الآثار الجانبية الشائعة",
"seriousWarnings": "تحذيرات خطيرة",
"storage": "التخزين",
"aiDisclaimerPrescription": "سيتم مشاركة بيانات نتائج الوصفات الطبية الخاصة بك بشكل آمن مع محلل الذكاء الاصطناعي لدينا لتحليلها. يساعد هذا في توفير رؤى صحية مخصصة. هل ترغب في المتابعة؟",
"generateAiAnalysisPrescription": "تحليل الذكاء الاصطناعي",
"loadingAIAnalysisPrescription": "ٍتحليل الوصفات الطبية بواسطة الذكاء الاصطناعي، يرجى الانتظار..."
} }

@ -1798,7 +1798,7 @@
"followUsOn": "Follow us on:", "followUsOn": "Follow us on:",
"followUsOnX": "Follow us \n on X", "followUsOnX": "Follow us \n on X",
"likeUsOnFB": "Like us on Facebook", "likeUsOnFB": "Like us on Facebook",
"watchUsOnYoutube": "Watch us on Instagram", "watchUsOnYoutube": "Watch us on youtube",
"connectOnLinkedin": "Connect on LinkedIn", "connectOnLinkedin": "Connect on LinkedIn",
"riskFactorPageTitle": "What do you feel?", "riskFactorPageTitle": "What do you feel?",
"bloodDonationService": "Blood Donation", "bloodDonationService": "Blood Donation",
@ -1817,6 +1817,17 @@
"ancillaryOrdersListNew": "Ancillary Orders List", "ancillaryOrdersListNew": "Ancillary Orders List",
"medicalReportNew": "Medical Report", "medicalReportNew": "Medical Report",
"livecarePendingReuqestNew": "Live Care Pending Request" "livecarePendingReuqestNew": "Live Care Pending Request"
"medicinesAnalysis": "Medicines Analysis",
"importantWarnings": "Important Warnings",
"medicineInteractions": "Medicine Interactions",
"followUpNeeded": "Follow-up Needed",
"benefit": "Benefit",
"commonSideEffects": "Common Side Effects",
"seriousWarnings": "Serious Warnings",
"storage": "Storage",
"aiDisclaimerPrescription": "Your prescription data will be securely shared with our AI Analyzer for analysis. This helps provide personalized health insights. Do you want to proceed?",
"generateAiAnalysisPrescription": "Generate AI analysis for this prescription",
"loadingAIAnalysisPrescription": "Analysing your prescription, let the AI do the magic, This might take some time."
} }

@ -242,6 +242,7 @@ class ApiConsts {
static String getAiRadiologyAnalysis = "$getAiAnalysisURL/radiology"; static String getAiRadiologyAnalysis = "$getAiAnalysisURL/radiology";
static String getAiOverViewLabOrdersNew = "$getAiAnalysisURL/analyze_lab_orders"; static String getAiOverViewLabOrdersNew = "$getAiAnalysisURL/analyze_lab_orders";
static String getAiOverViewLabOrderNew = "$getAiAnalysisURL/analyze"; static String getAiOverViewLabOrderNew = "$getAiAnalysisURL/analyze";
static String getAiPrescriptionAnalysis = "$getAiAnalysisURL/prescription_analysis";
static String googleCloudStorageARTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/ar-SA.json"; static String googleCloudStorageARTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/ar-SA.json";
static String googleCloudStorageENTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/en-US.json"; static String googleCloudStorageENTranslationFileURL = "https://storage.googleapis.com/hmg-patientapp-translations/en-US.json";

@ -118,6 +118,7 @@ class CalenderUtilsNew {
FutureOr<bool> createMultipleEvents({ FutureOr<bool> createMultipleEvents({
required int reminderMinutes, required int reminderMinutes,
int? frequencyNumber, int? frequencyNumber,
num scaleOffset = 24,
required int days, required int days,
required String orderDate, required String orderDate,
required String itemDescriptionN, required String itemDescriptionN,
@ -128,8 +129,20 @@ class CalenderUtilsNew {
}) async { }) async {
DateTime startTimeOfDay = scheduleDateTime ?? DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0); DateTime startTimeOfDay = scheduleDateTime ?? DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 8, 0);
print("the frequency is $frequencyNumber"); print("the frequency is $frequencyNumber");
print("the scaleOffset is $scaleOffset");
frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2 frequencyNumber ??= 2; //Some time frequency number is null so by default will be 2
int interval = calculateIntervalAsPerFrequency(frequencyNumber);
// Calculate interval between doses in hours
int intervalBetweenDoses = calculateIntervalAsPerFrequency(frequencyNumber, scaleOffset);
// Calculate interval between cycles (days between each set of doses)
// scaleOffset represents hours in one cycle (e.g., 24 for daily, 168 for weekly)
int daysPerCycle = (scaleOffset / 24).ceil(); // 168 / 24 = 7 days
print("Interval between doses: $intervalBetweenDoses hours");
print("Days per cycle: $daysPerCycle");
// Calculate remaining days based on prescription days and order date // Calculate remaining days based on prescription days and order date
DateTime orderDateTime = DateUtil.convertStringToDate(orderDate); DateTime orderDateTime = DateUtil.convertStringToDate(orderDate);
@ -144,30 +157,43 @@ class CalenderUtilsNew {
bool statusOfOperation = false; bool statusOfOperation = false;
for (int i = 0; i < remainingDays; i++) { // Calculate number of cycles (e.g., for weekly medication over 90 days = ~13 weeks)
// Reset to the original time for each new day int numberOfCycles = (remainingDays / daysPerCycle).ceil(); // 90 / 7 = 13 cycles
DateTime actualDate = startTimeOfDay.add(Duration(days: i));
print("Number of cycles: $numberOfCycles");
print("Remaining days: $remainingDays");
// Iterate through each cycle (daily, weekly, etc.)
for (int i = 0; i < numberOfCycles; i++) { // Loops 13 times (weekly)
DateTime cycleStartDate = startTimeOfDay.add(Duration(days: i * daysPerCycle)); // Adds 7 days each time
// Check if this cycle is still within the prescription period
if (cycleStartDate.difference(orderDateTime).inDays > days) {
break; // Stop if we've exceeded the prescription duration
}
DateTime actualDate = cycleStartDate;
//event for number of days (frequency per day) // Create events for each dose in this cycle (frequency per cycle)
for (int j = 0; j < frequencyNumber; j++) { for (int j = 0; j < frequencyNumber; j++) {
statusOfOperation = await createOrUpdateEvent( statusOfOperation = await createOrUpdateEvent(
title: "$itemDescriptionN Medication about to due for prescription, #$prescriptionNumber", title: "$itemDescriptionN Medication about to due for prescription, #$prescriptionNumber",
description: "$itemDescriptionN $frequencyNumber $route ", description: "$itemDescriptionN $frequencyNumber $route ",
scheduleDateTime: actualDate, scheduleDateTime: actualDate,
location: '', location: '',
//event id with variations
reminderMinutes: reminderMinutes); reminderMinutes: reminderMinutes);
if (!statusOfOperation) return false; if (!statusOfOperation) return false;
actualDate = actualDate.add(Duration(hours: interval)); // Add interval between doses (in hours)
actualDate = actualDate.add(Duration(hours: intervalBetweenDoses));
} }
} }
return statusOfOperation; return statusOfOperation;
} }
int calculateIntervalAsPerFrequency(int frequencyNumber) { int calculateIntervalAsPerFrequency(int frequencyNumber, num scaleOffset) {
return 24 ~/ frequencyNumber; return scaleOffset ~/ frequencyNumber;
} }
FutureOr<List<Event>> getEvents() async { FutureOr<List<Event>> getEvents() async {

@ -0,0 +1,79 @@
class PrescriptionAnalysisResponse {
String? prescriptionSummary;
List<MedicineAnalysis>? medicinesAnalysis;
List<String>? importantWarnings;
List<String>? medicineInteractions;
String? followUpNeeded;
int? languageId;
PrescriptionAnalysisResponse({
this.prescriptionSummary,
this.medicinesAnalysis,
this.importantWarnings,
this.medicineInteractions,
this.followUpNeeded,
this.languageId,
});
PrescriptionAnalysisResponse.fromJson(Map<String, dynamic> json) {
prescriptionSummary = json['prescription_summary'];
if (json['medicines_analysis'] != null) {
medicinesAnalysis = <MedicineAnalysis>[];
json['medicines_analysis'].forEach((v) {
medicinesAnalysis!.add(MedicineAnalysis.fromJson(v));
});
}
importantWarnings = json['important_warnings'] != null ? json['important_warnings'].cast<String>() : [];
medicineInteractions = json['medicine_interactions'] != null ? json['medicine_interactions'].cast<String>() : [];
followUpNeeded = json['follow_up_needed'];
languageId = json['language_id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['prescription_summary'] = prescriptionSummary;
if (medicinesAnalysis != null) {
data['medicines_analysis'] = medicinesAnalysis!.map((v) => v.toJson()).toList();
}
data['important_warnings'] = importantWarnings;
data['medicine_interactions'] = medicineInteractions;
data['follow_up_needed'] = followUpNeeded;
data['language_id'] = languageId;
return data;
}
}
class MedicineAnalysis {
String? medicineName;
String? benefit;
List<String>? commonSideEffects;
List<String>? seriousWarnings;
String? storage;
MedicineAnalysis({
this.medicineName,
this.benefit,
this.commonSideEffects,
this.seriousWarnings,
this.storage,
});
MedicineAnalysis.fromJson(Map<String, dynamic> json) {
medicineName = json['medicine_name'];
benefit = json['benefit'];
commonSideEffects = json['common_side_effects'] != null ? json['common_side_effects'].cast<String>() : [];
seriousWarnings = json['serious_warnings'] != null ? json['serious_warnings'].cast<String>() : [];
storage = json['storage'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['medicine_name'] = medicineName;
data['benefit'] = benefit;
data['common_side_effects'] = commonSideEffects;
data['serious_warnings'] = seriousWarnings;
data['storage'] = storage;
return data;
}
}

@ -5,6 +5,7 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.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/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart';
@ -23,6 +24,8 @@ abstract class PrescriptionsRepo {
{required String latitude, required String longitude, required String appointmentNo, required String dischargeID, required String projectID}); {required String latitude, required String longitude, required String appointmentNo, required String dischargeID, required String projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionOrdersList(); Future<Either<Failure, GenericApiModel<dynamic>>> getPrescriptionOrdersList();
Future<Either<Failure, GenericApiModel<PrescriptionAnalysisResponse>>> getPrescriptionAiAnalysis({required dynamic payload, required int langId});
} }
class PrescriptionsRepoImp implements PrescriptionsRepo { class PrescriptionsRepoImp implements PrescriptionsRepo {
@ -314,4 +317,47 @@ class PrescriptionsRepoImp implements PrescriptionsRepo {
return Left(UnknownFailure(e.toString())); return Left(UnknownFailure(e.toString()));
} }
} }
@override
Future<Either<Failure, GenericApiModel<PrescriptionAnalysisResponse>>> getPrescriptionAiAnalysis({required dynamic payload, required int langId}) async {
try {
GenericApiModel<PrescriptionAnalysisResponse>? apiResponse;
Failure? failure;
await apiClient.post(
ApiConsts.getAiPrescriptionAnalysis,
isAllowAny: true,
isExternal: true,
apiHeaders: {
'Accept-Language': 'en-US,en;q=0.7',
'Content-Type': 'application/json',
'X-API-KEY': '9d9d2ac4c1fc302299dbb0fbb1b7fea1',
'accept': 'application/json',
},
body: {"medicines": payload, "language_id": langId},
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final analysisResponse = PrescriptionAnalysisResponse.fromJson(response);
apiResponse = GenericApiModel<PrescriptionAnalysisResponse>(
messageStatus: 1,
statusCode: statusCode,
errorMessage: null,
data: analysisResponse,
);
} catch (e) {
loggerService.logError('Error parsing prescription AI analysis: $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()));
}
}
} }

@ -9,6 +9,7 @@ import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/core/dependencies.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/calender_utils_new.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_delivery_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_detail_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
@ -17,6 +18,7 @@ import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_deli
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.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';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.dart'; import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.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 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
@ -55,6 +57,9 @@ class PrescriptionsViewModel extends ChangeNotifier {
DateTime? selectedReminderTime; DateTime? selectedReminderTime;
PrescriptionAnalysisResponse? prescriptionAnalysisResponse;
bool isPrescriptionAIAnalysisNeedsToBeShown = false;
PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices}); PrescriptionsViewModel({required this.prescriptionsRepo, required this.errorHandlerService, required this.navServices});
initPrescriptionsViewModel() { initPrescriptionsViewModel() {
@ -340,4 +345,60 @@ class PrescriptionsViewModel extends ChangeNotifier {
selectedReminderTime = dateTime; selectedReminderTime = dateTime;
notifyListeners(); notifyListeners();
} }
void setIsPrescriptionAIAnalysisNeedsToBeShown(bool value) {
isPrescriptionAIAnalysisNeedsToBeShown = value;
}
Future<void> getPrescriptionAiAnalysis({
required List<PrescriptionDetailResponseModel> prescriptions,
required int langId,
required String loadingText,
required Function(dynamic) onNavigate,
}) async {
LoaderBottomSheet.showLoader(
loadingText: loadingText,
showCloseButton: true,
onCloseTap: () {
setIsPrescriptionAIAnalysisNeedsToBeShown(false);
},
);
// Prepare medicines payload
List<Map<String, dynamic>> medicines = [];
for (var prescription in prescriptions) {
if (prescription.itemDescription != null && prescription.itemDescription!.isNotEmpty) {
medicines.add({
"name": prescription.itemDescription ?? "",
"frequency": prescription.frequency ?? "",
"duration": "${prescription.days ?? 0} Days",
});
}
}
final result = await prescriptionsRepo.getPrescriptionAiAnalysis(
payload: medicines,
langId: langId,
);
result.fold(
(failure) async {
LoaderBottomSheet.hideLoader();
if (isPrescriptionAIAnalysisNeedsToBeShown) {
await errorHandlerService.handleError(failure: failure);
}
},
(apiResponse) {
LoaderBottomSheet.hideLoader();
if (apiResponse.messageStatus == 2) {
// Error handling
} else if (apiResponse.messageStatus == 1) {
if (isPrescriptionAIAnalysisNeedsToBeShown) {
prescriptionAnalysisResponse = apiResponse.data;
onNavigate(apiResponse.data);
}
}
},
);
}
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,310 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/prescription_analysis_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.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/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/expandable_list_widget.dart';
import 'package:provider/provider.dart';
class PrescriptionAiAnalysisDetailedPage extends StatefulWidget {
const PrescriptionAiAnalysisDetailedPage({super.key});
@override
State<PrescriptionAiAnalysisDetailedPage> createState() => _PrescriptionAiAnalysisDetailedPageState();
}
class _PrescriptionAiAnalysisDetailedPageState extends State<PrescriptionAiAnalysisDetailedPage> {
late PrescriptionsViewModel prescriptionsViewModel;
@override
Widget build(BuildContext context) {
prescriptionsViewModel = Provider.of<PrescriptionsViewModel>(context, listen: false);
return CollapsingListView(
isClose: true,
title: LocaleKeys.aiAnalysis.tr(context: context),
child: Consumer<PrescriptionsViewModel>(
builder: (context, model, child) {
if (model.prescriptionAnalysisResponse == null) {
return Utils.getNoDataWidget(context);
}
final analysis = model.prescriptionAnalysisResponse!;
List<ExpandableListItem> expandableItems = [];
// Summary Section
if (analysis.prescriptionSummary != null && analysis.prescriptionSummary!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.summary.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
initiallyExpanded: true,
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFF0B85F7)),
),
padding: EdgeInsets.all(16.r),
child: (analysis.prescriptionSummary ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
),
SizedBox(height: 8.h),
],
),
);
}
// Medicines Analysis Section
if (analysis.medicinesAnalysis != null && analysis.medicinesAnalysis!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.medicinesAnalysis.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
...analysis.medicinesAnalysis!.map((medicine) {
return Column(
children: [
_buildMedicineCard(medicine),
SizedBox(height: 16.h),
],
);
}).toList(),
],
),
);
}
// Important Warnings Section
if (analysis.importantWarnings != null && analysis.importantWarnings!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.importantWarnings.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFFFF5252)),
),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.importantWarnings!.map((warning) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.warning_amber_rounded, color: Color(0xFFFF5252), size: 18.w),
SizedBox(width: 8.w),
Expanded(child: warning.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400)),
],
),
);
}).toList(),
),
),
SizedBox(height: 8.h),
],
),
);
}
// Medicine Interactions Section
if (analysis.medicineInteractions != null && analysis.medicineInteractions!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.medicineInteractions.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFFFFAF15)),
),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: analysis.medicineInteractions!.map((interaction) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.info_outline, color: Color(0xFFFFAF15), size: 18.w),
SizedBox(width: 8.w),
Expanded(child: interaction.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400)),
],
),
);
}).toList(),
),
),
SizedBox(height: 8.h),
],
),
);
}
// Follow-up Needed Section
if (analysis.followUpNeeded != null && analysis.followUpNeeded!.isNotEmpty) {
expandableItems.add(
ExpandableListItem(
backgroundColor: Colors.transparent,
expandedBackgroundColor: Colors.transparent,
title: LocaleKeys.followUpNeeded.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
children: [
SizedBox(height: 10.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: AppColors.primaryRedColor),
),
padding: EdgeInsets.all(16.r),
child: (analysis.followUpNeeded ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
),
SizedBox(height: 8.h),
],
),
);
}
return Column(
children: [
if (expandableItems.isEmpty)
Utils.getNoDataWidget(context)
else
CustomExpandableList(
expansionMode: ExpansionMode.exactlyOne,
dividerColor: AppColors.dividerColor,
itemPadding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 14.h),
items: expandableItems,
theme: ExpandableListTheme.custom(
defaultTrailingIcon: Utils.buildSvgWithAssets(
icon: AppAssets.arrow_down,
height: 22.h,
width: 22.w,
iconColor: AppColors.textColor,
),
),
).paddingSymmetrical(16.w, 0.0),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.info_outline, color: AppColors.greyTextColor, size: 20.r),
SizedBox(width: 8.w),
Expanded(
child: ("${LocaleKeys.disclaimer.tr()}:${LocaleKeys.thisAboveInfo.tr()}").toText12(color: AppColors.greyTextColor, fontWeight: FontWeight.w400),
),
],
).paddingSymmetrical(16.w, 16.h)
],
);
},
),
);
}
Widget _buildMedicineCard(MedicineAnalysis medicine) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 12.r,
side: BorderSide(width: 1, color: Color(0xFF4CAF50)),
),
padding: EdgeInsets.all(16.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Medicine Name
(medicine.medicineName ?? "").toText16(isBold: true, color: AppColors.blackColor),
SizedBox(height: 12.h),
// Benefit
if (medicine.benefit != null && medicine.benefit!.isNotEmpty) ...[
_buildInfoRow(
icon: Icons.medication_rounded,
iconColor: Color(0xFF4CAF50),
title: LocaleKeys.benefit.tr(context: context),
content: medicine.benefit!,
),
SizedBox(height: 12.h),
],
// Common Side Effects
if (medicine.commonSideEffects != null && medicine.commonSideEffects!.isNotEmpty) ...[
_buildInfoRow(
icon: Icons.warning_amber_rounded,
iconColor: Color(0xFFFFAF15),
title: LocaleKeys.commonSideEffects.tr(context: context),
content: medicine.commonSideEffects!.join(', '),
),
SizedBox(height: 12.h),
],
// Serious Warnings
if (medicine.seriousWarnings != null && medicine.seriousWarnings!.isNotEmpty) ...[
_buildInfoRow(
icon: Icons.error_outline,
iconColor: Color(0xFFFF5252),
title: LocaleKeys.seriousWarnings.tr(context: context),
content: medicine.seriousWarnings!.join(', '),
),
SizedBox(height: 12.h),
],
// Storage
if (medicine.storage != null && medicine.storage!.isNotEmpty) ...[
_buildInfoRow(
icon: Icons.inventory_2_outlined,
iconColor: Color(0xFF2196F3),
title: LocaleKeys.storage.tr(context: context),
content: medicine.storage!,
),
],
],
),
);
}
Widget _buildInfoRow({
required IconData icon,
required Color iconColor,
required String title,
required String content,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Row(
// children: [
// // Icon(icon, color: iconColor, size: 18.w),
// SizedBox(width: 8.w),
// // title.toText14(isBold: true, color: AppColors.blackColor),
// ],
// ),
SizedBox(height: 4.h),
content.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
],
);
}
}

@ -15,6 +15,7 @@ import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/models/resp_models/patient_prescriptions_response_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_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/presentation/prescriptions/prescription_ai_analysis_detailed_page.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_item_view.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescription_item_view.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/theme/colors.dart';
@ -23,6 +24,7 @@ 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/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:open_filex/open_filex.dart'; import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
@ -42,7 +44,6 @@ class PrescriptionDetailPage extends StatefulWidget {
class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> { class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
late PrescriptionsViewModel prescriptionsViewModel; late PrescriptionsViewModel prescriptionsViewModel;
bool _isSwitched = false; // Initial state of the switch
@override @override
void initState() { void initState() {
@ -239,13 +240,17 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
), ),
), ),
), ),
Column( Container(
children: [ Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor, color: AppColors.whiteColor,
borderRadius: 24.h, borderRadius: 24.h,
hasShadow: true, hasShadow: true,
), ),
child: Column(
children: [
SizedBox(height: 24.h),
Container(
child: CustomButton( child: CustomButton(
text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context), text: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? LocaleKeys.resendOrder.tr(context: context) : LocaleKeys.prescriptionDeliveryError.tr(context: context),
onPressed: () async { onPressed: () async {
@ -267,59 +272,72 @@ class _PrescriptionDetailPageState extends State<PrescriptionDetailPage> {
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
borderRadius: 12, borderRadius: 12,
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
height: 50.h, height: 56.h,
icon: AppAssets.prescription_refill_icon, icon: AppAssets.prescription_refill_icon,
iconColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35), iconColor: widget.prescriptionsResponseModel.isHomeMedicineDeliverySupported! ? Colors.white : AppColors.textColor.withOpacity(0.35),
iconSize: 20.h, iconSize: 20.h,
).paddingSymmetrical(24.h, 0.h), ).paddingSymmetrical(24.h, 0.h),
), ),
Utils.havePrivilege(119) ? Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration( Utils.havePrivilege(119) ? Container(
color: AppColors.whiteColor, child: Container(
borderRadius: 24.h, height: 56.h,
hasShadow: true, decoration: BoxDecoration(
), borderRadius: BorderRadius.circular(14.r),
child: Container( gradient: LinearGradient(
height: 56.h, begin: Alignment.centerLeft,
decoration: BoxDecoration( end: Alignment.centerRight,
borderRadius: BorderRadius.circular(12.r), stops: [0.236, 1.0],
gradient: LinearGradient( colors: [
begin: Alignment.centerLeft, Color(0xFF8A38F5),
end: Alignment.centerRight, Color(0xFFE20BBB),
stops: [0.236, 1.0], // 53.6% and 100% ],
colors: [ ),
Color(0xFF8A38F5), // Transparent ),
Color(0xFFE20BBB), // Solid #F8F8F8 child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(right: 4.w, left: 4.w),
child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white),
),
LocaleKeys.generateAiAnalysisPrescription.tr(context: context).toText16(isBold: true, color: Colors.white)
], ],
), ),
), ).paddingSymmetrical(24.h, 12.h).onPress(() {
child: Row( final _dialogService = getIt.get<DialogService>();
crossAxisAlignment: CrossAxisAlignment.center, _dialogService.showCommonBottomSheetWithoutH(
mainAxisAlignment: MainAxisAlignment.center, message: LocaleKeys.aiDisclaimerPrescription.tr(),
children: [ label: LocaleKeys.consent.tr(),
Padding( okLabel: LocaleKeys.acceptLbl.tr(),
padding: EdgeInsets.only(right: 4.w, left: 4.w), cancelLabel: LocaleKeys.rejectView.tr(),
child: Utils.buildSvgWithAssets(icon: AppAssets.aiOverView, width: 16.h, height: 16.h, iconColor: Colors.white), onOkPressed: () {
), context.pop();
LocaleKeys.generateAiAnalysisResult.tr(context: context).toText16(isBold: true, color: Colors.white) prescriptionsViewModel.setIsPrescriptionAIAnalysisNeedsToBeShown(true);
], prescriptionsViewModel.getPrescriptionAiAnalysis(
), prescriptions: prescriptionsViewModel.prescriptionDetailsList,
).paddingSymmetrical(24.h, 24.h).onPress(() async { langId: getIt.get<AppState>().getLanguageID(),
final _dialogService = getIt.get<DialogService>(); loadingText: LocaleKeys.loadingAIAnalysis.tr(context: context),
await _dialogService.showCommonBottomSheetWithoutH( onNavigate: (data) {
message: LocaleKeys.aiDisclaimer.tr(), // Navigate to prescription AI analysis detailed page
label: LocaleKeys.consent.tr(), Navigator.push(
okLabel: LocaleKeys.acceptLbl.tr(), context,
cancelLabel: LocaleKeys.rejectView.tr(), CustomPageRoute(
onOkPressed: () { direction: AxisDirection.down,
page: PrescriptionAiAnalysisDetailedPage(),
),
);
},
);
},
onCancelPressed: () {
context.pop();
});
}),
}, ): SizedBox(height: 24,),
onCancelPressed: () { ]))
context.pop();
});
}),
) : SizedBox(height: 24,) ,
])
], ],
), ),
); );

@ -222,6 +222,7 @@ class PrescriptionItemView extends StatelessWidget {
CalenderUtilsNew calender = CalenderUtilsNew.instance; CalenderUtilsNew calender = CalenderUtilsNew.instance;
bool isEventAdded = await calender.createMultipleEvents( bool isEventAdded = await calender.createMultipleEvents(
reminderMinutes: 10, reminderMinutes: 10,
scaleOffset : prescriptionVM.prescriptionDetailsList[index].scaleOffset!,
frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(), frequencyNumber: prescriptionVM.prescriptionDetailsList[index].frequencyNumber?.toInt(),
days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(), days: prescriptionVM.prescriptionDetailsList[index].days!.toInt(),
orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!, orderDate: prescriptionVM.prescriptionDetailsList[index].orderDate!,

Loading…
Cancel
Save