Skip to content

Commit

Permalink
feat(app): further improve medication and gene lists
Browse files Browse the repository at this point in the history
  • Loading branch information
tamslo committed Jan 23, 2025
1 parent e0d4012 commit c1f3e5e
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 25 deletions.
4 changes: 4 additions & 0 deletions app/lib/common/constants.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:url_launcher/url_launcher.dart';

const medicationsIcon = FontAwesomeIcons.pills;
const genesIcon = FontAwesomeIcons.dna;

Uri anniUrl([String slug = '']) =>
Uri.http('hpi-annotation-service.duckdns.org', 'api/v1/$slug');

Expand Down
20 changes: 15 additions & 5 deletions app/lib/common/widgets/drug_search/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ class DrugSearch extends HookWidget {
@override
Widget build(BuildContext context) {
final searchController = useTextEditingController();
final noDrugsMessage = '${context.l10n.search_no_drugs(
showFilter
? context.l10n.search_no_drugs_with_filter_amendment
: '')
}\n\n${context.l10n.included_content_addition}';
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
: ''
),
noDrugsMessage: noDrugsMessage,
searchForDrugClass: searchForDrugClass,
buildContainer: ({
children,
Expand All @@ -60,6 +61,15 @@ class DrugSearch extends HookWidget {
),
),
),
ListPageInclusionDescription(
type: ListPageInclusionDescriptionType.medications,
customPadding: EdgeInsets.only(
left: PharMeTheme.smallSpace,
right: PharMeTheme.smallSpace,
top: PharMeTheme.smallSpace * 1.5,
bottom: PharMeTheme.smallSpace,
),
),
if (children != null) scrollList(
keepPosition: keepPosition,
children,
Expand Down
6 changes: 5 additions & 1 deletion app/lib/common/widgets/indicators.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ Widget loadingIndicator() =>
genericIndicator(child: CircularProgressIndicator(), verticalPadding: 100);
Widget errorIndicator(String description) =>
genericIndicator(
child: Text(description, textAlign: TextAlign.center),
child: Text(
description,
textAlign: TextAlign.center,
style: TextStyle(fontStyle: FontStyle.italic),
),
verticalPadding: PharMeTheme.mediumToLargeSpace,
);

Expand Down
2 changes: 1 addition & 1 deletion app/lib/common/widgets/list_description.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ListDescription extends StatelessWidget {
horizontal: PharMeTheme.smallSpace,
),
child: Text.rich(
style: subheaderDividerStyle(color: PharMeTheme.onSurfaceText),
style: PharMeTheme.textTheme.bodyMedium,
TextSpan(
children: [
...textParts,
Expand Down
123 changes: 123 additions & 0 deletions app/lib/common/widgets/list_page_inclusion_description.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

import '../module.dart';

enum ListPageInclusionDescriptionType {
medications,
genes,
}

class ListPageInclusionDescription extends StatelessWidget {
const ListPageInclusionDescription({
super.key,
this.text,
this.customPadding,
required this.type,
});

final String? text;
final ListPageInclusionDescriptionType type;
final EdgeInsets? customPadding;

@override
Widget build(BuildContext context) {
final inclusionText = context.l10n.included_content_disclaimer_text(
type == ListPageInclusionDescriptionType.medications
? context.l10n.included_content_medications
: context.l10n.included_content_genes
);
return PageDescription(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (text != null) Text(text!),
if (text != null) SizedBox(height: PharMeTheme.smallToMediumSpace),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(
left: PharMeTheme.smallSpace * 1.5,
right: PharMeTheme.smallSpace * 1.5,
top: PharMeTheme.smallSpace * 0.5,
bottom: PharMeTheme.smallSpace,
),
child: IncludedContentIcon(type: type),
),
Expanded(
child: Text(
inclusionText,
style: TextStyle(color: PharMeTheme.iconColor),
),
),
],
),
],
),
customPadding: customPadding,
);
}

}

class IncludedContentIcon extends StatelessWidget {
const IncludedContentIcon({
super.key,
required this.type,
this.color,
this.size,
});

final ListPageInclusionDescriptionType type;
final Color? color;
final double? size;

@override
Widget build(BuildContext context) {
final icon = type == ListPageInclusionDescriptionType.medications
? medicationsIcon
: genesIcon;
final totalSize = size ?? PharMeTheme.mediumToLargeSpace * 1.5;
final iconSize = totalSize * 0.9;
final checkIconBackgroundSize = totalSize * 0.5;
final checkIconSize = checkIconBackgroundSize * 0.8;
final rightShift = type == ListPageInclusionDescriptionType.medications
? checkIconBackgroundSize / 2
: checkIconBackgroundSize / 4;
return Stack(
children: [
SizedBox(
height: totalSize,
width: totalSize + rightShift,
),
Icon(
icon,
size: iconSize,
color: color ?? PharMeTheme.buttonColor,
),
Positioned(
right: 0,
bottom: 0,
child: Stack(
children: [
Icon(
FontAwesomeIcons.solidCircle,
size: checkIconBackgroundSize,
color: PharMeTheme.surfaceColor,
),
Positioned(
top: (checkIconBackgroundSize - checkIconSize) / 2,
left: (checkIconBackgroundSize - checkIconSize) / 2,
child: Icon(
FontAwesomeIcons.solidCircleCheck,
size: checkIconSize,
color: PharMeTheme.sinaiPurple,
)),
],
),
)
],
);
}

}
1 change: 1 addition & 0 deletions app/lib/common/widgets/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export 'hyperlink.dart';
export 'indicators.dart';
export 'lifecycle_observer.dart';
export 'list_description.dart';
export 'list_page_inclusion_description.dart';
export 'page_description.dart';
export 'page_indicator_explanation.dart';
export 'page_scaffold.dart';
Expand Down
5 changes: 3 additions & 2 deletions app/lib/common/widgets/page_description.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import '../module.dart';

class PageDescription extends StatelessWidget {
const PageDescription(this.widget);
const PageDescription(this.widget, { this.customPadding });

factory PageDescription.fromText(String text) =>
PageDescription(Text(text));

final Widget widget;
final EdgeInsets? customPadding;

@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
padding: customPadding ?? EdgeInsets.only(
left: PharMeTheme.smallSpace,
right: PharMeTheme.smallSpace,
bottom: PharMeTheme.smallSpace),
Expand Down
29 changes: 21 additions & 8 deletions app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"@drug_selection_continue_warning_title": {},
"drug_selection_continue_warning": "When you proceed to the next step of the app setup, you will not be able to come back to this page.\n\nYou can always change your current medications later in the app.",
"@drug_selection_continue_warning": {},
"drug_selection_description": "You can edit the medications you are currently taking below. \n\nPlease note that the list may not include all medications you are currently taking, ONLY medications that are known to have clinically meaningful interactions with genes are included.",
"drug_selection_description": "You can edit the medications you are currently taking below.",
"@drug_selection_description": {},
"drug_selection_no_drugs_loaded": "No medications loaded",
"@drug_selection_no_drugs_loaded": {},
Expand Down Expand Up @@ -101,7 +101,7 @@
"warning_level_red": "Consider alternatives",
"@warning_level_red": {},

"search_content_explanation": "Below, medications that are known to have clinically relevant interactions with genes are listed.",
"search_content_explanation": "Get an overview on your PGx tests results per medication. Tap on a medication so see what your result means and what to do.",
"@search_content_explanation": {},
"search_page_tooltip_search": "Search for medications by their name, brand name or class.",
"@search_page_tooltip_search": {},
Expand All @@ -124,7 +124,7 @@
},
"search_no_drugs_with_filter_amendment": " or filters",
"@search_no_drugs_with_filter_amendment": {},
"search_no_drugs": "No medications found that match your search term{amendment}.\n\nThe medication you are looking for might also not be included in PharMe because it does not have relevant DNA-based guidelines.\n\nClinical dosing may apply, consult your pharmacist or doctor for more information.",
"search_no_drugs": "No medications found that match your search term{amendment}. Clinical dosing may apply, consult your pharmacist or doctor for more information.",
"@search_no_drugs": {
"placeholders": {
"amendment": {
Expand Down Expand Up @@ -326,7 +326,7 @@
},
"items": {
"type": "String",
"example": "medications with clinically relevant gene interactions"
"example": "medications with clinical PGx guidelines"
}
}
},
Expand All @@ -336,11 +336,11 @@
"@medications_dropdown_position": {},
"report_show_all_dropdown_item": "gene",
"@report_show_all_dropdown_item": {},
"report_show_all_dropdown_items": "genes with known medication interactions",
"report_show_all_dropdown_items": "genes with clinical PGx guidelines",
"@report_show_all_dropdown_items": {},
"drugs_show_all_dropdown_item": "medication",
"@drugs_show_all_dropdown_item": {},
"drugs_show_all_dropdown_items": "medications with clinically relevant gene interactions",
"drugs_show_all_dropdown_items": "medications with clinical PGx guidelines",
"@drugs_show_all_dropdown_items": {},

"gene_page_headline": "{gene} report",
Expand Down Expand Up @@ -539,13 +539,26 @@
"@onboarding_4_button": {},
"onboarding_4_already_tested_text": "PharMe matches your genetic information with what scientists know about how certain genes and medications interact.\n\nThe information provided by PharMe is based on proven guidelines from trusted organizations like the Clinical Pharmacogenetics Implementation Consortium (CPIC®) and the U.S. Food and Drug Administration (FDA).",
"@onboarding_4_already_tested_text": {},
"onboarding_4_disclaimer": "PharMe ONLY includes medications that are known to have meaningful interactions with genes. If you cannot find a medication in PharMe, there may not be enough evidence for gene interactions.",
"@onboarding_4_disclaimer": {},
"onboarding_5_header": "We care about your privacy",
"@onboarding_5_header": {},
"onboarding_5_text": "Once you download your genetic information, it is stored safely on your phone.\n\nOur system does not collect any information about you, including your name or DNA.",
"@onboarding_5_text": {},

"included_content_medications": "medications",
"@included_content_medications": {},
"included_content_genes": "genes",
"@included_content_genes": {},
"included_content_disclaimer_text": "PharMe only includes {content} with clinical PGx guidelines from CPIC and the FDA.",
"@included_content_disclaimer_text": {
"placeholders": {
"content": {
"type": "String",
"example": "medications"
}
}
},
"included_content_addition": "While only to a small percentage of medications have PGx guidelines, they are among the most commonly prescribed ones.\n\nIf you cannot find a medication in PharMe, there may not be enough evidence for meaningful gene interactions.",
"@included_content_addition": {},

"more_page_account_settings": "Settings",
"@more_page_account_settings": {},
Expand Down
6 changes: 2 additions & 4 deletions app/lib/main/pages/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

import '../../common/module.dart';

class TabRouteDefinition {
Expand All @@ -18,12 +16,12 @@ List<TabRouteDefinition> getTabRoutesDefinition(BuildContext context) {
TabRouteDefinition(
pageRouteInfo: SearchRoute(),
label: context.l10n.nav_drugs,
icon: FontAwesomeIcons.pills,
icon: medicationsIcon,
),
TabRouteDefinition(
pageRouteInfo: ReportRoute(),
label: context.l10n.nav_report,
icon: FontAwesomeIcons.dna,
icon: genesIcon,
),
TabRouteDefinition(
pageRouteInfo: FaqRoute(),
Expand Down
18 changes: 15 additions & 3 deletions app/lib/onboarding/pages/onboarding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,15 @@ class OnboardingPage extends HookWidget {
text: context.l10n.onboarding_4_already_tested_text,
color: Colors.grey.shade600,
bottom: DisclaimerCard(
icon: FontAwesomeIcons.pills,
iconWidget: IncludedContentIcon(
type: ListPageInclusionDescriptionType.medications,
color: PharMeTheme.onSurfaceText,
size: OnboardingDimensions.iconSize,
),
iconPadding: EdgeInsets.all(PharMeTheme.smallSpace * 0.5),
text: context.l10n.onboarding_4_disclaimer,
text: '${context.l10n.included_content_disclaimer_text(
context.l10n.included_content_medications,
)}\n\n${context.l10n.included_content_addition}',
),
),
OnboardingSubPage(
Expand Down Expand Up @@ -483,13 +489,15 @@ class OnboardingSubPage extends HookWidget {
class DisclaimerCard extends StatelessWidget {
const DisclaimerCard({
this.icon,
this.iconWidget,
required this.text,
this.secondLineText,
this.onClick,
this.iconPadding,
});

final IconData? icon;
final Widget? iconWidget;
final String text;
final String? secondLineText;
final GestureTapCallback? onClick;
Expand All @@ -509,7 +517,11 @@ class DisclaimerCard extends StatelessWidget {
children: [
Padding(
padding: iconPadding ?? EdgeInsets.zero,
child: Icon(icon ?? Icons.warning_rounded, size: 32),
child: iconWidget ?? Icon(
icon ?? Icons.warning_rounded,
size: OnboardingDimensions.iconSize,
color: PharMeTheme.onSurfaceText,
),
),
SizedBox(width: PharMeTheme.smallSpace),
Expanded(
Expand Down
5 changes: 5 additions & 0 deletions app/lib/report/pages/gene.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ class GenePage extends HookWidget {
genotypeResult.geneDisplayString
),
),
SizedBox(height: PharMeTheme.mediumSpace),
ListPageInclusionDescription(
type: ListPageInclusionDescriptionType.medications,
customPadding: EdgeInsets.zero,
),
],
),
),
Expand Down
5 changes: 4 additions & 1 deletion app/lib/report/pages/report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ class ReportPage extends HookWidget {
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageDescription.fromText(context.l10n.report_content_explanation),
ListPageInclusionDescription(
text: context.l10n.report_content_explanation,
type: ListPageInclusionDescriptionType.genes,
),
scrollList(
_buildReportLists(
context,
Expand Down

0 comments on commit c1f3e5e

Please sign in to comment.