From c6d8a9c81b614c621f8f2204234788538b9867b5 Mon Sep 17 00:00:00 2001 From: tamslo Date: Fri, 29 Nov 2024 17:18:07 +0100 Subject: [PATCH] feat(app): add indicators for drug list and improve --- app/lib/common/widgets/drug_list/builder.dart | 66 +++++++++- .../common/widgets/drug_search/builder.dart | 80 ++++-------- app/lib/l10n/app_en.arb | 4 + app/lib/report/pages/gene.dart | 118 +++++++++--------- app/lib/report/pages/report.dart | 1 + pharme.code-workspace | 1 + 6 files changed, 155 insertions(+), 115 deletions(-) diff --git a/app/lib/common/widgets/drug_list/builder.dart b/app/lib/common/widgets/drug_list/builder.dart index eb8872f3..09a036e5 100644 --- a/app/lib/common/widgets/drug_list/builder.dart +++ b/app/lib/common/widgets/drug_list/builder.dart @@ -9,6 +9,7 @@ typedef DrugItemBuilder = List Function( } ); +// TODO(tamslo): https://github.com/hpi-dhc/PharMe/issues/731 class DrugList extends HookWidget { const DrugList({ super.key, @@ -19,7 +20,7 @@ class DrugList extends HookWidget { this.showDrugInteractionIndicator = false, this.searchForDrugClass = true, this.drugActivityChangeable = false, - this.buildContainer, + required this.buildContainer, }); final DrugListState state; @@ -32,7 +33,11 @@ class DrugList extends HookWidget { // in the "All medications" list to make searching and toggling a medication's // activity less confusing final bool drugActivityChangeable; - final Widget Function(List children)? buildContainer; + final Widget Function({ + List? children, + Widget? indicator, + Widget? noDrugsMessage, + }) buildContainer; Widget _buildDrugList( BuildContext context, @@ -46,7 +51,7 @@ class DrugList extends HookWidget { searchForDrugClass: searchForDrugClass, ).sortedBy((drug) => drug.name); if (filteredDrugs.isEmpty && noDrugsMessage != null) { - return errorIndicator(noDrugsMessage!); + return buildContainer(noDrugsMessage: errorIndicator(noDrugsMessage!)); } List? activeDrugsList; // Do not show repeated active drugs when searching in medication selection @@ -126,9 +131,18 @@ class DrugList extends HookWidget { ], if (activeDrugsList == null) ...allDrugsList, ]; - return (buildContainer != null) - ? buildContainer!(drugLists) - : Column(crossAxisAlignment: CrossAxisAlignment.start, children: drugLists); + final indicator = _maybeBuildDrugListIndicator( + context: context, + drugs: drugs, + filter: filter, + activeDrugs: activeDrugs, + otherDrugsExpanded: currentlyExpanded, + currentlyEnabled: currentlyEnabled, + ); + return buildContainer( + children: drugLists, + indicator: indicator, + ); } @override @@ -144,4 +158,44 @@ class DrugList extends HookWidget { loading: loadingIndicator, ); } + + Widget _maybeBuildDrugListIndicator({ + required BuildContext context, + required List drugs, + required FilterState filter, + required ActiveDrugs activeDrugs, + required bool otherDrugsExpanded, + required bool currentlyEnabled, + }) { + var indicatorText = ''; + if (currentlyEnabled && !otherDrugsExpanded) { + final listHelperText = context.l10n.show_all_dropdown_text( + context.l10n.drugs_show_all_dropdown_item, + context.l10n.drugs_show_all_dropdown_items, + ); + indicatorText = listHelperText; + } + if (showDrugInteractionIndicator) { + final filteredDrugs = filter.filter( + drugs, + activeDrugs, + searchForDrugClass: searchForDrugClass, + ); + if (filteredDrugs.any((drug) => isInhibitor(drug.name))) { + final inhibitorText = context.l10n.search_page_indicator_explanation( + drugInteractionIndicatorName, + drugInteractionIndicator + ); + if (indicatorText.isNotBlank) { + indicatorText = '$indicatorText\n\n$inhibitorText'; + } else { + indicatorText = inhibitorText; + } + } + } + if (indicatorText.isNotBlank) { + return PageIndicatorExplanation(indicatorText); + } + return SizedBox.shrink(); + } } diff --git a/app/lib/common/widgets/drug_search/builder.dart b/app/lib/common/widgets/drug_search/builder.dart index 3360a974..2759af66 100644 --- a/app/lib/common/widgets/drug_search/builder.dart +++ b/app/lib/common/widgets/drug_search/builder.dart @@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart'; import '../../../../common/module.dart'; import '../../../drug/widgets/tooltip_icon.dart'; +// TODO(tamslo): https://github.com/hpi-dhc/PharMe/issues/731 class DrugSearch extends HookWidget { const DrugSearch({ super.key, @@ -31,33 +32,33 @@ class DrugSearch extends HookWidget { @override Widget build(BuildContext context) { final searchController = useTextEditingController(); - return Column( - children: [ - Padding( - padding: EdgeInsets.all(PharMeTheme.smallSpace), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: _buildSearchBarItems(context, searchController), - ), - ), - DrugList( - state: state, - activeDrugs: activeDrugs, - buildDrugItems: buildDrugItems, - showDrugInteractionIndicator: showDrugInteractionIndicator, - noDrugsMessage: context.l10n.search_no_drugs( - showFilter - ? context.l10n.search_no_drugs_with_filter_amendment - : '' - ), - searchForDrugClass: searchForDrugClass, - buildContainer: - (children) => scrollList(keepPosition: keepPosition, children), - drugActivityChangeable: drugActivityChangeable, + return DrugList( + state: state, + activeDrugs: activeDrugs, + buildDrugItems: buildDrugItems, + showDrugInteractionIndicator: showDrugInteractionIndicator, + noDrugsMessage: context.l10n.search_no_drugs( + showFilter + ? context.l10n.search_no_drugs_with_filter_amendment + : '' + ), + searchForDrugClass: searchForDrugClass, + buildContainer: + ({children, indicator, noDrugsMessage}) => Column( + children: [ + Padding( + padding: EdgeInsets.all(PharMeTheme.smallSpace), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: _buildSearchBarItems(context, searchController), + ), + ), + if (children != null) scrollList(keepPosition: keepPosition, children), + if (noDrugsMessage != null) noDrugsMessage, + if (indicator != null) indicator, + ], ), - _maybeBuildInteractionIndicator(context, state, activeDrugs) - ?? SizedBox.shrink(), - ], + drugActivityChangeable: drugActivityChangeable, ); } @@ -92,31 +93,4 @@ class DrugSearch extends HookWidget { ], ]; } - - Widget? _maybeBuildInteractionIndicator( - BuildContext context, - DrugListState state, - ActiveDrugs activeDrugs, - ) { - return state.whenOrNull( - loaded: (drugs, filter) { - if (showDrugInteractionIndicator) { - final filteredDrugs = filter.filter( - drugs, - activeDrugs, - searchForDrugClass: searchForDrugClass, - ); - if (filteredDrugs.any((drug) => isInhibitor(drug.name))) { - return PageIndicatorExplanation( - context.l10n.search_page_indicator_explanation( - drugInteractionIndicatorName, - drugInteractionIndicator - ), - ); - } - } - return null; - } - ); - } } diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 50496417..3635f0ae 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -307,6 +307,10 @@ "@report_show_all_dropdown_item": {}, "report_show_all_dropdown_items": "genes with known medication interactions", "@report_show_all_dropdown_items": {}, + "drugs_show_all_dropdown_item": "medication", + "@drugs_show_all_dropdown_item": {}, + "drugs_show_all_dropdown_items": "medication with clinically relevant gene interactions", + "@drugs_show_all_dropdown_items": {}, "gene_page_headline": "{gene} report", "@gene_page_headline": { diff --git a/app/lib/report/pages/gene.dart b/app/lib/report/pages/gene.dart index 823a6a7b..ac9af984 100644 --- a/app/lib/report/pages/gene.dart +++ b/app/lib/report/pages/gene.dart @@ -20,74 +20,80 @@ class GenePage extends HookWidget { builder: (context, activeDrugs, child) => BlocProvider( create: (context) => cubit, child: BlocBuilder( - builder: (context, state) => pageScaffold( + builder: (context, state) => unscrollablePageScaffold( title: context.l10n.gene_page_headline(genotypeResult.geneDisplayString), - body: [ - Padding( - padding: EdgeInsets.symmetric( - horizontal: PharMeTheme.smallToMediumSpace, - vertical: PharMeTheme.mediumSpace - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + body: DrugList( + state: state, + activeDrugs: activeDrugs, + noDrugsMessage: context.l10n.gene_page_no_relevant_drugs, + buildContainer: ({children, indicator, noDrugsMessage}) => + Column( children: [ - SubHeader( - context.l10n.gene_page_your_result( - genotypeResult.geneDisplayString, + Padding( + padding: EdgeInsets.symmetric( + horizontal: PharMeTheme.smallToMediumSpace, + vertical: PharMeTheme.mediumSpace ), - tooltip: context.l10n - .gene_page_name_tooltip( - genotypeResult.gene, - ), - ), - SizedBox(height: PharMeTheme.smallToMediumSpace), - RoundedCard( - radius: PharMeTheme.mediumSpace, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Table( - columnWidths: Map.from({ - 0: IntrinsicColumnWidth(), - 1: IntrinsicColumnWidth(flex: 1), - }), - children: [ - _buildRow( - context.l10n.gene_page_genotype, - genotypeResult.variantDisplayString(context), - tooltip: context.l10n.gene_page_genotype_tooltip - ), - _buildPhenotypeRow(context), - ], + SubHeader( + context.l10n.gene_page_your_result( + genotypeResult.geneDisplayString, + ), + tooltip: context.l10n + .gene_page_name_tooltip( + genotypeResult.gene, + ), ), - if (isInhibited(genotypeResult, drug: null)) ...[ - SizedBox(height: PharMeTheme.smallSpace), - buildDrugInteractionInfo( - context, - [genotypeResult], - drug: null, + SizedBox(height: PharMeTheme.smallToMediumSpace), + RoundedCard( + radius: PharMeTheme.mediumSpace, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Table( + columnWidths: Map.from({ + 0: IntrinsicColumnWidth(), + 1: IntrinsicColumnWidth(flex: 1), + }), + children: [ + _buildRow( + context.l10n.gene_page_genotype, + genotypeResult.variantDisplayString(context), + tooltip: context.l10n.gene_page_genotype_tooltip + ), + _buildPhenotypeRow(context), + ], + ), + if (isInhibited(genotypeResult, drug: null)) ...[ + SizedBox(height: PharMeTheme.smallSpace), + buildDrugInteractionInfo( + context, + [genotypeResult], + drug: null, + ), + ] + ], + )), + SizedBox(height: PharMeTheme.smallToMediumSpace), + SubHeader( + context.l10n.gene_page_relevant_drugs, + tooltip: context.l10n.gene_page_relevant_drugs_tooltip( + genotypeResult.geneDisplayString ), - ] - ], - )), - SizedBox(height: PharMeTheme.smallToMediumSpace), - SubHeader( - context.l10n.gene_page_relevant_drugs, - tooltip: context.l10n.gene_page_relevant_drugs_tooltip( - genotypeResult.geneDisplayString + ), + SizedBox(height: PharMeTheme.smallSpace), + ], ), ), - SizedBox(height: PharMeTheme.smallSpace), - DrugList( - state: state, - activeDrugs: activeDrugs, - noDrugsMessage: context.l10n.gene_page_no_relevant_drugs, - ), - ], + if (children != null) scrollList(children), + if (noDrugsMessage != null) noDrugsMessage, + if (indicator != null) indicator, + ] ), - ), - ], + ), ), ), ) diff --git a/app/lib/report/pages/report.dart b/app/lib/report/pages/report.dart index ac0f5b54..d44e7737 100644 --- a/app/lib/report/pages/report.dart +++ b/app/lib/report/pages/report.dart @@ -117,6 +117,7 @@ class ReportPage extends HookWidget { ).toList(); } + // TODO(tamslo): https://github.com/hpi-dhc/PharMe/issues/731 Widget _maybeBuildPageIndicators( BuildContext context, Iterable relevantGenes, diff --git a/pharme.code-workspace b/pharme.code-workspace index dea9a466..057ae7c9 100644 --- a/pharme.code-workspace +++ b/pharme.code-workspace @@ -132,6 +132,7 @@ "Statins", "subfolders", "tacrolimus", + "tamslo", "terbinafine", "tobramycin", "tramadol",