Skip to content

Commit

Permalink
Merge pull request #616 from hpi-dhc/issue/480-active-drugs-onboarding
Browse files Browse the repository at this point in the history
Issue/480 active drugs onboarding
  • Loading branch information
tamslo authored Jun 20, 2023
2 parents 8295c3a + 01547ca commit 78fb117
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 37 deletions.
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

0 comments on commit 78fb117

Please sign in to comment.