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

feat: 3129 Allow to swipe between product images on the full screen image view #3325

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
512284c
Swipeable view for product images
omkarChend1kar Nov 15, 2022
2772e17
Swipeable view for product images
omkarChend1kar Nov 15, 2022
1288068
Merge branch 'swipeable_product_image_view' of https://github.com/omk…
omkarChend1kar Nov 15, 2022
f4e14cf
Merge branch 'develop' of https://github.com/omkarChend1kar/smooth-ap…
omkarChend1kar Nov 15, 2022
3460fe4
Resolve for formatting issue in file smooth_images_view.dart
omkarChend1kar Nov 16, 2022
5df856b
Resolve for formatting issue in file smooth_images_view.dart
omkarChend1kar Nov 16, 2022
8a3a2f1
Merge branch 'swipeable_product_image_view' of https://github.com/omk…
omkarChend1kar Nov 16, 2022
9866c91
Merge branch 'develop' into swipeable_product_image_view
monsieurtanuki Nov 17, 2022
b589c3c
Merge branch 'develop' of https://github.com/omkarChend1kar/smooth-ap…
omkarChend1kar Nov 18, 2022
2d5136e
1. Refactoring on previous code
omkarChend1kar Nov 18, 2022
693d477
Merge branch 'swipeable_product_image_view' of https://github.com/omk…
omkarChend1kar Nov 18, 2022
5ff8425
Resolved formatting and annotations issue
omkarChend1kar Nov 18, 2022
20fffcb
Code refactoring
omkarChend1kar Nov 21, 2022
739b51d
Merge branch 'develop' into swipeable_product_image_view
omkarChend1kar Nov 26, 2022
9e1ec8b
Formatting changes
omkarChend1kar Nov 26, 2022
bcb3135
Merge branch 'swipeable_product_image_view' of https://github.com/omk…
omkarChend1kar Nov 26, 2022
7b1fbaa
Formatting changes
omkarChend1kar Nov 26, 2022
3bdad42
Merge branch 'swipeable_product_image_view' of https://github.com/omk…
omkarChend1kar Nov 26, 2022
bde4737
feat: 3129 Allow to swipe between product images on the full screen i…
omkarChend1kar Nov 26, 2022
2aa8f9e
feat: 3129 Allow to swipe between product images on the full screen i…
omkarChend1kar Nov 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -36,28 +36,33 @@ class SmoothImagesSliverGrid extends SmoothImagesView {
padding: const EdgeInsets.all(MEDIUM_SPACE),
sliver: SliverGrid(
delegate: LoadingSliverChildBuilderDelegate(
loading: loading,
childCount: imageList.length,
loadingWidget: _buildShimmer(),
loadingCount: loadingCount,
childBuilder: (BuildContext context, int index) {
final MapEntry<ProductImageData, ImageProvider<Object>?> entry =
imageList[index];
final ImageProvider? imageProvider = entry.value;
final String? imageUrl = entry.key.imageUrl;
loading: loading,
childCount: imageList.length,
loadingWidget: _buildShimmer(),
loadingCount: loadingCount,
childBuilder: (BuildContext context, int index) {
final MapEntry<ProductImageData, ImageProvider<Object>?> entry =
imageList[index];
final ImageProvider? imageProvider = entry.value;
final String? imageUrl = entry.key.imageUrl;

return imageProvider == null || imageUrl == null
? const PictureNotFound()
: Hero(
tag: imageUrl,
child: _ImageTile(
image: imageProvider,
onTap: onTap == null
? null
: () => onTap!(entry.key, entry.value),
),
);
}),
return imageProvider == null || imageUrl == null
? const PictureNotFound()
: Hero(
tag: imageUrl,
child: _ImageTile(
image: imageProvider,
onTap: onTap == null
? null
: () => onTap!(
entry.key,
entry.value,
null,
),
),
);
},
),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxTileWidth,
childAspectRatio: childAspectRatio,
Expand Down
Expand Up @@ -36,7 +36,11 @@ class SmoothImagesSliverList extends SmoothImagesView {
),
onTap: onTap == null
? null
: () => onTap!(imageList[index].key, imageList[index].value),
: () => onTap!(
imageList[index].key,
imageList[index].value,
index,
),
),
),
);
Expand Down
Expand Up @@ -10,6 +10,6 @@ abstract class SmoothImagesView extends StatelessWidget {
});

final Map<ProductImageData, ImageProvider?> imagesData;
final void Function(ProductImageData, ImageProvider?)? onTap;
final void Function(ProductImageData, ImageProvider?, int?)? onTap;
final bool loading;
}
@@ -1,17 +1,19 @@
import 'dart:io';
Copy link
Contributor

Choose a reason for hiding this comment

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

No


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:smooth_app/data_models/product_image_data.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/database/transient_file.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/widgets/images/smooth_images_sliver_list.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_back_button.dart';
import 'package:smooth_app/helpers/product_cards_helper.dart';
import 'package:smooth_app/pages/image_crop_page.dart';
import 'package:smooth_app/pages/product/common/product_refresher.dart';
import 'package:smooth_app/pages/product/product_image_viewer.dart';
import 'package:smooth_app/pages/product/confirm_and_upload_picture.dart';
import 'package:smooth_app/pages/product/product_image_swipeable_view.dart';
import 'package:smooth_app/widgets/smooth_app_bar.dart';
import 'package:smooth_app/widgets/smooth_scaffold.dart';

Expand All @@ -32,14 +34,11 @@ class _ProductImageGalleryViewState extends State<ProductImageGalleryView> {
late final LocalDatabase _localDatabase;
late final Product _initialProduct;
late Product _product;

late Map<ProductImageData, ImageProvider?> _selectedImages;

bool _isRefreshed = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

No

ImageProvider? _provideImage(ProductImageData imageData) =>
TransientFile.getImageProvider(imageData, _barcode);

imageData.imageUrl == null ? null : NetworkImage(imageData.imageUrl!);
Copy link
Contributor

Choose a reason for hiding this comment

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

No

String get _barcode => _initialProduct.barcode!;

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -80,7 +79,7 @@ class _ProductImageGalleryViewState extends State<ProductImageGalleryView> {
)
: null,
leading: SmoothBackButton(
onPressed: () => Navigator.maybePop(context),
onPressed: () => Navigator.maybePop(context, _isRefreshed),
Copy link
Contributor

Choose a reason for hiding this comment

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

No

),
),
body: RefreshIndicator(
Expand All @@ -97,9 +96,16 @@ class _ProductImageGalleryViewState extends State<ProductImageGalleryView> {
),
SmoothImagesSliverList(
imagesData: _selectedImages,
onTap: (ProductImageData data, _) =>
TransientFile.isImageAvailable(data, _barcode)
? _openImage(data)
onTap: (
ProductImageData data,
_,
int? currentProductImageDataIndex,
) =>
data.imageUrl != null
? _openImage(
selectedImages: _selectedImages,
index: currentProductImageDataIndex ?? 0,
)
: _newImage(data),
),
],
Expand All @@ -119,22 +125,54 @@ class _ProductImageGalleryViewState extends State<ProductImageGalleryView> {
),
),
);

Future<void> _openImage(ProductImageData imageData) async =>
Navigator.push<void>(
Future<void> _openImage({
required int index,
required Map<ProductImageData, ImageProvider?> selectedImages,
}) async =>
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (_) => ProductImageViewer(
product: _product,
imageField: imageData.imageField,
),
builder: (_) {
return ProductImageSwipeableView(
barcode: _barcode,
initialProductImageDataIndex: index,
selectedImages: _selectedImages,
);
},
),
);
Future<void> _newImage(ProductImageData data) async {
Copy link
Contributor

Choose a reason for hiding this comment

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

No

final File? croppedImageFile = await startNewImageCropping(this);
if (croppedImageFile == null) {
return;
}
if (!mounted) {
return;
}
setState(() {
final FileImage fileImage = FileImage(croppedImageFile);
final ImageField imageField = data.imageField;
for (final ProductImageData productImageData in _selectedImages.keys) {
if (productImageData.imageField == imageField) {
_selectedImages[productImageData] = fileImage;
return;
}
}
});
final File? uploaded = await Navigator.push<File>(
context,
MaterialPageRoute<File>(
builder: (BuildContext context) => ConfirmAndUploadPicture(
barcode: _barcode,
imageField: data.imageField,
initialPhoto: croppedImageFile,
),
),
);
final bool isUploaded = uploaded != null;

Future<void> _newImage(ProductImageData data) async =>
confirmAndUploadNewPicture(
this,
barcode: _barcode,
imageField: data.imageField,
);
if (isUploaded) {
_isRefreshed = true;
}
}
}
@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:smooth_app/data_models/product_image_data.dart';
import 'package:smooth_app/generic_lib/design_constants.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_back_button.dart';
import 'package:smooth_app/pages/product/product_image_viewer.dart';

///Widget to display swipeable product images,
///Opens product image with [initialProductImageDataIndex] from list of images Typecasted from [selectedImages]
class ProductImageSwipeableView extends StatefulWidget {
const ProductImageSwipeableView({
super.key,
required this.selectedImages,
required this.initialProductImageDataIndex,
required this.barcode,
});

final Map<ProductImageData, ImageProvider?> selectedImages;
final int initialProductImageDataIndex;
final String barcode;

@override
State<ProductImageSwipeableView> createState() =>
_ProductImageSwipeableViewState();
}

class _ProductImageSwipeableViewState extends State<ProductImageSwipeableView> {
final ValueNotifier<int> _currentImageDataIndex = ValueNotifier<int>(0);
late List<ProductImageData> _imageDataList;
late PageController _controller;

@override
void initState() {
super.initState();
_currentImageDataIndex.value = widget.initialProductImageDataIndex;
_imageDataList = List<ProductImageData>.from(widget.selectedImages.keys);
_controller = PageController(
initialPage: widget.initialProductImageDataIndex,
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's say currentImageDataIndex.value now that you populated it.

);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
foregroundColor: WHITE_COLOR,
elevation: 0,
title: ValueListenableBuilder<int>(
valueListenable: _currentImageDataIndex,
builder: (_, int index, __) {
return Text(
_imageDataList[index].title,
);
},
),
leading: SmoothBackButton(
iconColor: Colors.white,
onPressed: () => Navigator.maybePop(context),
),
),
body: PageView.builder(
onPageChanged: (int index) {
_currentImageDataIndex.value = index;
},
controller: _controller,
itemCount: widget.selectedImages.keys.length,
itemBuilder: (BuildContext context, int index) {
return ProductImageViewer(
monsieurtanuki marked this conversation as resolved.
Show resolved Hide resolved
barcode: widget.barcode,
imageData: _imageDataList[index],
);
},
),
);
}
}