Skip to content

Commit

Permalink
feat(#691): style filters
Browse files Browse the repository at this point in the history
  • Loading branch information
tamslo committed Feb 23, 2024
1 parent 0d9c07f commit 48a9af0
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 66 deletions.
12 changes: 12 additions & 0 deletions app/lib/common/models/drug/warning_level.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ enum WarningLevel {
none,
}

extension WarningLevelLabel on WarningLevel {
String getLabel(BuildContext context) {
final labelMap = {
WarningLevel.red.name: context.l10n.warning_level_red,
WarningLevel.yellow.name: context.l10n.warning_level_yellow,
WarningLevel.green.name: context.l10n.warning_level_green,
WarningLevel.none.name: context.l10n.warning_level_missing,
};
return labelMap[name]!;
}
}

extension WarningLevelIcon on WarningLevel {
static final _iconMap = {
WarningLevel.red.name: Icons.dangerous_rounded,
Expand Down
213 changes: 154 additions & 59 deletions app/lib/common/widgets/drug_search/filter_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class FilterMenuItem {
bool _value;
// ignore: avoid_positional_boolean_parameters
final void Function(bool newValue) updateSearch;
final Widget Function(BuildContext context, {
final Widget Function(
BuildContext context, {
required bool value,
required Function statefulOnChange,
}) build;
Expand All @@ -20,9 +21,8 @@ class FilterMenuItem {
}

class FilterMenu extends HookWidget {
const FilterMenu(this.cubit, this.state, this.activeDrugs, {
required this.useDrugClass
});
const FilterMenu(this.cubit, this.state, this.activeDrugs,
{required this.useDrugClass});

final DrugListCubit cubit;
final DrugListState state;
Expand All @@ -35,87 +35,182 @@ class FilterMenu extends HookWidget {
}

Widget? _buildFilters(BuildContext context) {
return state.whenOrNull(loaded: (allDrugs, filter) =>
SafeArea(
child: Column(
children: _geMenuItems(context, allDrugs, filter, activeDrugs),
return state.whenOrNull(
loaded: (allDrugs, filter) => SafeArea(
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: PharMeTheme.surfaceColor,
width: PharMeTheme.smallSpace,
),
borderRadius: BorderRadius.only(
topRight: Radius.circular(PharMeTheme.smallSpace),
)),
child: Container(
color: PharMeTheme.surfaceColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
top: PharMeTheme.mediumSpace,
right: PharMeTheme.mediumSpace,
bottom: PharMeTheme.mediumSpace,
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IconButton(
onPressed: Scaffold.of(context).closeDrawer,
icon: Icon(Icons.arrow_back_ios_rounded),
color: PharMeTheme.iconColor,
visualDensity: VisualDensity.compact,
),
SizedBox(width: PharMeTheme.smallSpace * 0.5),
Text(
context.l10n.search_page_filter_heading,
style: PharMeTheme.textTheme.headlineMedium,
),
],
),
),
Padding(
padding: EdgeInsets.only(
left: PharMeTheme.mediumSpace,
right: PharMeTheme.mediumSpace,
bottom: PharMeTheme.mediumSpace,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: PharMeTheme.mediumSpace),
SubheaderDivider(
text: context.l10n.search_page_filter_subheading_usage,
useLine: false,
padding: 0,
),
_getDrugStatusFilter(context, allDrugs, filter),
SizedBox(height: PharMeTheme.mediumSpace),
SubheaderDivider(
text: context.l10n.search_page_filter_subheading_level,
useLine: false,
padding: 0,
),
SizedBox(height: PharMeTheme.smallSpace),
..._getWarningLevelFilters(context, allDrugs, filter),
],
),
),
],
),
),
),
));
}

int _getFilteredNumber({
required FilterState itemFilter,
required List<Drug> drugs,
}) {
return itemFilter
.filter(drugs, activeDrugs, useDrugClass: useDrugClass)
.length;
}

Widget _getFilterText(
String text, {
required FilterState itemFilter,
required List<Drug> drugs,
}) {
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(text),
Text(
' (${_getFilteredNumber(itemFilter: itemFilter, drugs: drugs)})',
style: PharMeTheme.textTheme.labelMedium!.copyWith(
color: darkenColor(PharMeTheme.onSurfaceText, -0.2),
),
),
)
],
);
}

List<Widget> _geMenuItems(
Widget _getDrugStatusFilter(
BuildContext context,
List<Drug> drugs,
FilterState filter,
ActiveDrugs activeDrugs,
) {
String formatItemFilterNumber(FilterState itemFilter) =>
'(${
itemFilter.filter(drugs, activeDrugs, useDrugClass: useDrugClass).length
})';
String drugStatusNumber({ required bool showInactive}) =>
formatItemFilterNumber(FilterState.from(
final value = filter.showInactive;
FilterState drugStatusFilterState({required bool showInactive}) {
return FilterState.from(
FilterState.initial(),
showInactive: showInactive,
));
String warningLevelNumber(WarningLevel warningLevel) {
final currentWarningLevelFilter = FilterState.from(filter);
currentWarningLevelFilter.showWarningLevel.forEach(
(currentWarningLevel, currentValue) =>
currentWarningLevelFilter.showWarningLevel[currentWarningLevel] =
currentWarningLevel == warningLevel
);
return formatItemFilterNumber(currentWarningLevelFilter);
}
Widget buildDrugStatusItem() {
final value = filter.showInactive;
return DropdownButton<bool>(
value: value,
items: [
DropdownMenuItem<bool>(
value: true,
child: Text(
'${context.l10n.search_page_filter_all_drugs} '
'${drugStatusNumber(showInactive: true)}'
),
return DropdownButton<bool>(
value: value,
items: [
DropdownMenuItem<bool>(
value: true,
child: _getFilterText(
context.l10n.search_page_filter_all_drugs,
itemFilter: drugStatusFilterState(showInactive: true),
drugs: drugs,
),
DropdownMenuItem<bool>(
value: false,
child: Text(
'${context.l10n.search_page_filter_only_active_drugs} '
'${drugStatusNumber(showInactive: false)}'
),
),
DropdownMenuItem<bool>(
value: false,
child: _getFilterText(
context.l10n.search_page_filter_only_active_drugs,
itemFilter: drugStatusFilterState(showInactive: false),
drugs: drugs,
),
],
onChanged: (newValue) => newValue != value
? cubit.search(showInactive: newValue)
: null,
);
),
],
onChanged: (newValue) =>
newValue != value ? cubit.search(showInactive: newValue) : null,
);
}

List<Widget> _getWarningLevelFilters(
BuildContext context,
List<Drug> drugs,
FilterState filter,
) {
FilterState warningLevelFilter(WarningLevel warningLevel) {
final currentFilter = FilterState.from(filter);
currentFilter.showWarningLevel.forEach(
(currentWarningLevel, currentValue) =>
currentFilter.showWarningLevel[currentWarningLevel] =
currentWarningLevel == warningLevel);
return currentFilter;
}
Widget buildWarningLevelItem(WarningLevel warningLevel) {
final value = filter.showWarningLevel[warningLevel]!;
return ActionChip(
onPressed: () => cubit.search(
showWarningLevel: { warningLevel: !value },
showWarningLevel: {warningLevel: !value},
),
avatar: Icon(
value ? warningLevel.icon : warningLevel.outlinedIcon,
color: value ? PharMeTheme.onSurfaceText : warningLevel.textColor,
color: PharMeTheme.onSurfaceText,
),
label: _getFilterText(
warningLevel.getLabel(context),
itemFilter: warningLevelFilter(warningLevel),
drugs: drugs,
),
label: Text(warningLevelNumber(warningLevel),
style: TextStyle(color: PharMeTheme.onSurfaceText)),
visualDensity: VisualDensity.compact,
color: MaterialStatePropertyAll(value
? warningLevel.color
: Colors.transparent
color: MaterialStatePropertyAll(
value ? warningLevel.color : Colors.transparent),
side: BorderSide(
color: value ? warningLevel.color : PharMeTheme.onSurfaceColor,
),
);
}
return [
buildDrugStatusItem(),
...WarningLevel.values
.map(buildWarningLevelItem),
];
return WarningLevel.values.map(buildWarningLevelItem).toList();
}
}
6 changes: 3 additions & 3 deletions app/lib/common/widgets/subheader_divider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import '../module.dart';
class SubheaderDivider extends StatelessWidget {
const SubheaderDivider({
this.text = '',
this.indent = 20.0,
this.padding,
this.color,
this.useLine = true,
super.key,
});

final String text;
final double indent;
final double? padding;
final Color? color;
final bool useLine;

@override
Widget build(BuildContext context) {
final widgetColor = color ?? Colors.grey[600];
return Padding(
padding: EdgeInsets.all(PharMeTheme.smallSpace),
padding: EdgeInsets.all(padding ?? PharMeTheme.smallSpace),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down
12 changes: 8 additions & 4 deletions app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,19 @@
"general_and": "and",
"general_poor_metabolizer": "Poor Metabolizer",
"general_not_tested": "Not tested",

"warning_level_green": "Standard precaution",
"warning_level_missing": "Standard precaution (missing data)",
"warning_level_yellow": "Use with caution",
"warning_level_red": "Consider avoiding",

"search_page_tooltip_search": "Search for drugs by their name, brand name or class.",
"search_page_tooltip_search_no_class": "Search for drugs by their name or brand name.",
"search_page_filter_heading": "Filter drugs",
"search_page_filter_subheading_usage": "Filter by usage status",
"search_page_filter_subheading_level": "Filter by guideline result",
"search_page_filter_all_drugs": "All drugs",
"search_page_filter_only_active_drugs": "Currently taken drugs",
"search_page_filter_green": "Green warning level",
"search_page_filter_yellow": "Yellow warning level",
"search_page_filter_red": "Red warning level",
"search_page_filter_only_with_guidelines": "Only drugs with guidelines",
"search_page_indicator_explanation": "Taking drugs with an {indicatorName} ({indicator}) can influence your results for other drugs",
"@search_page_indicator_explanation": {
"placeholders": {
Expand Down

0 comments on commit 48a9af0

Please sign in to comment.