Skip to content

Commit

Permalink
feat: Improve photo gallery accessibility + internationalization (#5366)
Browse files Browse the repository at this point in the history
* Photo gallery: accessibility improvements + date format translatable

* Fix typos

* Use `DateFormat.ymd` instead

* Card based layout
  • Loading branch information
g123k authored Jun 18, 2024
1 parent 229ea66 commit 64d38f1
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 44 deletions.
18 changes: 18 additions & 0 deletions packages/smooth_app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,24 @@
"@product_refreshed": {
"description": "Confirmation, that the product data refresh is done"
},
"product_image_accessibility_label": "Image taken on {date}",
"@product_image_accessibility_label": {
"placeholders": {
"date": {
"type": "String",
"description": "The date of picture (in localized format for YYYY-MM-DD)"
}
}
},
"product_image_outdated_accessibility_label": "Image taken on {date}. This image may be outdated",
"@product_image_outdated_accessibility_label": {
"placeholders": {
"date": {
"type": "String",
"description": "The date of picture (in localized format for YYYY-MM-DD)"
}
}
},
"homepage_main_card_logo_description": "Welcome to Open Food Facts",
"@homepage_main_card_logo_description": {
"description": "Description for accessibility of the Open Food Facts logo on the homepage"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/fetched_product.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/helpers/product_cards_helper.dart';
import 'package:smooth_app/pages/image/product_image_other_page.dart';
import 'package:smooth_app/pages/image/product_image_widget.dart';
Expand Down Expand Up @@ -116,20 +117,27 @@ class _RawGridGallery extends StatelessWidget {
// order by descending ids
index = rawImages.length - 1 - index;
final ProductImage productImage = rawImages[index];
return InkWell(
onTap: () async => Navigator.push<void>(
context,
MaterialPageRoute<bool>(
builder: (BuildContext context) => ProductImageOtherPage(
product,
int.parse(productImage.imgid!),
return Padding(
padding: EdgeInsetsDirectional.only(
start: VERY_SMALL_SPACE,
end: index % _columns == 0 ? VERY_SMALL_SPACE : 0.0,
bottom: VERY_SMALL_SPACE,
),
child: InkWell(
onTap: () async => Navigator.push<void>(
context,
MaterialPageRoute<bool>(
builder: (BuildContext context) => ProductImageOtherPage(
product,
int.parse(productImage.imgid!),
),
),
),
),
child: ProductImageWidget(
productImage: productImage,
barcode: product.barcode!,
squareSize: squareSize,
child: ProductImageWidget(
productImage: productImage,
barcode: product.barcode!,
squareSize: squareSize,
),
),
);
},
Expand Down
131 changes: 99 additions & 32 deletions packages/smooth_app/lib/pages/image/product_image_widget.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/widgets/images/smooth_image.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/query/product_query.dart';
import 'package:smooth_app/resources/app_icons.dart';
import 'package:smooth_app/themes/smooth_theme_colors.dart';

/// Displays a product image thumbnail with the upload date on top.
class ProductImageWidget extends StatelessWidget {
class ProductImageWidget extends StatefulWidget {
const ProductImageWidget({
required this.productImage,
required this.barcode,
Expand All @@ -18,54 +22,117 @@ class ProductImageWidget extends StatelessWidget {
final String barcode;
final double squareSize;

static final DateFormat _dateFormat = DateFormat('yyyy-MM-dd');
@override
State<ProductImageWidget> createState() => _ProductImageWidgetState();
}

class _ProductImageWidgetState extends State<ProductImageWidget> {
@override
void initState() {
super.initState();
_loadImagePalette();
}

Future<void> _loadImagePalette() async {
final ColorScheme palette = await ColorScheme.fromImageProvider(
provider: NetworkImage(widget.productImage.getUrl(
widget.barcode,
uriHelper: ProductQuery.uriProductHelper,
)));

setState(() {
backgroundColor = palette.primaryContainer;
darkBackground = backgroundColor!.computeLuminance() < 0.5;
});
}

Color? backgroundColor;
bool? darkBackground;

@override
Widget build(BuildContext context) {
final SmoothColorsThemeExtension colors =
Theme.of(context).extension<SmoothColorsThemeExtension>()!;
final AppLocalizations appLocalizations = AppLocalizations.of(context);
final DateFormat dateFormat =
DateFormat.yMd(ProductQuery.getLanguage().offTag);

darkBackground = darkBackground ?? true;

final Widget image = SmoothImage(
width: squareSize,
height: squareSize,
width: widget.squareSize,
height: widget.squareSize,
imageProvider: NetworkImage(
productImage.getUrl(
barcode,
widget.productImage.getUrl(
widget.barcode,
uriHelper: ProductQuery.uriProductHelper,
),
),
rounded: false,
);
final DateTime? uploaded = productImage.uploaded;
final DateTime? uploaded = widget.productImage.uploaded;
if (uploaded == null) {
return image;
}
final DateTime now = DateTime.now();
final String date = _dateFormat.format(uploaded);
final bool expired = now.difference(uploaded).inDays > 365;
return Stack(
children: <Widget>[
image,
SizedBox(
width: squareSize,
height: squareSize,
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.all(SMALL_SPACE),
child: Container(
height: VERY_LARGE_SPACE,
color: expired
? Colors.red.withAlpha(128)
: Colors.white.withAlpha(128),
child: Center(
child: AutoSizeText(
date,
maxLines: 1,
final bool expired = DateTime.now().difference(uploaded).inDays > 365;
final String date = dateFormat.format(uploaded);

return Semantics(
label: expired
? appLocalizations.product_image_outdated_accessibility_label(date)
: appLocalizations.product_image_accessibility_label(date),
excludeSemantics: true,
button: true,
child: SmoothCard(
padding: EdgeInsets.zero,
color: backgroundColor ?? colors.primaryBlack,
borderRadius: ANGULAR_BORDER_RADIUS,
margin: EdgeInsets.zero,
child: ClipRRect(
borderRadius: ANGULAR_BORDER_RADIUS,
child: Column(
children: <Widget>[
Expanded(
child: image,
),
SizedBox(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: SMALL_SPACE,
vertical: VERY_SMALL_SPACE,
),
child: Stack(
children: <Widget>[
Center(
child: AutoSizeText(
date,
maxLines: 1,
style: TextStyle(
color: darkBackground!
? Colors.white
: colors.primaryDark,
),
),
),
if (expired)
Positioned.directional(
end: 0.0,
height: 20.0,
textDirection: Directionality.of(context),
child: Outdated(
size: 18.0,
color: colors.red,
),
),
],
),
),
),
),
)
],
),
),
],
),
);
}
}

0 comments on commit 64d38f1

Please sign in to comment.