Skip to content

Commit

Permalink
fix: Optimized version of the scan cards for small screens (openfoodf…
Browse files Browse the repository at this point in the history
…acts#5928)

* Optimized version of the scan cards for small screens

* Fix some Rive animations

* Use a slideup transition from the carousel
  • Loading branch information
g123k authored Nov 25, 2024
1 parent 3580504 commit c8d5392
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 69 deletions.
Binary file modified packages/smooth_app/assets/animations/off.riv
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/pages/product/hideable_container.dart';
import 'package:smooth_app/pages/scan/carousel/scan_carousel.dart';
import 'package:smooth_app/resources/app_icons.dart' as icons;
import 'package:smooth_app/themes/smooth_theme.dart';
import 'package:smooth_app/themes/smooth_theme_colors.dart';
Expand All @@ -27,7 +29,8 @@ class ScanProductBaseCard extends StatelessWidget {
super.key,
});

static const double HEADER_MIN_HEIGHT = 50.0;
static const double HEADER_MIN_HEIGHT_NORMAL = 50.0;
static const double HEADER_MIN_HEIGHT_DENSE = 45.0;

final String headerLabel;
final Color headerIndicatorColor;
Expand Down Expand Up @@ -145,10 +148,13 @@ class _SmoothProductCardHeader extends StatelessWidget {
context.extension<SmoothColorsThemeExtension>().primarySemiDark;
final String closeTooltip =
AppLocalizations.of(context).carousel_close_tooltip;
final bool dense = context.read<ScanCardDensity>() == ScanCardDensity.DENSE;

return ConstrainedBox(
constraints: const BoxConstraints(
minHeight: ScanProductBaseCard.HEADER_MIN_HEIGHT,
constraints: BoxConstraints(
minHeight: dense
? ScanProductBaseCard.HEADER_MIN_HEIGHT_DENSE
: ScanProductBaseCard.HEADER_MIN_HEIGHT_NORMAL,
),
child: DecoratedBox(
decoration: BoxDecoration(
Expand All @@ -170,7 +176,7 @@ class _SmoothProductCardHeader extends StatelessWidget {
color: indicatorColor,
),
),
const SizedBox(width: MEDIUM_SPACE),
SizedBox(width: dense ? BALANCED_SPACE : MEDIUM_SPACE),
Expanded(
child: Text(
label,
Expand Down Expand Up @@ -237,11 +243,14 @@ class ScanProductBaseCardTitle extends StatelessWidget {

@override
Widget build(BuildContext context) {
final bool dense = context.read<ScanCardDensity>() == ScanCardDensity.DENSE;

return SizedBox(
width: double.infinity,
child: Padding(
padding:
const EdgeInsetsDirectional.only(bottom: MEDIUM_SPACE).copyWith(
padding: EdgeInsetsDirectional.only(
bottom: dense ? SMALL_SPACE : MEDIUM_SPACE,
).copyWith(
top: padding?.top,
bottom: padding?.bottom,
start: padding?.start,
Expand Down Expand Up @@ -293,11 +302,12 @@ class ScanProductBaseCardBarcode extends StatelessWidget {
final SmoothColorsThemeExtension theme =
context.extension<SmoothColorsThemeExtension>();
final bool lightTheme = context.lightTheme();
final bool dense = context.read<ScanCardDensity>() == ScanCardDensity.DENSE;

return Padding(
padding: const EdgeInsetsDirectional.only(
top: MEDIUM_SPACE,
bottom: LARGE_SPACE * 2,
padding: EdgeInsetsDirectional.only(
top: dense ? SMALL_SPACE : MEDIUM_SPACE,
bottom: dense ? BALANCED_SPACE : LARGE_SPACE * 2,
).copyWith(
top: padding?.top,
bottom: padding?.bottom,
Expand All @@ -311,14 +321,14 @@ class ScanProductBaseCardBarcode extends StatelessWidget {
),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 100.0,
constraints: BoxConstraints(
minHeight: dense ? 75.0 : 100.0,
),
child: SmoothBarcodeWidget(
height: height ?? 100.0,
padding: const EdgeInsetsDirectional.symmetric(
padding: EdgeInsetsDirectional.symmetric(
horizontal: 30.0,
vertical: MEDIUM_SPACE,
vertical: dense ? SMALL_SPACE : MEDIUM_SPACE,
),
color: Colors.black,
backgroundColor: lightTheme ? Colors.white : Colors.transparent,
Expand Down Expand Up @@ -367,12 +377,15 @@ class ScanProductBaseCardButton extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
text,
style: const TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold,
Padding(
padding: const EdgeInsetsDirectional.only(bottom: 3.0),
child: Text(
text,
style: const TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: MEDIUM_SPACE),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/cards/product_cards/smooth_product_base_card.dart';
import 'package:smooth_app/data_models/continuous_scan_model.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/pages/scan/carousel/scan_carousel.dart';
import 'package:smooth_app/resources/app_animations.dart';
import 'package:smooth_app/themes/smooth_theme.dart';
import 'package:smooth_app/themes/smooth_theme_colors.dart';

Expand All @@ -26,37 +27,41 @@ class ScanProductCardError extends StatelessWidget {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final SmoothColorsThemeExtension theme =
context.extension<SmoothColorsThemeExtension>();
final bool dense = context.read<ScanCardDensity>() == ScanCardDensity.DENSE;

return ScanProductBaseCard(
headerLabel: appLocalizations.carousel_error_header,
headerIndicatorColor: theme.error,
onRemove: onRemoveProduct,
backgroundChild: PositionedDirectional(
backgroundChild: const PositionedDirectional(
top: 0.0,
end: 5.0,
child: SvgPicture.asset('assets/product/scan_card_product_error.svg'),
child: OrangeErrorAnimation(),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ScanProductBaseCardTitle(
title: appLocalizations.carousel_error_title,
padding: const EdgeInsetsDirectional.only(top: 5.0, end: 25.0),
padding: EdgeInsetsDirectional.only(
top: dense ? 0.0 : 5.0,
end: 25.0,
),
),
const SizedBox(height: LARGE_SPACE),
ScanProductBaseCardText(
text: Text(appLocalizations.carousel_error_text_1),
),
ScanProductBaseCardBarcode(
barcode: barcode,
height: 75.0,
height: dense ? 60.0 : 75.0,
),
const Spacer(),
if (dense) const SizedBox(height: SMALL_SPACE) else const Spacer(),
ScanProductBaseCardText(
text: Text(appLocalizations.carousel_error_text_2),
),
const SizedBox(height: LARGE_SPACE),
if (dense) const Spacer() else const SizedBox(height: LARGE_SPACE),
ScanProductBaseCardButton(
text: appLocalizations.carousel_error_button,
onTap: () async {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/cards/product_cards/smooth_product_base_card.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/pages/navigator/app_navigator.dart';
import 'package:smooth_app/pages/scan/carousel/scan_carousel.dart';
import 'package:smooth_app/resources/app_animations.dart';
import 'package:smooth_app/themes/smooth_theme.dart';
import 'package:smooth_app/themes/smooth_theme_colors.dart';
import 'package:smooth_app/widgets/smooth_text.dart';
Expand All @@ -24,25 +26,29 @@ class ScanProductCardNotFound extends StatelessWidget {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final SmoothColorsThemeExtension theme =
context.extension<SmoothColorsThemeExtension>();
final bool dense = context.read<ScanCardDensity>() == ScanCardDensity.DENSE;

return ScanProductBaseCard(
headerLabel: appLocalizations.carousel_unknown_product_header,
headerIndicatorColor: theme.error,
onRemove: onRemoveProduct,
backgroundChild: PositionedDirectional(
backgroundChild: const PositionedDirectional(
top: 0.0,
end: 5.0,
child: SvgPicture.asset('assets/product/scan_card_product_error.svg'),
child: OrangeErrorAnimation(),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ScanProductBaseCardTitle(
title: appLocalizations.carousel_unknown_product_title,
padding: const EdgeInsetsDirectional.only(top: 5.0, end: 25.0),
padding: EdgeInsetsDirectional.only(
top: dense ? 0.0 : 5.0,
end: 25.0,
),
),
const SizedBox(height: LARGE_SPACE),
SizedBox(height: dense ? BALANCED_SPACE : LARGE_SPACE),
ScanProductBaseCardText(
text: TextWithBubbleParts(
text: appLocalizations.carousel_unknown_product_text,
Expand All @@ -53,7 +59,7 @@ class ScanProductCardNotFound extends StatelessWidget {
bubbleTextStyle: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 12.5,
fontSize: 13.5,
),
bubblePadding: const EdgeInsetsDirectional.only(
top: 2.5,
Expand Down
8 changes: 2 additions & 6 deletions packages/smooth_app/lib/pages/hunger_games/congrats.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:rive/rive.dart';
import 'package:smooth_app/data_models/user_management_provider.dart';
import 'package:smooth_app/generic_lib/buttons/smooth_simple_button.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/generic_lib/loading_dialog.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/pages/user_management/login_page.dart';
import 'package:smooth_app/resources/app_animations.dart';

typedef AnonymousAnnotationList = Map<String, InsightAnnotation>;

Expand Down Expand Up @@ -183,11 +183,7 @@ class _Header extends StatelessWidget {
child: SizedBox(
width: 230 * multiplier,
height: 235 * multiplier,
child: const RiveAnimation.asset(
'assets/animations/off.riv',
artboard: 'Success',
stateMachines: <String>['Animation'],
),
child: const SunAnimation(type: SunAnimationType.fullAnimation),
),
),
Padding(
Expand Down
26 changes: 20 additions & 6 deletions packages/smooth_app/lib/pages/navigator/app_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:smooth_app/helpers/extension_on_text_helper.dart';
import 'package:smooth_app/pages/guides/guide/guide_nutriscore_v2.dart';
import 'package:smooth_app/pages/navigator/error_page.dart';
import 'package:smooth_app/pages/navigator/external_page.dart';
import 'package:smooth_app/pages/navigator/slide_up_transition.dart';
import 'package:smooth_app/pages/onboarding/onboarding_flow_navigator.dart';
import 'package:smooth_app/pages/preferences/user_preferences_page.dart';
import 'package:smooth_app/pages/product/add_new_product/add_new_product_page.dart';
Expand Down Expand Up @@ -139,7 +140,7 @@ class _SmoothGoRouter {
routes: <GoRoute>[
GoRoute(
path: '${_InternalAppRoutes.PRODUCT_DETAILS_PAGE}/:productId',
builder: (BuildContext context, GoRouterState state) {
pageBuilder: (BuildContext context, GoRouterState state) {
Product product;

if (state.extra is Product) {
Expand All @@ -152,7 +153,7 @@ class _SmoothGoRouter {
throw Exception('No product provided!');
}

final Widget widget = ProductPage(
Widget widget = ProductPage(
product,
withHeroAnimation:
state.uri.queryParameters['heroAnimation'] != 'false',
Expand All @@ -163,10 +164,21 @@ class _SmoothGoRouter {
);

if (ExternalScanCarouselManager.find(context) == null) {
return ExternalScanCarouselManager(child: widget);
} else {
return widget;
widget = ExternalScanCarouselManager(child: widget);
}

return switch (ProductPageTransition.byName(
state.uri.queryParameters['transition'])) {
ProductPageTransition.standard => MaterialPage<void>(
key: state.pageKey,
child: widget,
),
ProductPageTransition.slideUp =>
OpenUpwardsPage.getTransition<void>(
key: state.pageKey,
child: widget,
),
};
},
),
GoRoute(
Expand Down Expand Up @@ -450,11 +462,13 @@ class AppRoutes {
bool useHeroAnimation = true,
String? heroTag = '',
ProductPageBackButton? backButtonType,
ProductPageTransition? transition = ProductPageTransition.standard,
}) =>
'/${_InternalAppRoutes.PRODUCT_DETAILS_PAGE}/$barcode'
'?heroAnimation=$useHeroAnimation'
'&heroTag=$heroTag'
'&backButtonType=${backButtonType?.name}';
'&backButtonType=${backButtonType?.name}'
'&transition=${transition?.name}';

// Product loader (= when a product is not in the database) - typical use case: deep links
static String PRODUCT_LOADER(String barcode, {bool edit = false}) =>
Expand Down
Loading

0 comments on commit c8d5392

Please sign in to comment.