Reenable hero using the thumbnail

This commit is contained in:
Ming Ming 2022-12-18 19:52:57 +08:00
parent 9ab9f11fb5
commit 1fc9de5af2
3 changed files with 130 additions and 24 deletions

View file

@ -19,3 +19,44 @@ class CustomizableMaterialPageRoute extends MaterialPageRoute {
}
String getImageHeroTag(FileDescriptor file) => "imageHero(${file.fdPath})";
// copied from flutter
Widget defaultHeroFlightShuttleBuilder(
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
final Hero toHero = toHeroContext.widget as Hero;
final MediaQueryData? toMediaQueryData = MediaQuery.maybeOf(toHeroContext);
final MediaQueryData? fromMediaQueryData =
MediaQuery.maybeOf(fromHeroContext);
if (toMediaQueryData == null || fromMediaQueryData == null) {
return toHero.child;
}
final EdgeInsets fromHeroPadding = fromMediaQueryData.padding;
final EdgeInsets toHeroPadding = toMediaQueryData.padding;
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
return MediaQuery(
data: toMediaQueryData.copyWith(
padding: (flightDirection == HeroFlightDirection.push)
? EdgeInsetsTween(
begin: fromHeroPadding,
end: toHeroPadding,
).evaluate(animation)
: EdgeInsetsTween(
begin: toHeroPadding,
end: fromHeroPadding,
).evaluate(animation),
),
child: toHero.child);
},
);
}

View file

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
@ -8,9 +9,11 @@ import 'package:nc_photos/api/api_util.dart' as api_util;
import 'package:nc_photos/cache_manager_util.dart';
import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/entity/local_file.dart';
import 'package:nc_photos/flutter_util.dart' as flutter_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/mobile/android/content_uri_image_provider.dart';
import 'package:nc_photos/widget/cached_network_image_mod.dart' as mod;
import 'package:nc_photos/widget/network_thumbnail.dart';
import 'package:np_codegen/np_codegen.dart';
part 'image_viewer.g.dart';
@ -113,30 +116,78 @@ class RemoteImageViewer extends StatefulWidget {
@npLog
class _RemoteImageViewerState extends State<RemoteImageViewer> {
@override
build(BuildContext context) => _ImageViewer(
canZoom: widget.canZoom,
onHeightChanged: widget.onHeightChanged,
onZoomStarted: widget.onZoomStarted,
onZoomEnded: widget.onZoomEnded,
child: mod.CachedNetworkImage(
cacheManager: LargeImageCacheManager.inst,
imageUrl: _getImageUrl(widget.account, widget.file),
httpHeaders: {
"Authorization": Api.getAuthorizationHeaderValue(widget.account),
},
fit: BoxFit.contain,
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
imageBuilder: (context, child, imageProvider) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_onItemLoaded();
});
const SizeChangedLayoutNotification().dispatch(context);
return child;
},
),
);
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
// needed to get rid of the large image blinking during Hero animation
setState(() {});
}
});
}
@override
Widget build(BuildContext context) {
return _ImageViewer(
canZoom: widget.canZoom,
onHeightChanged: widget.onHeightChanged,
onZoomStarted: widget.onZoomStarted,
onZoomEnded: widget.onZoomEnded,
child: Stack(
fit: StackFit.passthrough,
children: [
Hero(
tag: flutter_util.getImageHeroTag(widget.file),
flightShuttleBuilder: (flightContext, animation, flightDirection,
fromHeroContext, toHeroContext) {
_isHeroDone = false;
animation.addStatusListener(_animationListener);
return flutter_util.defaultHeroFlightShuttleBuilder(
flightContext,
animation,
flightDirection,
fromHeroContext,
toHeroContext,
);
},
child: CachedNetworkImage(
fit: BoxFit.contain,
cacheManager: ThumbnailCacheManager.inst,
imageUrl: NetworkRectThumbnail.imageUrlForFile(
widget.account, widget.file),
httpHeaders: {
"Authorization":
Api.getAuthorizationHeaderValue(widget.account),
},
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
),
),
if (_isHeroDone)
mod.CachedNetworkImage(
cacheManager: LargeImageCacheManager.inst,
imageUrl: _getImageUrl(widget.account, widget.file),
httpHeaders: {
"Authorization":
Api.getAuthorizationHeaderValue(widget.account),
},
fit: BoxFit.contain,
fadeInDuration: const Duration(),
filterQuality: FilterQuality.high,
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
imageBuilder: (context, child, imageProvider) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_onItemLoaded();
});
const SizeChangedLayoutNotification().dispatch(context);
return child;
},
),
],
),
);
}
void _onItemLoaded() {
if (!_isLoaded) {
@ -146,7 +197,19 @@ class _RemoteImageViewerState extends State<RemoteImageViewer> {
}
}
void _animationListener(AnimationStatus status) {
if (status == AnimationStatus.completed) {
_isHeroDone = true;
if (mounted) {
setState(() {});
}
}
}
var _isLoaded = false;
// initially set to true such that the large image will show when hero didn't
// run (i.e., when swiping in viewer)
var _isHeroDone = true;
}
class _ImageViewer extends StatefulWidget {

View file

@ -6,6 +6,7 @@ import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:nc_photos/entity/local_file.dart';
import 'package:nc_photos/flutter_util.dart' as flutter_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/mobile/android/content_uri_image_provider.dart';
import 'package:nc_photos/theme.dart';
@ -63,6 +64,7 @@ class PhotoListImageItem extends PhotoListFileItem {
previewUrl: previewUrl,
isGif: file.fdMime == "image/gif",
isFavorite: shouldShowFavoriteBadge && file.fdIsFavorite == true,
heroKey: flutter_util.getImageHeroTag(file),
);
final Account account;