diff --git a/app/lib/common/constants.dart b/app/lib/common/constants.dart index 6a61d57a..0d849293 100644 --- a/app/lib/common/constants.dart +++ b/app/lib/common/constants.dart @@ -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'); diff --git a/app/lib/common/widgets/drug_search/builder.dart b/app/lib/common/widgets/drug_search/builder.dart index 69b929f1..2e4b436b 100644 --- a/app/lib/common/widgets/drug_search/builder.dart +++ b/app/lib/common/widgets/drug_search/builder.dart @@ -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, @@ -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, diff --git a/app/lib/common/widgets/indicators.dart b/app/lib/common/widgets/indicators.dart index 75aa098f..4d08e2a9 100644 --- a/app/lib/common/widgets/indicators.dart +++ b/app/lib/common/widgets/indicators.dart @@ -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, ); diff --git a/app/lib/common/widgets/list_description.dart b/app/lib/common/widgets/list_description.dart index 6332b3de..1573f5cb 100644 --- a/app/lib/common/widgets/list_description.dart +++ b/app/lib/common/widgets/list_description.dart @@ -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, diff --git a/app/lib/common/widgets/list_page_inclusion_description.dart b/app/lib/common/widgets/list_page_inclusion_description.dart new file mode 100644 index 00000000..562d92da --- /dev/null +++ b/app/lib/common/widgets/list_page_inclusion_description.dart @@ -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, + )), + ], + ), + ) + ], + ); + } + +} \ No newline at end of file diff --git a/app/lib/common/widgets/module.dart b/app/lib/common/widgets/module.dart index c05ef2e0..b868f751 100644 --- a/app/lib/common/widgets/module.dart +++ b/app/lib/common/widgets/module.dart @@ -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'; diff --git a/app/lib/common/widgets/page_description.dart b/app/lib/common/widgets/page_description.dart index 649309e1..ef0867c7 100644 --- a/app/lib/common/widgets/page_description.dart +++ b/app/lib/common/widgets/page_description.dart @@ -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), diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 82040af3..b6ac5a00 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -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": {}, @@ -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": {}, @@ -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": { @@ -326,7 +326,7 @@ }, "items": { "type": "String", - "example": "medications with clinically relevant gene interactions" + "example": "medications with clinical PGx guidelines" } } }, @@ -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", @@ -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": {}, diff --git a/app/lib/main/pages/main.dart b/app/lib/main/pages/main.dart index f5bf77bf..f0f0774b 100644 --- a/app/lib/main/pages/main.dart +++ b/app/lib/main/pages/main.dart @@ -1,5 +1,3 @@ -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; - import '../../common/module.dart'; class TabRouteDefinition { @@ -18,12 +16,12 @@ List 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(), diff --git a/app/lib/onboarding/pages/onboarding.dart b/app/lib/onboarding/pages/onboarding.dart index 6642c1bb..08c64974 100644 --- a/app/lib/onboarding/pages/onboarding.dart +++ b/app/lib/onboarding/pages/onboarding.dart @@ -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( @@ -483,6 +489,7 @@ class OnboardingSubPage extends HookWidget { class DisclaimerCard extends StatelessWidget { const DisclaimerCard({ this.icon, + this.iconWidget, required this.text, this.secondLineText, this.onClick, @@ -490,6 +497,7 @@ class DisclaimerCard extends StatelessWidget { }); final IconData? icon; + final Widget? iconWidget; final String text; final String? secondLineText; final GestureTapCallback? onClick; @@ -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( diff --git a/app/lib/report/pages/gene.dart b/app/lib/report/pages/gene.dart index 9db489ad..9ec07816 100644 --- a/app/lib/report/pages/gene.dart +++ b/app/lib/report/pages/gene.dart @@ -92,6 +92,11 @@ class GenePage extends HookWidget { genotypeResult.geneDisplayString ), ), + SizedBox(height: PharMeTheme.mediumSpace), + ListPageInclusionDescription( + type: ListPageInclusionDescriptionType.medications, + customPadding: EdgeInsets.zero, + ), ], ), ), diff --git a/app/lib/report/pages/report.dart b/app/lib/report/pages/report.dart index cf71644c..c1534cb9 100644 --- a/app/lib/report/pages/report.dart +++ b/app/lib/report/pages/report.dart @@ -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,