From a80f6f35b0fded3775e63204b34a4ae2d189ad62 Mon Sep 17 00:00:00 2001 From: Tamara Slosarek Date: Tue, 3 Sep 2024 17:48:41 +0200 Subject: [PATCH] feat(#712): sort and color gene tiles --- app/lib/common/models/drug/warning_level.dart | 1 + app/lib/report/pages/report.dart | 86 +++++++++++++++---- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/app/lib/common/models/drug/warning_level.dart b/app/lib/common/models/drug/warning_level.dart index 73b6f4c8..dbdb24d0 100644 --- a/app/lib/common/models/drug/warning_level.dart +++ b/app/lib/common/models/drug/warning_level.dart @@ -95,6 +95,7 @@ extension WarningLevelLegend on List { required String? Function(WarningLevel) getText, InlineSpan? separator, }) { + // TODO(tamslo): isLastItem should consider skipped items and consider potential icon margin to add after text, https://github.com/hpi-dhc/PharMe/issues/712 var content = []; for (final (index, warningLevel) in indexed) { final text = getText(warningLevel); diff --git a/app/lib/report/pages/report.dart b/app/lib/report/pages/report.dart index e8a6547a..e4c24f5b 100644 --- a/app/lib/report/pages/report.dart +++ b/app/lib/report/pages/report.dart @@ -2,6 +2,8 @@ import 'package:provider/provider.dart'; import '../../common/module.dart'; +typedef WarningLevelCounts = Map; + @RoutePage() class ReportPage extends StatelessWidget { @override @@ -12,6 +14,12 @@ class ReportPage extends StatelessWidget { ); } + int _getSeverityCount(WarningLevelCounts warningLevelCounts, int severity) { + return warningLevelCounts.filter( + (warningLevelCount) => warningLevelCount.key.severity == severity + ).values.first; + } + Widget _buildReportPage(BuildContext context, ActiveDrugs activeDrugs) { final presentGenes = Set.from(UserData.instance.genotypeResults!.values.map( (genotypeResult) => genotypeResult.gene @@ -24,7 +32,34 @@ class ReportPage extends StatelessWidget { ...missingGenes.map( (gene) => GenotypeResult.missingResult(gene, context), ), - ].sortedBy((genotypeResult) => genotypeResult.gene); + ]; + final warningLevelCounts = {}; + for (final genotypeResult in userGenotypes) { + warningLevelCounts[genotypeResult.gene] = {}; + final affectedDrugs = CachedDrugs.instance.drugs?.filter( + (drug) => drug.guidelineGenotypes.contains(genotypeResult.key.value) + ) ?? []; + for (final warningLevel in WarningLevel.values) { + warningLevelCounts[genotypeResult.gene]![warningLevel] = + affectedDrugs.filter( + (drug) => drug.warningLevel == warningLevel + ).length; + } + } + var sortedGenotypes = userGenotypes.sortedBy( + (genotypeResult) => genotypeResult.gene + ); + final sortedWarningLevels = WarningLevel.values.sortedBy( + (warningLevel) => warningLevel.severity + ); + for (final warningLevel in sortedWarningLevels) { + sortedGenotypes = sortedGenotypes.sortedByDescending((genotypeResult) => + _getSeverityCount( + warningLevelCounts[genotypeResult.gene]!, + warningLevel.severity, + ), + ); + } final hasActiveInhibitors = activeDrugs.names.any(isInhibitor); return PopScope( canPop: false, @@ -46,8 +81,9 @@ class ReportPage extends StatelessWidget { ] ), ), - ...userGenotypes.map((genotypeResult) => GeneCard( + ...sortedGenotypes.map((genotypeResult) => GeneCard( genotypeResult, + warningLevelCounts[genotypeResult.gene]!, key: Key('gene-card-${genotypeResult.key.value}') )), ], @@ -66,9 +102,19 @@ class ReportPage extends StatelessWidget { } class GeneCard extends StatelessWidget { - const GeneCard(this.genotypeResult, { super.key }); + const GeneCard(this.genotypeResult, this.warningLevelCounts, { super.key }); final GenotypeResult genotypeResult; + final WarningLevelCounts warningLevelCounts; + + Color? _getHighestSeverityColor(WarningLevelCounts warningLevelCounts) { + final sortedWarningLevels = WarningLevel.values.sortedByDescending( + (warningLevel) => warningLevel.severity + ); + return sortedWarningLevels.filter( + (warningLevel) => warningLevelCounts[warningLevel]! > 0 + ).firstOrNull?.color; + } @override Widget build(BuildContext context) { @@ -79,14 +125,13 @@ class GeneCard extends StatelessWidget { final phenotypeText = phenotypeInformation.adaptionText.isNullOrBlank ? phenotypeInformation.phenotype : '${phenotypeInformation.phenotype}$drugInteractionIndicator'; - final affectedDrugs = CachedDrugs.instance.drugs?.filter( - (drug) => drug.guidelineGenotypes.contains(genotypeResult.key.value) - ) ?? []; + final hasLegend = warningLevelCounts.values.any((count) => count > 0); return RoundedCard( onTap: () => context.router.push( GeneRoute(genotypeResult: genotypeResult) ), radius: 16, + color: _getHighestSeverityColor(warningLevelCounts), child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( @@ -106,15 +151,26 @@ class GeneCard extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), - Text.rich(WarningLevel.values.buildLegend( - getText: (warningLevel) { - final warningLevelCount = affectedDrugs.filter( - (drug) => drug.warningLevel == warningLevel - ).length; - return warningLevelCount > 0 - ? warningLevelCount.toString() - : null; - }), + if (hasLegend) DecoratedBox( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: 2, + horizontal: 4, + ), + child: Text.rich(WarningLevel.values.buildLegend( + getText: (warningLevel) { + final warningLevelCount = + warningLevelCounts[warningLevel]!; + return warningLevelCount > 0 + ? warningLevelCount.toString() + : null; + }), + ), + ), ), ], ),