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

Dynamically limit the number of elements rendered on Scan card. #648

Merged
merged 18 commits into from
Nov 12, 2021
12 changes: 5 additions & 7 deletions packages/smooth_app/lib/helpers/product_cards_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,17 @@ String getProductName(Product product, AppLocalizations appLocalizations) =>
const EdgeInsets SMOOTH_CARD_PADDING =
EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0);

/// A SmoothCard on Product cards using standardized margin.
/// A SmoothCard on Product cards using default margin and padding.
Widget buildProductSmoothCard({
Widget? header,
required Widget body,
EdgeInsets? padding = EdgeInsets.zero,
EdgeInsets? margin = const EdgeInsets.symmetric(
horizontal: SMALL_SPACE,
),
}) {
return SmoothCard(
margin: const EdgeInsets.only(
right: SMALL_SPACE,
left: SMALL_SPACE,
top: VERY_SMALL_SPACE,
bottom: VERY_LARGE_SPACE,
),
margin: margin,
padding: padding,
header: header,
child: body,
Expand Down
16 changes: 11 additions & 5 deletions packages/smooth_app/lib/pages/product/new_product_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:smooth_app/pages/product/common/product_dialog_helper.dart';
import 'package:smooth_app/pages/product/summary_card.dart';
import 'package:smooth_app/themes/smooth_theme.dart';
import 'package:smooth_app/themes/theme_provider.dart';
import 'package:smooth_ui_library/util/ui_helpers.dart';

class NewProductPage extends StatefulWidget {
const NewProductPage(this.product);
Expand Down Expand Up @@ -188,7 +189,7 @@ class _ProductPageState extends State<NewProductPage> {
alignment: Alignment.topLeft,
child: _buildProductImagesCarousel(context),
),
SummaryCard(_product, _productPreferences),
SummaryCard(_product, _productPreferences, isRenderedInProductPage: true),
_buildKnowledgePanelCards(),
]);
}
Expand Down Expand Up @@ -217,10 +218,15 @@ class _ProductPageState extends State<NewProductPage> {
}
final List<Widget> widgetsWrappedInSmoothCards = <Widget>[];
for (final Widget widget in knowledgePanelWidgets) {
widgetsWrappedInSmoothCards.add(buildProductSmoothCard(
body: widget,
padding: SMOOTH_CARD_PADDING,
));
widgetsWrappedInSmoothCards.add(
Padding(
padding: const EdgeInsets.only(top: VERY_LARGE_SPACE),
child: buildProductSmoothCard(
body: widget,
padding: SMOOTH_CARD_PADDING,
),
),
);
}
return Center(
child: Column(
Expand Down
156 changes: 119 additions & 37 deletions packages/smooth_app/lib/pages/product/summary_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import 'package:smooth_ui_library/util/ui_helpers.dart';

const List<String> _SCORE_ATTRIBUTE_IDS = <String>[
Attribute.ATTRIBUTE_NUTRISCORE,
Attribute.ATTRIBUTE_ECOSCORE
Attribute.ATTRIBUTE_ECOSCORE,
];

const List<String> _ATTRIBUTE_GROUP_ORDER = <String>[
Expand All @@ -27,19 +27,106 @@ const List<String> _ATTRIBUTE_GROUP_ORDER = <String>[
AttributeGroup.ATTRIBUTE_GROUP_LABELS,
];

class SummaryCard extends StatelessWidget {
// TODO(jasmeet): Change the signature to
// SummaryCard({ required this.product, required this.productPreferences });
const SummaryCard(this._product, this._productPreferences);
// Each row in the summary card takes roughly 40px.
const int SUMMARY_CARD_ROW_HEIGHT = 40;
Comment on lines +30 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's hard to say, what happens if the user has as an example adjusted his font size


class SummaryCard extends StatefulWidget {
const SummaryCard(this._product, this._productPreferences,
{this.isRenderedInProductPage = false});

final Product _product;
final ProductPreferences _productPreferences;
final bool isRenderedInProductPage;

@override
State<SummaryCard> createState() => _SummaryCardState();
}

class _SummaryCardState extends State<SummaryCard> {
// Number of Rows that will be printed in the SummaryCard, initialized to a
// very high number for infinite rows.
int totalPrintableRows = 10000;

@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
if (widget.isRenderedInProductPage) {
return buildProductSmoothCard(
header: _buildProductCompatibilityHeader(context),
body: Padding(
padding: SMOOTH_CARD_PADDING,
child: _buildSummaryCardContent(context),
),
);
} else {
return _buildLimitedSizeSummaryCard(constraints.maxHeight);
}
});
}

Widget _buildLimitedSizeSummaryCard(double parentHeight) {
totalPrintableRows = parentHeight ~/ SUMMARY_CARD_ROW_HEIGHT;
return Stack(
children: <Widget>[
ClipRRect(
borderRadius:
const BorderRadius.vertical(bottom: SmoothCard.CIRCULAR_RADIUS),
child: OverflowBox(
alignment: AlignmentDirectional.topStart,
minHeight: parentHeight,
maxHeight: double.infinity,
child: buildProductSmoothCard(
header: _buildProductCompatibilityHeader(context),
body: Padding(
padding: SMOOTH_CARD_PADDING,
child: _buildSummaryCardContent(context),
),
margin: EdgeInsets.zero,
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
padding: const EdgeInsets.symmetric(
vertical: SMALL_SPACE,
),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(bottom: SmoothCard.CIRCULAR_RADIUS),
),
child: Center(
// TODO(jasmeet): Internationalize
child: Text(
'Tap to see more info...',
style: Theme.of(context)
.textTheme
.bodyText1!
.apply(color: Colors.lightBlue),
),
),
),
],
),
],
);
}

Widget _buildSummaryCardContent(BuildContext context) {
final List<Attribute> scoreAttributes =
AttributeListExpandable.getPopulatedAttributes(
_product, _SCORE_ATTRIBUTE_IDS);
widget._product, _SCORE_ATTRIBUTE_IDS);

// Header takes 1 row.
// Product Title Tile takes 2 rows to render.
// Footer takes 1 row.
totalPrintableRows -= 4;
// Each Score card takes about 1.5 rows to render.
totalPrintableRows -= (1.5 * scoreAttributes.length).ceil();

final List<AttributeGroup> attributeGroupsToBeRendered =
_getAttributeGroupsToBeRendered();
Expand All @@ -57,32 +144,25 @@ class SummaryCard extends StatelessWidget {
],
),
);

return buildProductSmoothCard(
header: _buildProductCompatibilityHeader(context),
body: Padding(
padding: SMOOTH_CARD_PADDING,
child: Column(
children: <Widget>[
_buildProductTitleTile(context),
for (final Attribute attribute in scoreAttributes)
ScoreCard(
iconUrl: attribute.iconUrl!,
description:
attribute.descriptionShort ?? attribute.description!,
cardEvaluation: getCardEvaluationFromAttribute(attribute),
),
attributesContainer,
],
),
),
return Column(
children: <Widget>[
_buildProductTitleTile(context),
for (final Attribute attribute in scoreAttributes)
ScoreCard(
iconUrl: attribute.iconUrl!,
description: attribute.descriptionShort ?? attribute.description!,
cardEvaluation: getCardEvaluationFromAttribute(attribute),
),
attributesContainer,
],
);
}

List<AttributeGroup> _getAttributeGroupsToBeRendered() {
final List<AttributeGroup> attributeGroupsToBeRendered = <AttributeGroup>[];
for (final String groupId in _ATTRIBUTE_GROUP_ORDER) {
final Iterable<AttributeGroup> groupIterable = _product.attributeGroups!
final Iterable<AttributeGroup> groupIterable = widget
._product.attributeGroups!
.where((AttributeGroup group) => group.id == groupId);
if (groupIterable.isEmpty) {
continue;
Expand All @@ -91,7 +171,8 @@ class SummaryCard extends StatelessWidget {

final bool containsImportantAttributes = group.attributes!.any(
(Attribute attribute) =>
_productPreferences.isAttributeImportant(attribute.id!) == true);
widget._productPreferences.isAttributeImportant(attribute.id!) ==
true);
if (containsImportantAttributes) {
attributeGroupsToBeRendered.add(group);
}
Expand All @@ -101,7 +182,7 @@ class SummaryCard extends StatelessWidget {

Widget _buildProductCompatibilityHeader(BuildContext context) {
final ProductCompatibility compatibility =
getProductCompatibility(_productPreferences, _product);
getProductCompatibility(widget._productPreferences, widget._product);
// NOTE: This is temporary and will be updated once the feature is supported
// by the server.
return Container(
Expand Down Expand Up @@ -133,12 +214,12 @@ class SummaryCard extends StatelessWidget {
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
getProductName(_product, appLocalizations),
getProductName(widget._product, appLocalizations),
style: themeData.textTheme.headline4,
),
subtitle: Text(_product.brands ?? appLocalizations.unknownBrand),
subtitle: Text(widget._product.brands ?? appLocalizations.unknownBrand),
trailing: Text(
_product.quantity ?? '',
widget._product.quantity ?? '',
style: themeData.textTheme.headline3,
),
),
Expand All @@ -159,13 +240,16 @@ class SummaryCard extends StatelessWidget {
returnNullIfStatusUnknown:
group.id == AttributeGroup.ATTRIBUTE_GROUP_LABELS,
);
if (attributeChip != null) {
if (attributeChip != null &&
attributeChips.length / 2 < totalPrintableRows) {
attributeChips.add(attributeChip);
}
}
if (attributeChips.isEmpty) {
return EMPTY_WIDGET;
}
totalPrintableRows =
totalPrintableRows - (attributeChips.length / 2).ceil();
return Column(
children: <Widget>[
_buildAttributeGroupHeader(context, group, isFirstGroup),
Expand Down Expand Up @@ -216,7 +300,8 @@ class SummaryCard extends StatelessWidget {
// Score Attribute Ids have already been rendered.
return null;
}
if (_productPreferences.isAttributeImportant(attribute.id!) != true) {
if (widget._productPreferences.isAttributeImportant(attribute.id!) !=
true) {
// Not an important attribute.
return null;
}
Expand All @@ -238,10 +323,7 @@ class SummaryCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
attributeIcon,
Expanded(
child: Text(
attributeDisplayTitle,
)),
Expanded(child: Text(attributeDisplayTitle)),
]));
});
}
Expand Down