Skip to content

fix: New UI for the food preferences #6466

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

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
7 changes: 5 additions & 2 deletions packages/smooth_app/lib/helpers/attributes_card_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ enum AttributeEvaluation {
}
}

Widget getAttributeDisplayIcon(final Attribute attribute) {
Widget getAttributeDisplayIcon(final Attribute attribute,
{bool? isFoodPreferences = false, BuildContext? context}) {
return Padding(
padding: const EdgeInsetsDirectional.only(end: VERY_SMALL_SPACE),
child: attribute.getCircledIcon(
backgroundColor: getAttributeDisplayBackgroundColor(attribute),
backgroundColor: isFoodPreferences!
? Theme.of(context!).primaryColor
: getAttributeDisplayBackgroundColor(attribute),
size: 32.0,
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,33 @@ class AttributeGroupListTile extends StatelessWidget {
final Widget icon;

@override
Widget build(BuildContext context) => Padding(
padding: const EdgeInsets.symmetric(
horizontal: LARGE_SPACE,
vertical: LARGE_SPACE,
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
),
child: DefaultTextStyle.merge(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[title, icon],
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: LARGE_SPACE,
vertical: LARGE_SPACE,
),
child: DefaultTextStyle.merge(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(15),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[title, icon],
),
),
style: Theme.of(context).textTheme.headlineMedium,
),
style: Theme.of(context).textTheme.headlineMedium,
),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,29 @@ class UserPreferencesAttributeGroup {
result.add(
UserPreferencesItemSimple(
labels: <String>[],
builder: (_) => InkWell(
onTap: () async => userPreferences.setActiveAttributeGroup(group.id!),
child: AttributeGroupListTile(
title: Text(
group.name ?? appLocalizations.unknown,
style: themeData.textTheme.titleLarge,
builder: (_) => Padding(
padding: const EdgeInsets.only(
left: LARGE_SPACE,
right: LARGE_SPACE,
),
child: Card(
shape: const RoundedRectangleBorder(),
margin: const EdgeInsets.only(top: LARGE_SPACE),
child: InkWell(
onTap: () async =>
userPreferences.setActiveAttributeGroup(group.id!),
child: AttributeGroupListTile(
title: Text(
group.name ?? appLocalizations.unknown,
style: themeData.textTheme.titleLarge!.copyWith(
color: Colors.white,
),
),
icon: collapsed!
? const Icon(Icons.keyboard_arrow_right)
: const Icon(Icons.keyboard_arrow_down),
),
),
icon: collapsed!
? const Icon(Icons.keyboard_arrow_right)
: const Icon(Icons.keyboard_arrow_down),
),
),
),
Expand Down Expand Up @@ -96,7 +109,14 @@ class UserPreferencesAttributeGroup {
if (attribute.id != null) attribute.id!,
if (attribute.name != null) attribute.name!,
],
builder: (_) => AttributeButton(attribute, productPreferences),
builder: (_) => Padding(
padding: const EdgeInsets.symmetric(horizontal: LARGE_SPACE),
child: Card(
shape: const RoundedRectangleBorder(),
margin: EdgeInsets.zero,
child: AttributeButton(attribute, productPreferences),
),
),
),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,23 @@ class UserPreferencesFood extends AbstractUserPreferences {
List<Widget> getOnboardingContent() {
final List<Widget> result = <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: LARGE_SPACE),
padding: const EdgeInsets.symmetric(
horizontal: LARGE_SPACE,
),
child: Text(
getTitleString(),
style: themeData.textTheme.displayMedium,
),
),
];
for (final UserPreferencesItem item in _getOnboardingBody()) {
result.add(item.builder(context));
result.add(Padding(
padding: const EdgeInsets.only(
left: SMALL_SPACE,
right: SMALL_SPACE,
),
child: item.builder(context),
));
}
return result;
}
Expand Down
179 changes: 97 additions & 82 deletions packages/smooth_app/lib/widgets/attribute_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/data_models/product_preferences.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart';
import 'package:smooth_app/helpers/attributes_card_helper.dart';

/// Colored button for attribute importance, with corresponding action
class AttributeButton extends StatelessWidget {
class AttributeButton extends StatefulWidget {
const AttributeButton(
this.attribute,
this.productPreferences,
Expand All @@ -23,100 +23,115 @@ class AttributeButton extends StatelessWidget {
PreferenceImportance.ID_MANDATORY,
];

@override
State<AttributeButton> createState() => _AttributeButtonState();
}

class _AttributeButtonState extends State<AttributeButton> {
bool editMode = false;
@override
Widget build(BuildContext context) {
final ThemeData themeData = Theme.of(context);
final String currentImportanceId =
productPreferences.getImportanceIdForAttributeId(attribute.id!);
const double horizontalPadding = LARGE_SPACE;
final double widgetWidth =
MediaQuery.sizeOf(context).width - 2 * horizontalPadding;
final double importanceWidth = widgetWidth / 4;
final String currentImportanceId = widget.productPreferences
.getImportanceIdForAttributeId(widget.attribute.id!);
final TextStyle style = themeData.textTheme.headlineMedium!;
final String? info = attribute.settingNote;
final String? info = widget.attribute.settingNote;
final List<Widget> children = <Widget>[];
for (final String importanceId in _importanceIds) {
if (!editMode) {
children.add(
Expanded(
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () async => productPreferences.setImportance(
attribute.id!,
InkWell(
onTap: () async => widget.productPreferences.setImportance(
widget.attribute.id!,
currentImportanceId,
),
child: ListTile(
leading: Icon(
Icons.radio_button_checked,
color: themeData.colorScheme.primary,
),
title: AutoSizeText(
widget.productPreferences
.getPreferenceImportanceFromImportanceId(currentImportanceId)!
.name!,
),
trailing: IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
setState(() => editMode = !editMode);
},
),
),
),
);
} else {
for (final String importanceId in AttributeButton._importanceIds) {
children.add(
InkWell(
onTap: () async {
setState(() => editMode = !editMode);
widget.productPreferences.setImportance(
widget.attribute.id!,
importanceId,
);
},
child: ListTile(
leading: Icon(
currentImportanceId == importanceId
? Icons.radio_button_checked
: Icons.radio_button_off,
color: themeData.colorScheme.primary,
),
child: Container(
width: importanceWidth,
margin: const EdgeInsets.symmetric(horizontal: 2.0),
constraints:
const BoxConstraints(minHeight: MINIMUM_TOUCH_SIZE),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(
currentImportanceId == importanceId
? Icons.radio_button_checked
: Icons.radio_button_off,
color: themeData.colorScheme.primary,
),
const SizedBox(height: VERY_SMALL_SPACE),
AutoSizeText(
productPreferences
.getPreferenceImportanceFromImportanceId(
importanceId)!
.name!,
maxLines: 2,
textAlign: TextAlign.center,
),
],
),
title: AutoSizeText(
widget.productPreferences
.getPreferenceImportanceFromImportanceId(importanceId)!
.name!,
maxLines: 2,
),
),
),
),
);
);
}
}
return Padding(
padding: const EdgeInsets.symmetric(
vertical: SMALL_SPACE,
horizontal: horizontalPadding,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
trailing: info == null ? null : const Icon(Icons.info_outline),
title: AutoSizeText(
attribute.settingName ?? attribute.name!,
maxLines: 2,
style: style,
),
onTap: info == null
? null
: () async => showDialog<void>(
context: context,
builder: (BuildContext context) {
final AppLocalizations appLocalizations =
AppLocalizations.of(context);
return SmoothAlertDialog(
body: Text(info),
positiveAction: SmoothActionButton(
text: appLocalizations.close,
onPressed: () => Navigator.pop(context),
),
);
},
),
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ListTile(
leading: getAttributeDisplayIcon(
widget.attribute,
context: context,
isFoodPreferences: true,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
tileColor: Theme.of(context).colorScheme.secondary,
trailing: info == null ? null : const Icon(Icons.info_outline),
title: AutoSizeText(
widget.attribute.settingName ?? widget.attribute.name!,
maxLines: 2,
style: style,
),
],
),
onTap: info == null
? null
: () async => showDialog<void>(
context: context,
builder: (BuildContext context) {
final AppLocalizations appLocalizations =
AppLocalizations.of(context);
return SmoothAlertDialog(
body: Text(info),
positiveAction: SmoothActionButton(
text: appLocalizations.close,
onPressed: () => Navigator.pop(context),
),
);
},
),
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
),
],
);
}
}