Minor performance improvements during swipe b/w photos (#1361)

This commit is contained in:
Neeraj Gupta 2023-08-30 12:22:28 +05:30 committed by GitHub
commit d67efccf8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 53 deletions

View file

@ -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 <u-terms>termini di servizio</u-terms> e la <u-policy>politica sulla privacy</u-policy>"),
"singleFileDeleteFromDevice": m47,

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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<DetailPage> {
},
physics: _shouldDisableScroll
? const NeverScrollableScrollPhysics()
: const PageScrollPhysics(),
: const FastScrollPhysics(speedFactor: 4.0),
controller: _pageController,
itemCount: _files!.length,
);

View file

@ -279,10 +279,10 @@ class _FileDetailsWidgetState extends State<FileDetailsWidget> {
"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");
}

View file

@ -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;
@ -127,7 +130,6 @@ class _ZoomableImageState extends State<ZoomableImage>
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 +139,6 @@ class _ZoomableImageState extends State<ZoomableImage>
setState(() {
_imageProvider = imageProvider;
_loadedSmallThumbnail = true;
_captureThumbnailDimensions(_imageProvider!);
});
}
}).catchError((e) {
@ -235,7 +236,10 @@ class _ZoomableImageState extends State<ZoomableImage>
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,50 +250,62 @@ class _ZoomableImageState extends State<ZoomableImage>
}
}
Future<void> _captureThumbnailDimensions(ImageProvider imageProvider) async {
final imageInfo = await getImageInfo(imageProvider);
_thumbnailWidth = imageInfo.image.width;
}
Future<void> _updatePhotoViewController(ImageProvider imageProvider) async {
if (_thumbnailWidth == null || _photoViewController.scale == null) {
return;
Future<void> _updatePhotoViewController({
required ImageProvider? previewImageProvider,
required ImageProvider finalImageProvider,
}) async {
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 imageInfo = await getImageInfo(imageProvider);
final scale = _photoViewController.scale! /
(imageInfo.image.width / _thumbnailWidth!);
final currentPosition = _photoViewController.value.position;
final positionScaleFactor = 1 / scale;
final newPosition = currentPosition.scale(
positionScaleFactor,
positionScaleFactor,
);
_photoViewController = PhotoViewController(
initialPosition: newPosition,
initialScale: scale,
);
_updateAspectRatioIfNeeded(imageInfo).ignore();
}
// Fallback logic to finish back fill and update aspect
// ratio if needed.
Future<void> _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<void> _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,
});
}
}

View file

@ -47,15 +47,24 @@ class _FilePropertiesItemWidgetState extends State<FilePropertiesItemWidget> {
}
Future<List<Widget>> _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 = <Widget>[];
if (showDimension) {
if (dimString.isNotEmpty) {
subSectionWidgets.add(
Text(
"${widget.exifData["megaPixels"]}MP "
"${widget.exifData["resolution"]} ",
dimString.toString(),
style: getEnteTextTheme(context).miniMuted,
),
);