diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index 3f0d9a965..c6fc73aee 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -12,6 +12,7 @@ import 'package:aves/widgets/collection/collection_page.dart'; import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/viewer/entry_action_delegate.dart'; import 'package:aves/widgets/viewer/entry_vertical_pager.dart'; +import 'package:aves/widgets/viewer/hero.dart'; import 'package:aves/widgets/viewer/info/notifications.dart'; import 'package:aves/widgets/viewer/multipage.dart'; import 'package:aves/widgets/viewer/overlay/bottom.dart'; @@ -57,7 +58,7 @@ class _EntryViewerStackState extends State with SingleTickerPr final List> _videoControllers = []; final List> _multiPageControllers = []; final List>> _viewStateNotifiers = []; - final ValueNotifier _visualLeaveInfoNotifier = ValueNotifier(null); + final ValueNotifier _heroInfoNotifier = ValueNotifier(null); CollectionLens get collection => widget.collection; @@ -75,6 +76,8 @@ class _EntryViewerStackState extends State with SingleTickerPr void initState() { super.initState(); final entry = widget.initialEntry; + // opening hero, with viewer as target + _heroInfoNotifier.value = HeroInfo(entry); _entryNotifier.value = entry; _currentHorizontalPage = max(0, entries.indexOf(entry)); _currentVerticalPage = ValueNotifier(imagePage); @@ -167,8 +170,8 @@ class _EntryViewerStackState extends State with SingleTickerPr } return SynchronousFuture(false); }, - child: ValueListenableProvider.value( - value: _visualLeaveInfoNotifier, + child: ValueListenableProvider.value( + value: _heroInfoNotifier, builder: (context, snapshot) { return NotificationListener( onNotification: (notification) { @@ -365,6 +368,9 @@ class _EntryViewerStackState extends State with SingleTickerPr if (page == transitionPage) { await _actionDelegate.dismissFeedback(); _popVisual(); + } else if (page == infoPage) { + // prevent hero when viewer is offscreen + _heroInfoNotifier.value = null; } } @@ -409,12 +415,21 @@ class _EntryViewerStackState extends State with SingleTickerPr void _popVisual() { if (Navigator.canPop(context)) { - _visualLeaveInfoNotifier.value = VisualLeaveInfo(_entryNotifier.value); - // we post closing the viewer page so that hero animation source is ready - WidgetsBinding.instance.addPostFrameCallback((_) { + void pop() { _onLeave(); Navigator.pop(context); - }); + } + + // closing hero, with viewer as source + final heroInfo = HeroInfo(_entryNotifier.value); + if (_heroInfoNotifier.value != heroInfo) { + _heroInfoNotifier.value = heroInfo; + // we post closing the viewer page so that hero animation source is ready + WidgetsBinding.instance.addPostFrameCallback((_) => pop()); + } else { + // viewer already has correct hero info, no need to rebuild + pop(); + } } else { // exit app when trying to pop a viewer page for a single entry SystemNavigator.pop(); @@ -518,18 +533,3 @@ class _EntryViewerStackState extends State with SingleTickerPr void _pauseVideoControllers() => _videoControllers.forEach((e) => e.item2.pause()); } - -class VisualLeaveInfo { - final AvesEntry entry; - - const VisualLeaveInfo(this.entry); - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) return false; - return other is VisualLeaveInfo && other.entry == entry; - } - - @override - int get hashCode => entry.hashCode; -} diff --git a/lib/widgets/viewer/hero.dart b/lib/widgets/viewer/hero.dart new file mode 100644 index 000000000..c7db1594c --- /dev/null +++ b/lib/widgets/viewer/hero.dart @@ -0,0 +1,16 @@ +import 'package:aves/model/entry.dart'; + +class HeroInfo { + final AvesEntry entry; + + const HeroInfo(this.entry); + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) return false; + return other is HeroInfo && other.entry == entry; + } + + @override + int get hashCode => entry.hashCode; +} diff --git a/lib/widgets/viewer/visual/entry_page_view.dart b/lib/widgets/viewer/visual/entry_page_view.dart index ce9e98b25..d822de4ce 100644 --- a/lib/widgets/viewer/visual/entry_page_view.dart +++ b/lib/widgets/viewer/visual/entry_page_view.dart @@ -11,7 +11,7 @@ import 'package:aves/widgets/common/magnifier/magnifier.dart'; import 'package:aves/widgets/common/magnifier/scale/scale_boundaries.dart'; import 'package:aves/widgets/common/magnifier/scale/scale_level.dart'; import 'package:aves/widgets/common/magnifier/scale/state.dart'; -import 'package:aves/widgets/viewer/entry_viewer_stack.dart'; +import 'package:aves/widgets/viewer/hero.dart'; import 'package:aves/widgets/viewer/visual/error.dart'; import 'package:aves/widgets/viewer/visual/raster.dart'; import 'package:aves/widgets/viewer/visual/state.dart'; @@ -143,7 +143,7 @@ class _EntryPageViewState extends State { }, ); - return Consumer( + return Consumer( builder: (context, info, child) => Hero( tag: info?.entry == mainEntry ? mainEntry : hashCode, transitionOnUserGestures: true,