Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/480 active drugs onboarding #616

Merged
merged 4 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions app/lib/common/pages/drug/cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@ class DrugCubit extends Cubit<DrugState> {
if (value == null) return;
final drug = state.whenOrNull(loaded: (drug, _) => drug);
if (drug == null) return;
await setDrugActivity(drug, value);
emit(DrugState.loaded(drug, isActive: value));
}
}

// ignore: avoid_positional_boolean_parameters
Future<void> setDrugActivity(Drug drug, bool value) async {
final active = (UserData.instance.activeDrugNames ?? [])
.filter((name) => name != _drug.name)
.filter((name) => name != drug.name)
.toList();
if (value) {
active.add(_drug.name);
active.add(drug.name);
}
UserData.instance.activeDrugNames = active;
await UserData.save();
emit(DrugState.loaded(drug, isActive: value));
}
}

@freezed
Expand Down
2 changes: 2 additions & 0 deletions app/lib/common/routing/router.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '../../common/module.dart';
import '../../drugselection/module.dart';
import '../../faq/module.dart';
import '../../login/module.dart';
import '../../onboarding/module.dart';
Expand All @@ -12,6 +13,7 @@ part 'router.gr.dart';
@MaterialAutoRouter(
replaceInRouteName: 'Page,Route',
routes: [
drugSelectionRoutes,
loginRoutes,
onboardingRoutes,
AutoRoute(
Expand Down
37 changes: 20 additions & 17 deletions app/lib/common/utilities/drug_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,29 @@ Future<void> updateCachedDrugs() async {
final dataResponse = await get(anniUrl('data'));
if (dataResponse.statusCode != 200) throw Exception();
final data = AnniDataResponse.fromJson(jsonDecode(dataResponse.body)).data;
final previousVersion = CachedDrugs.instance.version;
CachedDrugs.instance.drugs = data.drugs;
CachedDrugs.instance.version = data.version;
await CachedDrugs.save();

final context = PharMeApp.navigatorKey.currentContext;
if (context != null) {
// ignore: use_build_context_synchronously
await showCupertinoModalPopup(
context: context,
builder: (context) => CupertinoAlertDialog(
title: Text(context.l10n.update_warning_title),
content: Text(context.l10n.update_warning_body),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () => Navigator.pop(context),
child: Text(context.l10n.action_continue),
),
],
),
);
if (previousVersion != null) {
final context = PharMeApp.navigatorKey.currentContext;
if (context != null) {
// ignore: use_build_context_synchronously
await showCupertinoModalPopup(
context: context,
builder: (context) => CupertinoAlertDialog(
title: Text(context.l10n.update_warning_title),
content: Text(context.l10n.update_warning_body),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
onPressed: () => Navigator.pop(context),
child: Text(context.l10n.action_continue),
),
],
),
);
}
}
}
32 changes: 32 additions & 0 deletions app/lib/common/widgets/full_width_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import '../module.dart';

class FullWidthButton extends StatelessWidget {
const FullWidthButton(
this.text,
this.action, {
Key? key,
this.enabled = true,
}) : super(key: key);

final bool enabled;
final String text;
final void Function() action;

@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: enabled ? action : null,
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
),
),
child: Text(text),
),
);
}
}
12 changes: 12 additions & 0 deletions app/lib/drugselection/module.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../common/module.dart';
import 'pages/drugselection.dart';

// We need to expose all pages for AutoRouter
export 'pages/cubit.dart';
export 'pages/drugselection.dart';

const drugSelectionRoutes = AutoRoute(
path: 'drugselection',
name: 'DrugSelectionRouter',
page: DrugSelectionPage,
);
24 changes: 24 additions & 0 deletions app/lib/drugselection/pages/cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:freezed_annotation/freezed_annotation.dart';

import '../../../common/module.dart';
import '../../common/pages/drug/cubit.dart';

part 'cubit.freezed.dart';

class DrugSelectionPageCubit extends Cubit<DrugSelectionPageState> {
DrugSelectionPageCubit() : super(DrugSelectionPageState.stable());

// ignore: avoid_positional_boolean_parameters
Future<void> updateDrugActivity(Drug drug, bool? value) async {
if (value == null) return;
emit(DrugSelectionPageState.updating());
await setDrugActivity(drug, value);
emit(DrugSelectionPageState.stable());
}
}

@freezed
class DrugSelectionPageState with _$DrugSelectionPageState {
const factory DrugSelectionPageState.stable() = _StableState;
const factory DrugSelectionPageState.updating() = _UpdatingState;
}
95 changes: 95 additions & 0 deletions app/lib/drugselection/pages/drugselection.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import '../../common/models/drug/cached_drugs.dart';
import '../../common/module.dart' hide MetaData;
import '../../common/widgets/full_width_button.dart';
import 'cubit.dart';

class DrugSelectionPage extends HookWidget {
const DrugSelectionPage({
Key? key,
@visibleForTesting this.cubit,
}) : super(key: key);

final DrugSelectionPageCubit? cubit;

@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => cubit ?? DrugSelectionPageCubit(),
child: BlocBuilder<DrugSelectionPageCubit, DrugSelectionPageState>(
builder: (context, state) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: ListView(
children: [
_buildHeader(context),
..._buildDrugList(context, state),
],
),
),
),
);
}
)
);
}

Widget _buildHeader(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: [
Text(
context.l10n.drug_selection_header,
style: PharMeTheme.textTheme.headlineLarge),
SizedBox(height: PharMeTheme.mediumSpace),
Text(
context.l10n.drug_selection_description,
style: PharMeTheme.textTheme.bodyLarge),
SizedBox(height: PharMeTheme.mediumSpace),
Text(
context.l10n.drug_selection_later,
style: PharMeTheme.textTheme.bodyLarge),
SizedBox(height: PharMeTheme.mediumSpace),
]
),
);
}

List<Widget> _buildDrugList(
BuildContext context,
DrugSelectionPageState state
) {
var enabled = true;
state.when(
stable: () => enabled = true,
updating: () => enabled = false
);
return [
// ...[...CachedDrugs.instance.drugs!, ...CachedDrugs.instance.drugs!, ...CachedDrugs.instance.drugs!].map(
...CachedDrugs.instance.drugs!.map(
(drug) => CheckboxListTile(
enabled: enabled,
value: UserData.instance.activeDrugNames!
.contains(drug.name),
onChanged: (value) {
context
.read<DrugSelectionPageCubit>()
.updateDrugActivity(drug, value);
},
title: Text(drug.name.capitalize()),
subtitle: Text(
'(${drug.annotations.brandNames.join(", ")})'
),
)
).toList(),
SizedBox(height: PharMeTheme.mediumSpace),
FullWidthButton(
context.l10n.general_continue,
() { context.router.replace(MainRoute()); },
enabled: enabled,
),
];
}
}
4 changes: 4 additions & 0 deletions app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"auth_choose_lab": "Please select your data provider",
"auth_sign_in": "Get data",
"auth_success": "Successfully imported data",

"drug_selection_header": "Select active drugs",
"drug_selection_description": "Please select the drugs you are currently taking below. If you are not taking checked drugs anymore, you can uncheck them.",
"drug_selection_later": "You can always change the status for each drug later on a drug's detail page.",

"err_could_not_retrieve_access_token": "An unexpected error occurred while retrieving the access token",
"err_fetch_user_data_failed": "An unexpected error occurred while fetching your genomic data",
Expand Down
2 changes: 2 additions & 0 deletions app/lib/login/pages/cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class LoginPageCubit extends Cubit<LoginPageState> {
token, lab.starAllelesUrl.toString());
await fetchAndSaveLookups();

await updateCachedDrugs();

// login + fetching of data successful
MetaData.instance.isLoggedIn = true;
await MetaData.save();
Expand Down
17 changes: 2 additions & 15 deletions app/lib/login/pages/login.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:dropdown_button2/dropdown_button2.dart';

import '../../../common/module.dart';
import '../../common/widgets/full_width_button.dart';
import '../models/lab.dart';
import 'cubit.dart';

Expand Down Expand Up @@ -163,21 +164,7 @@ class LoginPage extends HookWidget {
children: [
...children,
SizedBox(height: PharMeTheme.mediumSpace),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: action,
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
),
),
child: Text(actionText),
),
),
],
FullWidthButton(actionText, action ?? () {}), ],
);
}
}
2 changes: 1 addition & 1 deletion app/lib/onboarding/pages/onboarding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class OnboardingPage extends HookWidget {
key: Key('nextButton'),
onPressed: () {
if (isLastPage) {
context.router.replace(MainRoute());
context.router.replace(DrugSelectionRouter());
} else {
pageController.nextPage(
duration: Duration(milliseconds: 500),
Expand Down