Skip to content

Commit

Permalink
feat(#259): add whole tutorial flow
Browse files Browse the repository at this point in the history
  • Loading branch information
tamslo committed Apr 11, 2024
1 parent 94d517f commit b7568d5
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 71 deletions.
54 changes: 54 additions & 0 deletions app/lib/common/models/drug/warning_level.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,57 @@ extension WarningLevelColor on WarningLevel {
Color get color => WarningLevelColor._colorMap[name]!;
Color get textColor => darkenColor(color, 0.4);
}

extension WarningLevelDescription on WarningLevel {
TextSpan getDescription(String text) => TextSpan(
children: [
WidgetSpan(
child: Icon(
icon,
color: textColor,
size: PharMeTheme.textTheme.bodyMedium!.fontSize,
),
),
WidgetSpan(
child: SizedBox(width: PharMeTheme.smallSpace * 0.4),
),
TextSpan(
text: text,
style: PharMeTheme.textTheme.bodyMedium!.copyWith(color: textColor)
),
],
);
}

extension WarningLevelLegend on List<WarningLevel> {
TextSpan buildLegend({
required String? Function(WarningLevel) getText,
InlineSpan? separator,
}) {
var content = <InlineSpan>[];
for (final (index, warningLevel) in indexed) {
final text = getText(warningLevel);
if (text.isNullOrEmpty) continue;
final warningLevelIndicator = warningLevel.getDescription(text!);
final isLastItem = index == WarningLevel.values.length - 1;
content = isLastItem
? [ ...content, warningLevelIndicator ]
: [
...content,
warningLevelIndicator,
separator ?? WidgetSpan(
child: SizedBox(width: PharMeTheme.smallSpace * 0.8),
),
];
}
return TextSpan(
style: PharMeTheme.textTheme.bodyMedium,
children: content,
);
}

TextSpan getTextLegend(BuildContext context) => buildLegend(
getText: (warningLevel) => warningLevel.getLabel(context),
separator: TextSpan(text: ', '),
);
}
11 changes: 8 additions & 3 deletions app/lib/common/widgets/direction_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ class DirectionButton extends StatelessWidget {
color: textColor,
size: 32,
);
final buttonText = Text(
text,
style: PharMeTheme.textTheme.titleLarge!.copyWith(color: textColor),
final buttonText = Flexible(
child: Text(
text,
style: PharMeTheme.textTheme.titleLarge!.copyWith(
color: textColor,
overflow: TextOverflow.fade,
),
),
);
final buttonContent = direction == ButtonDirection.forward
? [ separator, buttonText, separator, icon ]
Expand Down
39 changes: 39 additions & 0 deletions app/lib/common/widgets/tutorial/show_app_tour.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,45 @@ FutureOr<void> showAppTour(
assetPath:
'assets/images/tutorial/05_bottom_navigation_loopable.gif',
),
TutorialPage(
title: (context) =>
context.l10n.tutorial_app_tour_2_title,
content: (context) => TextSpan(
children: [
TextSpan(text: context.l10n.tutorial_app_tour_2_body),
WarningLevel.values.getTextLegend(context),
],
),
assetPath:
'assets/images/tutorial/06_drug_search_and_filter_loopable.gif',
),
TutorialPage(
title: (context) =>
context.l10n.tutorial_app_tour_3_title,
content: (context) => TextSpan(
text: context.l10n.tutorial_app_tour_3_body,
),
assetPath:
'assets/images/tutorial/07_clopidogrel_loopable.gif',
),
TutorialPage(
title: (context) =>
context.l10n.tutorial_app_tour_4_title,
content: (context) => TextSpan(
text: context.l10n.tutorial_app_tour_4_body,
),
assetPath:
'assets/images/tutorial/08_report_and_cyp2c19_loopable.gif',
),
TutorialPage(
title: (context) =>
context.l10n.tutorial_app_tour_5_title,
content: (context) => TextSpan(
text: context.l10n.tutorial_app_tour_5_body,
),
assetPath:
'assets/images/tutorial/09_faq_and_more_loopable.gif',
),
],
onClose: revisiting
? null
Expand Down
15 changes: 10 additions & 5 deletions app/lib/common/widgets/tutorial/tutorial_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ class TutorialBuilder extends HookWidget {
? currentPage.content!(context)
: null;
final asset = currentPage.assetPath != null
? Image.asset(currentPage.assetPath!)
? Container(
color: PharMeTheme.onSurfaceColor,
child: Center(child: Image.asset(currentPage.assetPath!)),
)
: null;
return [
if (title != null) Text(
Expand All @@ -57,7 +60,7 @@ class TutorialBuilder extends HookWidget {
child: Padding(
padding: EdgeInsetsDirectional.only(top: PharMeTheme.mediumSpace),
// child: Container(),
child: Center(child: asset),
child: asset,
),
),
Padding(
Expand All @@ -74,7 +77,10 @@ class TutorialBuilder extends HookWidget {
final isFirstPage = currentPageIndex.value == 0;
final isLastPage = currentPageIndex.value == pages.length - 1;
return Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: isFirstPage
? MainAxisAlignment.end
: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
if (!isFirstPage) DirectionButton(
direction: ButtonDirection.backward,
Expand All @@ -86,11 +92,10 @@ class TutorialBuilder extends HookWidget {
onPressed: isLastPage
? Navigator.of(context).pop
: () => currentPageIndex.value = currentPageIndex.value + 1,

text: isLastPage && lastNextButtonText != null
? lastNextButtonText!
: context.l10n.action_continue,
emphasize: isLastPage,
emphasize: true,
),
],
);
Expand Down
13 changes: 11 additions & 2 deletions app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"action_cancel": "Cancel",
"action_continue": "Continue",
"action_back_to_app": "Back to app",
"action_finish": "Finish",

"error_title": "Something went wrong",
"error_uncaught_message_first_part": "PharMe has encountered an unknown error. ",
Expand Down Expand Up @@ -347,11 +348,19 @@
"nav_more": "More",
"tab_more": "More",

"tutorial_to_the_app": "Proceed to the app",
"tutorial_initial_drug_selection_title": "Setup PharMe",
"tutorial_initial_drug_selection_body": "As a first step, please update the list of your current medications.",
"tutorial_app_tour_1_title": "App Tour (1/5) · Navigation",
"tutorial_app_tour_1_body": "We would first like to guide you through the app's main functions.\n\nYou can switch between PharMe's main screens using the bottom navigation bar.\n\nIf you want to re-watch this app tour later, you can always do so on the last screen under More.",
"tutorial_app_tour_1_body": "We would first like to guide you through the app's main functions.\n\nYou can switch between PharMe's main screens using the bottom navigation bar – if you want to re-watch this app tour later, you can always do so on the last screen under More.",
"tutorial_app_tour_2_title": "App Tour (2/5) · Medication List",
"tutorial_app_tour_2_body": "Under Medications, you will find the list of all available medications in PharMe.\n\nYou can search for specific generic names, brand names, or medication classes, and filter the list by various criteria.\n\nAll medications in PharMe are labeled with a color and an icon: ",
"tutorial_app_tour_3_title": "App Tour (3/5) · Medication Details",
"tutorial_app_tour_3_body": "The medication details provide further information about how well this medication works for you, according to scientific guidelines.\n\nHere you can also change whether you are currently taking a medication and export a report for healthcare professionals.",
"tutorial_app_tour_4_title": "App Tour (4/5) · Gene Report",
"tutorial_app_tour_4_body": "Under Genes, you will find the results of your genetic test for genes with known medication interactions.\n\nSelect a gene to learn more about your results and how this gene might interact with specific medications.",
"tutorial_app_tour_5_title": "App Tour (5/5) · FAQ & Additional Features",
"tutorial_app_tour_5_body": "Under FAQ, you will find a list of frequently asked questions and further resources.\n\nUnder More, you will find additional information about the app as well as a contact form and other useful features. Please reach out if you have any questions while using the app!",

"onboarding_get_started": "Get started",
"onboarding_next": "Next",
"onboarding_prev": "Back",
Expand Down
2 changes: 1 addition & 1 deletion app/lib/main/pages/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class MainPage extends StatelessWidget {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await showAppTour(
context,
lastNextButtonText: context.l10n.tutorial_to_the_app,
lastNextButtonText: context.l10n.action_finish,
revisiting: false,
);
});
Expand Down
63 changes: 3 additions & 60 deletions app/lib/report/pages/report.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ class ReportPage extends StatelessWidget {
children: [
Text(context.l10n.report_legend_text),
SizedBox(height: PharMeTheme.smallSpace * 0.5),
_buildWarningLevelIndicators(
getText: (warningLevel) =>
warningLevel.getLabel(context),
separator: TextSpan(text: ', ')
),
Text.rich(WarningLevel.values.getTextLegend(context)),
]
),
),
Expand Down Expand Up @@ -110,15 +106,15 @@ class GeneCard extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
),
_buildWarningLevelIndicators(
Text.rich(WarningLevel.values.buildLegend(
getText: (warningLevel) {
final warningLevelCount = affectedDrugs.filter(
(drug) => drug.warningLevel == warningLevel
).length;
return warningLevelCount > 0
? warningLevelCount.toString()
: null;
},
}),
),
],
),
Expand All @@ -130,56 +126,3 @@ class GeneCard extends StatelessWidget {
);
}
}

Text _buildWarningLevelIndicators({
required String? Function(WarningLevel) getText,
InlineSpan? separator,
}) {
var content = <InlineSpan>[];
for (final (index, warningLevel) in WarningLevel.values.indexed) {
final text = getText(warningLevel);
if (text.isNullOrEmpty) continue;
final warningLevelIndicator = _buildWarningLevelIndicator(
warningLevel,
text: text!,
);
final isLastItem = index == WarningLevel.values.length - 1;
content = isLastItem
? [ ...content, ...warningLevelIndicator ]
: [
...content,
...warningLevelIndicator,
separator ?? WidgetSpan(
child: SizedBox(width: PharMeTheme.smallSpace * 0.8),
),
];
}
return Text.rich(
TextSpan(
style: PharMeTheme.textTheme.bodyMedium,
children: content,
)
);
}

List<InlineSpan> _buildWarningLevelIndicator(
WarningLevel warningLevel,
{ required String text }
) {
return [
WidgetSpan(
child: Icon(
warningLevel.icon,
color: warningLevel.textColor,
size: PharMeTheme.textTheme.bodyMedium!.fontSize,
),
),
WidgetSpan(
child: SizedBox(width: PharMeTheme.smallSpace * 0.4),
),
TextSpan(
text: text,
style: PharMeTheme.textTheme.bodyMedium!.copyWith(color: warningLevel.textColor)
),
];
}

0 comments on commit b7568d5

Please sign in to comment.