Compare commits
13 Commits
e70f7aa7e3
...
caa9da2cce
| Author | SHA1 | Date |
|---|---|---|
|
|
caa9da2cce | 16 hours ago |
|
|
efa7a39978 | 16 hours ago |
|
|
c9165b95c8 | 17 hours ago |
|
|
0ae2b6c1a0 | 17 hours ago |
|
|
2fd4a3e1a7 | 17 hours ago |
|
|
343c13f98d | 19 hours ago |
|
|
83f816e271 | 19 hours ago |
|
|
b0c12cceb5 | 19 hours ago |
|
|
344c9de29f | 19 hours ago |
|
|
597b637ca6 | 19 hours ago |
|
|
e842d85254 | 19 hours ago |
|
|
7d01e847eb | 20 hours ago |
|
|
514bf49956 | 20 hours ago |
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue