radiology ai Analysis
parent
7d86ca0511
commit
4cd5132627
@ -0,0 +1,255 @@
|
|||||||
|
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/radiology/radiology_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 RadiologyAiAnalysisDetailedPage extends StatefulWidget {
|
||||||
|
const RadiologyAiAnalysisDetailedPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RadiologyAiAnalysisDetailedPage> createState() => _RadiologyAiAnalysisDetailedPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RadiologyAiAnalysisDetailedPageState extends State<RadiologyAiAnalysisDetailedPage> {
|
||||||
|
late RadiologyViewModel radiologyProvider;
|
||||||
|
|
||||||
|
List<String> _parseStringToList(String? text) {
|
||||||
|
if (text == null || text.isEmpty) return [];
|
||||||
|
// Split by newlines and filter out empty lines
|
||||||
|
return text.split('\n').where((line) => line.trim().isNotEmpty).map((line) => line.trim()).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
radiologyProvider = Provider.of<RadiologyViewModel>(context, listen: false);
|
||||||
|
return CollapsingListView(
|
||||||
|
isClose: true,
|
||||||
|
title: LocaleKeys.aiAnalysis.tr(context: context),
|
||||||
|
child: Consumer<RadiologyViewModel>(
|
||||||
|
builder: (context, model, child) {
|
||||||
|
if (model.radiologyAiAnalysisResponse == null) {
|
||||||
|
return Utils.getNoDataWidget(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
final analysis = model.radiologyAiAnalysisResponse!;
|
||||||
|
List<ExpandableListItem> expandableItems = [];
|
||||||
|
|
||||||
|
// Parse string fields into lists
|
||||||
|
final predictions = _parseStringToList(analysis.aiPredictions);
|
||||||
|
final preventions = _parseStringToList(analysis.prevention);
|
||||||
|
final riskFactorsText = _parseStringToList(analysis.riskFactors);
|
||||||
|
|
||||||
|
// Summary Section
|
||||||
|
if (analysis.summary != null && analysis.summary!.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.summary ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lab Results Section (Radiology Results)
|
||||||
|
if (analysis.labResults != null && analysis.labResults!.isNotEmpty) {
|
||||||
|
expandableItems.add(
|
||||||
|
ExpandableListItem(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
expandedBackgroundColor: Colors.transparent,
|
||||||
|
title: LocaleKeys.labResults.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(0xFF0B85F7)),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.r),
|
||||||
|
child: (analysis.labResults ?? "").toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI Predictions Section
|
||||||
|
if (predictions.isNotEmpty) {
|
||||||
|
expandableItems.add(
|
||||||
|
ExpandableListItem(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
expandedBackgroundColor: Colors.transparent,
|
||||||
|
title: LocaleKeys.prediction.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: predictions.map((prediction) => _buildBulletItem(prediction)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Risk Factors Section
|
||||||
|
if (riskFactorsText.isNotEmpty) {
|
||||||
|
expandableItems.add(
|
||||||
|
ExpandableListItem(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
expandedBackgroundColor: Colors.transparent,
|
||||||
|
title: LocaleKeys.riskFactors.tr(context: context).toText18(weight: FontWeight.w700, color: AppColors.blackColor),
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 10.h),
|
||||||
|
...riskFactorsText.asMap().entries.map((entry) {
|
||||||
|
final riskText = entry.value;
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
|
||||||
|
color: Color(0xFFFBCB6E).withOpacity(0.10),
|
||||||
|
borderRadius: 12.r,
|
||||||
|
side: BorderSide(width: 1, color: Color(0xFFFBCB6E).withOpacity(0.10)),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.r),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Utils.buildSvgWithAssets(icon: AppAssets.guradIcon),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: LocaleKeys.riskFactors.tr(context: context).toText16(weight: FontWeight.w700, color: AppColors.blackColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
riskText.toText14(
|
||||||
|
color: AppColors.textColorLight,
|
||||||
|
height: 1.5,
|
||||||
|
weight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevention Section
|
||||||
|
if (preventions.isNotEmpty) {
|
||||||
|
expandableItems.add(
|
||||||
|
ExpandableListItem(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
expandedBackgroundColor: Colors.transparent,
|
||||||
|
title: LocaleKeys.prevention.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(0xFF18C273)),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.all(16.r),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: preventions.map((prevention) => _buildBulletItem(prevention)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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 _buildBulletItem(String text) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 12.h),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: text.toText14(color: AppColors.textColorLight, height: 1.5, weight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue