From d271cf05de34808a7570611d6960356f117a227f Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 30 Aug 2023 08:53:01 +0530 Subject: [PATCH 1/4] Fix: Show dimensions from file metadata --- lib/models/file/file.dart | 3 +++ lib/ui/viewer/file/file_details_widget.dart | 8 ++++---- .../file_properties_item_widget.dart | 19 ++++++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/models/file/file.dart b/lib/models/file/file.dart index 7de51adb6..a0481cd39 100644 --- a/lib/models/file/file.dart +++ b/lib/models/file/file.dart @@ -271,6 +271,9 @@ class EnteFile { int get width { return pubMagicMetadata?.w ?? 0; } + bool get hasDimensions { + return height != 0 && width != 0; + } // returns true if the file isn't available in the user's gallery bool get isRemoteFile { diff --git a/lib/ui/viewer/file/file_details_widget.dart b/lib/ui/viewer/file/file_details_widget.dart index 8ae4818ae..4ed1fe844 100644 --- a/lib/ui/viewer/file/file_details_widget.dart +++ b/lib/ui/viewer/file/file_details_widget.dart @@ -279,10 +279,10 @@ class _FileDetailsWidgetState extends State { "ImageLength"]; if (imageWidth != null && imageLength != null) { _exifData["resolution"] = '$imageWidth x $imageLength'; - _exifData['megaPixels'] = - ((imageWidth.values.firstAsInt() * imageLength.values.firstAsInt()) / - 1000000) - .toStringAsFixed(1); + final double megaPixels = + (imageWidth.values.firstAsInt() * imageLength.values.firstAsInt()) / 1000000; + final double roundedMegaPixels = (megaPixels * 10).round() / 10.0; + _exifData['megaPixels'] = roundedMegaPixels..toStringAsFixed(1); } else { debugPrint("No image width/height"); } diff --git a/lib/ui/viewer/file_details/file_properties_item_widget.dart b/lib/ui/viewer/file_details/file_properties_item_widget.dart index 1411d7588..d0f2916d2 100644 --- a/lib/ui/viewer/file_details/file_properties_item_widget.dart +++ b/lib/ui/viewer/file_details/file_properties_item_widget.dart @@ -47,15 +47,24 @@ class _FilePropertiesItemWidgetState extends State { } Future> _subTitleSection() async { - final bool showDimension = widget.exifData["resolution"] != null && - widget.exifData["megaPixels"] != null; + final StringBuffer dimString = StringBuffer(); + if (widget.exifData["resolution"] != null && + widget.exifData["megaPixels"] != null) { + dimString.write('${widget.exifData["megaPixels"]}MP '); + dimString.write('${widget.exifData["resolution"]}'); + } else if (widget.file.hasDimensions) { + final double megaPixels = + (widget.file.width * widget.file.height) / 1000000; + final double roundedMegaPixels = (megaPixels * 10).round() / 10.0; + dimString.write('${roundedMegaPixels.toStringAsFixed(1)}MP '); + dimString.write('${widget.file.width} x ${widget.file.height}'); + } final subSectionWidgets = []; - if (showDimension) { + if (dimString.isNotEmpty) { subSectionWidgets.add( Text( - "${widget.exifData["megaPixels"]}MP " - "${widget.exifData["resolution"]} ", + dimString.toString(), style: getEnteTextTheme(context).miniMuted, ), ); From 5c9c3531ab722d978340a8f20ee91751584e8a60 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 30 Aug 2023 09:49:53 +0530 Subject: [PATCH 2/4] Fix: Increase page scroll speed Signed-off-by: Neeraj Gupta <254676+ua741@users.noreply.github.com> --- lib/generated/intl/messages_it.dart | 13 +++++++++++-- lib/ui/common/fast_scroll_physics.dart | 24 ++++++++++++++++++++++++ lib/ui/viewer/file/detail_page.dart | 3 ++- 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 lib/ui/common/fast_scroll_physics.dart diff --git a/lib/generated/intl/messages_it.dart b/lib/generated/intl/messages_it.dart index 4cad869c4..8f94a0688 100644 --- a/lib/generated/intl/messages_it.dart +++ b/lib/generated/intl/messages_it.dart @@ -230,7 +230,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Aggiungi all\'album"), "addToEnte": MessageLookupByLibrary.simpleMessage("Aggiungi su ente"), "addToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Add to hidden album"), + MessageLookupByLibrary.simpleMessage("Aggiungi ad album nascosto"), "addViewer": MessageLookupByLibrary.simpleMessage("Aggiungi in sola lettura"), "addedAs": MessageLookupByLibrary.simpleMessage("Aggiunto come"), @@ -707,6 +707,8 @@ class MessageLookup extends MessageLookupByLibrary { "goToSettings": MessageLookupByLibrary.simpleMessage("Vai alle impostazioni"), "googlePlayId": MessageLookupByLibrary.simpleMessage("Google Play ID"), + "grantFullAccessPrompt": MessageLookupByLibrary.simpleMessage( + "Consenti l\'accesso a tutte le foto nelle Impostazioni"), "grantPermission": MessageLookupByLibrary.simpleMessage("Concedi il permesso"), "groupNearbyPhotos": MessageLookupByLibrary.simpleMessage( @@ -861,7 +863,7 @@ class MessageLookup extends MessageLookupByLibrary { "moveToAlbum": MessageLookupByLibrary.simpleMessage("Sposta nell\'album"), "moveToHiddenAlbum": - MessageLookupByLibrary.simpleMessage("Move to hidden album"), + MessageLookupByLibrary.simpleMessage("Sposta in album nascosto"), "movedSuccessfullyTo": m30, "movedToTrash": MessageLookupByLibrary.simpleMessage("Spostato nel cestino"), @@ -910,6 +912,8 @@ class MessageLookup extends MessageLookupByLibrary { "Ops, impossibile salvare le modifiche"), "oopsSomethingWentWrong": MessageLookupByLibrary.simpleMessage( "Oops! Qualcosa è andato storto"), + "openSettings": + MessageLookupByLibrary.simpleMessage("Apri Impostazioni"), "openTheItem": MessageLookupByLibrary.simpleMessage("• Apri la foto o il video"), "openstreetmapContributors": MessageLookupByLibrary.simpleMessage( @@ -980,6 +984,8 @@ class MessageLookup extends MessageLookupByLibrary { "preserveMore": MessageLookupByLibrary.simpleMessage("Salva più foto"), "pressAndHoldToPlayVideo": MessageLookupByLibrary.simpleMessage( "Tieni premuto per riprodurre il video"), + "pressAndHoldToPlayVideoDetailed": MessageLookupByLibrary.simpleMessage( + "Tieni premuto sull\'immagine per riprodurre il video"), "privacy": MessageLookupByLibrary.simpleMessage("Privacy"), "privacyPolicyTitle": MessageLookupByLibrary.simpleMessage("Privacy Policy"), @@ -1116,6 +1122,8 @@ class MessageLookup extends MessageLookupByLibrary { "Seleziona gli elementi da aggiungere"), "selectLanguage": MessageLookupByLibrary.simpleMessage("Seleziona una lingua"), + "selectMorePhotos": + MessageLookupByLibrary.simpleMessage("Seleziona più foto"), "selectReason": MessageLookupByLibrary.simpleMessage("Seleziona un motivo"), "selectYourPlan": @@ -1180,6 +1188,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Condivise con te"), "sharing": MessageLookupByLibrary.simpleMessage("Condivisione in corso..."), + "showMemories": MessageLookupByLibrary.simpleMessage("Mostra ricordi"), "signUpTerms": MessageLookupByLibrary.simpleMessage( "Accetto i termini di servizio e la politica sulla privacy"), "singleFileDeleteFromDevice": m47, diff --git a/lib/ui/common/fast_scroll_physics.dart b/lib/ui/common/fast_scroll_physics.dart new file mode 100644 index 000000000..97771af24 --- /dev/null +++ b/lib/ui/common/fast_scroll_physics.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class FastScrollPhysics extends PageScrollPhysics { + final double speedFactor; + + const FastScrollPhysics({this.speedFactor = 2.0, ScrollPhysics? parent}) + : super(parent: parent); + + @override + FastScrollPhysics applyTo(ScrollPhysics? ancestor) { + return FastScrollPhysics( + speedFactor: speedFactor, + parent: buildParent(ancestor), + ); + } + + @override + Simulation? createBallisticSimulation( + ScrollMetrics position, + double velocity, + ) { + return super.createBallisticSimulation(position, velocity * speedFactor); + } +} diff --git a/lib/ui/viewer/file/detail_page.dart b/lib/ui/viewer/file/detail_page.dart index 34ae1b1ab..9356bee4b 100644 --- a/lib/ui/viewer/file/detail_page.dart +++ b/lib/ui/viewer/file/detail_page.dart @@ -7,6 +7,7 @@ import 'package:photos/core/constants.dart'; import 'package:photos/core/errors.dart'; import "package:photos/generated/l10n.dart"; import 'package:photos/models/file/file.dart'; +import "package:photos/ui/common/fast_scroll_physics.dart"; import 'package:photos/ui/tools/editor/image_editor_page.dart'; import "package:photos/ui/viewer/file/file_app_bar.dart"; import "package:photos/ui/viewer/file/file_bottom_bar.dart"; @@ -200,7 +201,7 @@ class _DetailPageState extends State { }, physics: _shouldDisableScroll ? const NeverScrollableScrollPhysics() - : const PageScrollPhysics(), + : const FastScrollPhysics(speedFactor: 4.0), controller: _pageController, itemCount: _files!.length, ); From 6ee182ececa8525fb86388cd92d7e396b5d1901a Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:32:55 +0530 Subject: [PATCH 3/4] Perf: Avoid redundant computation of imageInfo --- lib/ui/viewer/file/zoomable_image.dart | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ui/viewer/file/zoomable_image.dart b/lib/ui/viewer/file/zoomable_image.dart index a17e54b4b..9463df711 100644 --- a/lib/ui/viewer/file/zoomable_image.dart +++ b/lib/ui/viewer/file/zoomable_image.dart @@ -127,7 +127,6 @@ class _ZoomableImageState extends State if (cachedThumbnail != null) { _imageProvider = Image.memory(cachedThumbnail).image; _loadedSmallThumbnail = true; - _captureThumbnailDimensions(_imageProvider!); } else { getThumbnailFromServer(_photo).then((file) { final imageProvider = Image.memory(file).image; @@ -137,7 +136,6 @@ class _ZoomableImageState extends State setState(() { _imageProvider = imageProvider; _loadedSmallThumbnail = true; - _captureThumbnailDimensions(_imageProvider!); }); } }).catchError((e) { @@ -235,7 +233,10 @@ class _ZoomableImageState extends State if (mounted) { precacheImage(imageProvider, context).then((value) async { if (mounted) { - await _updatePhotoViewController(imageProvider); + await _updatePhotoViewController( + previewImageProvider: _imageProvider, + finalImageProvider: imageProvider, + ); setState(() { _imageProvider = imageProvider; _loadedFinalImage = true; @@ -246,18 +247,17 @@ class _ZoomableImageState extends State } } - Future _captureThumbnailDimensions(ImageProvider imageProvider) async { - final imageInfo = await getImageInfo(imageProvider); - _thumbnailWidth = imageInfo.image.width; - } - - Future _updatePhotoViewController(ImageProvider imageProvider) async { - if (_thumbnailWidth == null || _photoViewController.scale == null) { + Future _updatePhotoViewController({ + required ImageProvider? previewImageProvider, + required ImageProvider finalImageProvider, + }) async { + if (_photoViewController.scale == null || previewImageProvider == null) { return; } - final imageInfo = await getImageInfo(imageProvider); + final prevImageInfo = await getImageInfo(previewImageProvider); + final finalImageInfo = await getImageInfo(finalImageProvider); final scale = _photoViewController.scale! / - (imageInfo.image.width / _thumbnailWidth!); + (finalImageInfo.image.width / prevImageInfo.image.width); final currentPosition = _photoViewController.value.position; final positionScaleFactor = 1 / scale; final newPosition = currentPosition.scale( @@ -268,7 +268,7 @@ class _ZoomableImageState extends State initialPosition: newPosition, initialScale: scale, ); - _updateAspectRatioIfNeeded(imageInfo).ignore(); + _updateAspectRatioIfNeeded(finalImageInfo).ignore(); } // Fallback logic to finish back fill and update aspect From d1f3e2d3131cdceaaff63d9066b598d98c6ad818 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:35:11 +0530 Subject: [PATCH 4/4] Fix: Avoid redundant fetch for imageInfo --- lib/ui/viewer/file/zoomable_image.dart | 82 +++++++++++++++----------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/lib/ui/viewer/file/zoomable_image.dart b/lib/ui/viewer/file/zoomable_image.dart index 9463df711..191053cce 100644 --- a/lib/ui/viewer/file/zoomable_image.dart +++ b/lib/ui/viewer/file/zoomable_image.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import "package:flutter/foundation.dart"; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:logging/logging.dart'; @@ -12,6 +13,7 @@ import 'package:photos/core/event_bus.dart'; import 'package:photos/db/files_db.dart'; import 'package:photos/events/files_updated_event.dart'; import 'package:photos/events/local_photos_updated_event.dart'; +import "package:photos/models/file/extensions/file_props.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/models/metadata/file_magic.dart"; import "package:photos/services/file_magic_service.dart"; @@ -19,6 +21,7 @@ import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/utils/file_util.dart'; import 'package:photos/utils/image_util.dart'; import 'package:photos/utils/thumbnail_util.dart'; +import "package:photos/utils/toast_util.dart"; class ZoomableImage extends StatefulWidget { final EnteFile photo; @@ -251,45 +254,58 @@ class _ZoomableImageState extends State required ImageProvider? previewImageProvider, required ImageProvider finalImageProvider, }) async { - if (_photoViewController.scale == null || previewImageProvider == null) { - return; + final bool shouldFixPosition = previewImageProvider != null && + _isZooming && + _photoViewController.scale != null; + ImageInfo? finalImageInfo; + if(shouldFixPosition) { + if (kDebugMode) { + showToast(context, + 'Updating photo scale zooming: $_isZooming and scale: ${_photoViewController.scale}'); + } + final prevImageInfo = await getImageInfo(previewImageProvider); + finalImageInfo = await getImageInfo(finalImageProvider); + final scale = _photoViewController.scale! / + (finalImageInfo.image.width / prevImageInfo.image.width); + final currentPosition = _photoViewController.value.position; + final positionScaleFactor = 1 / scale; + final newPosition = currentPosition.scale( + positionScaleFactor, + positionScaleFactor, + ); + _photoViewController = PhotoViewController( + initialPosition: newPosition, + initialScale: scale, + ); + } + final bool canUpdateMetadata = _photo.canEditMetaInfo; + // forcefully get finalImageInfo is dimensions are not available in metadata + if (finalImageInfo == null && canUpdateMetadata && !_photo.hasDimensions) { + finalImageInfo = await getImageInfo(finalImageProvider); + } + if (finalImageInfo != null && canUpdateMetadata) { + _updateAspectRatioIfNeeded(_photo, finalImageInfo).ignore(); } - final prevImageInfo = await getImageInfo(previewImageProvider); - final finalImageInfo = await getImageInfo(finalImageProvider); - final scale = _photoViewController.scale! / - (finalImageInfo.image.width / prevImageInfo.image.width); - final currentPosition = _photoViewController.value.position; - final positionScaleFactor = 1 / scale; - final newPosition = currentPosition.scale( - positionScaleFactor, - positionScaleFactor, - ); - _photoViewController = PhotoViewController( - initialPosition: newPosition, - initialScale: scale, - ); - _updateAspectRatioIfNeeded(finalImageInfo).ignore(); } // Fallback logic to finish back fill and update aspect // ratio if needed. - Future _updateAspectRatioIfNeeded(ImageInfo imageInfo) async { - if (_imageProvider != null && - widget.photo.isUploaded && - widget.photo.ownerID == _currentUserID) { - final int h = imageInfo.image.height, w = imageInfo.image.width; - if (h != 0 && - w != 0 && - (h != widget.photo.height || w != widget.photo.width)) { - _logger.info('Updating aspect ratio for ${widget.photo} to $h:$w'); - - await FileMagicService.instance.updatePublicMagicMetadata([ - widget.photo, - ], { - heightKey: h, - widthKey: w, - }); + Future _updateAspectRatioIfNeeded( + EnteFile enteFile, + ImageInfo imageInfo, + ) async { + final int h = imageInfo.image.height, w = imageInfo.image.width; + if (h != enteFile.height || w != enteFile.width) { + if (kDebugMode) { + showToast(context, 'Updating aspect ratio'); } + _logger.info('Updating aspect ratio for $enteFile to $h:$w'); + await FileMagicService.instance.updatePublicMagicMetadata([ + enteFile, + ], { + heightKey: h, + widthKey: w, + }); } }