fixed viewer hero
This commit is contained in:
parent
e77ed02164
commit
910dd1fe54
3 changed files with 40 additions and 24 deletions
|
@ -12,6 +12,7 @@ import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
import 'package:aves/widgets/viewer/entry_action_delegate.dart';
|
import 'package:aves/widgets/viewer/entry_action_delegate.dart';
|
||||||
import 'package:aves/widgets/viewer/entry_vertical_pager.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/info/notifications.dart';
|
||||||
import 'package:aves/widgets/viewer/multipage.dart';
|
import 'package:aves/widgets/viewer/multipage.dart';
|
||||||
import 'package:aves/widgets/viewer/overlay/bottom.dart';
|
import 'package:aves/widgets/viewer/overlay/bottom.dart';
|
||||||
|
@ -57,7 +58,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
final List<Tuple2<String, IjkMediaController>> _videoControllers = [];
|
final List<Tuple2<String, IjkMediaController>> _videoControllers = [];
|
||||||
final List<Tuple2<String, MultiPageController>> _multiPageControllers = [];
|
final List<Tuple2<String, MultiPageController>> _multiPageControllers = [];
|
||||||
final List<Tuple2<String, ValueNotifier<ViewState>>> _viewStateNotifiers = [];
|
final List<Tuple2<String, ValueNotifier<ViewState>>> _viewStateNotifiers = [];
|
||||||
final ValueNotifier<VisualLeaveInfo> _visualLeaveInfoNotifier = ValueNotifier(null);
|
final ValueNotifier<HeroInfo> _heroInfoNotifier = ValueNotifier(null);
|
||||||
|
|
||||||
CollectionLens get collection => widget.collection;
|
CollectionLens get collection => widget.collection;
|
||||||
|
|
||||||
|
@ -75,6 +76,8 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
final entry = widget.initialEntry;
|
final entry = widget.initialEntry;
|
||||||
|
// opening hero, with viewer as target
|
||||||
|
_heroInfoNotifier.value = HeroInfo(entry);
|
||||||
_entryNotifier.value = entry;
|
_entryNotifier.value = entry;
|
||||||
_currentHorizontalPage = max(0, entries.indexOf(entry));
|
_currentHorizontalPage = max(0, entries.indexOf(entry));
|
||||||
_currentVerticalPage = ValueNotifier(imagePage);
|
_currentVerticalPage = ValueNotifier(imagePage);
|
||||||
|
@ -167,8 +170,8 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
}
|
}
|
||||||
return SynchronousFuture(false);
|
return SynchronousFuture(false);
|
||||||
},
|
},
|
||||||
child: ValueListenableProvider<VisualLeaveInfo>.value(
|
child: ValueListenableProvider<HeroInfo>.value(
|
||||||
value: _visualLeaveInfoNotifier,
|
value: _heroInfoNotifier,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return NotificationListener(
|
return NotificationListener(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
|
@ -365,6 +368,9 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
if (page == transitionPage) {
|
if (page == transitionPage) {
|
||||||
await _actionDelegate.dismissFeedback();
|
await _actionDelegate.dismissFeedback();
|
||||||
_popVisual();
|
_popVisual();
|
||||||
|
} else if (page == infoPage) {
|
||||||
|
// prevent hero when viewer is offscreen
|
||||||
|
_heroInfoNotifier.value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,12 +415,21 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
|
|
||||||
void _popVisual() {
|
void _popVisual() {
|
||||||
if (Navigator.canPop(context)) {
|
if (Navigator.canPop(context)) {
|
||||||
_visualLeaveInfoNotifier.value = VisualLeaveInfo(_entryNotifier.value);
|
void pop() {
|
||||||
// we post closing the viewer page so that hero animation source is ready
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
_onLeave();
|
_onLeave();
|
||||||
Navigator.pop(context);
|
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 {
|
} else {
|
||||||
// exit app when trying to pop a viewer page for a single entry
|
// exit app when trying to pop a viewer page for a single entry
|
||||||
SystemNavigator.pop();
|
SystemNavigator.pop();
|
||||||
|
@ -518,18 +533,3 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
|
|
||||||
void _pauseVideoControllers() => _videoControllers.forEach((e) => e.item2.pause());
|
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;
|
|
||||||
}
|
|
||||||
|
|
16
lib/widgets/viewer/hero.dart
Normal file
16
lib/widgets/viewer/hero.dart
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -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_boundaries.dart';
|
||||||
import 'package:aves/widgets/common/magnifier/scale/scale_level.dart';
|
import 'package:aves/widgets/common/magnifier/scale/scale_level.dart';
|
||||||
import 'package:aves/widgets/common/magnifier/scale/state.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/error.dart';
|
||||||
import 'package:aves/widgets/viewer/visual/raster.dart';
|
import 'package:aves/widgets/viewer/visual/raster.dart';
|
||||||
import 'package:aves/widgets/viewer/visual/state.dart';
|
import 'package:aves/widgets/viewer/visual/state.dart';
|
||||||
|
@ -143,7 +143,7 @@ class _EntryPageViewState extends State<EntryPageView> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return Consumer<VisualLeaveInfo>(
|
return Consumer<HeroInfo>(
|
||||||
builder: (context, info, child) => Hero(
|
builder: (context, info, child) => Hero(
|
||||||
tag: info?.entry == mainEntry ? mainEntry : hashCode,
|
tag: info?.entry == mainEntry ? mainEntry : hashCode,
|
||||||
transitionOnUserGestures: true,
|
transitionOnUserGestures: true,
|
||||||
|
|
Loading…
Reference in a new issue