collection: prevent hero when navigating from drawer
This commit is contained in:
parent
104373a186
commit
accfb2c57b
8 changed files with 37 additions and 21 deletions
|
@ -21,6 +21,7 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin, CollectionSel
|
||||||
EntryGroupFactor groupFactor;
|
EntryGroupFactor groupFactor;
|
||||||
EntrySortFactor sortFactor;
|
EntrySortFactor sortFactor;
|
||||||
final AChangeNotifier filterChangeNotifier = AChangeNotifier();
|
final AChangeNotifier filterChangeNotifier = AChangeNotifier();
|
||||||
|
int id;
|
||||||
bool listenToSource;
|
bool listenToSource;
|
||||||
|
|
||||||
List<AvesEntry> _filteredEntries;
|
List<AvesEntry> _filteredEntries;
|
||||||
|
@ -33,10 +34,12 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin, CollectionSel
|
||||||
Iterable<CollectionFilter> filters,
|
Iterable<CollectionFilter> filters,
|
||||||
@required EntryGroupFactor groupFactor,
|
@required EntryGroupFactor groupFactor,
|
||||||
@required EntrySortFactor sortFactor,
|
@required EntrySortFactor sortFactor,
|
||||||
|
this.id,
|
||||||
this.listenToSource = true,
|
this.listenToSource = true,
|
||||||
}) : filters = {if (filters != null) ...filters.where((f) => f != null)},
|
}) : filters = {if (filters != null) ...filters.where((f) => f != null)},
|
||||||
groupFactor = groupFactor ?? EntryGroupFactor.month,
|
groupFactor = groupFactor ?? EntryGroupFactor.month,
|
||||||
sortFactor = sortFactor ?? EntrySortFactor.date {
|
sortFactor = sortFactor ?? EntrySortFactor.date {
|
||||||
|
id ??= hashCode;
|
||||||
if (listenToSource) {
|
if (listenToSource) {
|
||||||
_subscriptions.add(source.eventBus.on<EntryAddedEvent>().listen((e) => _refresh()));
|
_subscriptions.add(source.eventBus.on<EntryAddedEvent>().listen((e) => _refresh()));
|
||||||
_subscriptions.add(source.eventBus.on<EntryRemovedEvent>().listen((e) => onEntryRemoved(e.entries)));
|
_subscriptions.add(source.eventBus.on<EntryRemovedEvent>().listen((e) => onEntryRemoved(e.entries)));
|
||||||
|
|
|
@ -54,16 +54,20 @@ class InteractiveThumbnail extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
TransparentMaterialPageRoute(
|
TransparentMaterialPageRoute(
|
||||||
settings: RouteSettings(name: EntryViewerPage.routeName),
|
settings: RouteSettings(name: EntryViewerPage.routeName),
|
||||||
pageBuilder: (c, a, sa) => EntryViewerPage(
|
pageBuilder: (c, a, sa) {
|
||||||
collection: CollectionLens(
|
final viewerCollection = CollectionLens(
|
||||||
source: collection.source,
|
source: collection.source,
|
||||||
filters: collection.filters,
|
filters: collection.filters,
|
||||||
groupFactor: collection.groupFactor,
|
groupFactor: collection.groupFactor,
|
||||||
sortFactor: collection.sortFactor,
|
sortFactor: collection.sortFactor,
|
||||||
|
id: collection.id,
|
||||||
listenToSource: false,
|
listenToSource: false,
|
||||||
),
|
);
|
||||||
initialEntry: entry,
|
return EntryViewerPage(
|
||||||
),
|
collection: viewerCollection,
|
||||||
|
initialEntry: entry,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,21 @@ class DecoratedThumbnail extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// hero tag should include a collection identifier, so that it animates
|
||||||
|
// between different views of the entry in the same collection (e.g. thumbnails <-> viewer)
|
||||||
|
// but not between different collection instances, even with the same attributes (e.g. reloading collection page via drawer)
|
||||||
|
final heroTag = hashValues(collection?.id, entry);
|
||||||
var child = entry.isSvg
|
var child = entry.isSvg
|
||||||
? VectorImageThumbnail(
|
? VectorImageThumbnail(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
extent: extent,
|
extent: extent,
|
||||||
canHero: true,
|
heroTag: heroTag,
|
||||||
)
|
)
|
||||||
: RasterImageThumbnail(
|
: RasterImageThumbnail(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
extent: extent,
|
extent: extent,
|
||||||
isScrollingNotifier: isScrollingNotifier,
|
isScrollingNotifier: isScrollingNotifier,
|
||||||
canHero: true,
|
heroTag: heroTag,
|
||||||
);
|
);
|
||||||
|
|
||||||
child = Stack(
|
child = Stack(
|
||||||
|
|
|
@ -10,14 +10,14 @@ class RasterImageThumbnail extends StatefulWidget {
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
final double extent;
|
final double extent;
|
||||||
final ValueNotifier<bool> isScrollingNotifier;
|
final ValueNotifier<bool> isScrollingNotifier;
|
||||||
final bool canHero;
|
final Object heroTag;
|
||||||
|
|
||||||
const RasterImageThumbnail({
|
const RasterImageThumbnail({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.entry,
|
@required this.entry,
|
||||||
@required this.extent,
|
@required this.extent,
|
||||||
this.isScrollingNotifier,
|
this.isScrollingNotifier,
|
||||||
this.canHero = false,
|
this.heroTag,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -124,9 +124,9 @@ class _RasterImageThumbnailState extends State<RasterImageThumbnail> {
|
||||||
height: extent,
|
height: extent,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
);
|
);
|
||||||
return widget.canHero
|
return widget.heroTag != null
|
||||||
? Hero(
|
? Hero(
|
||||||
tag: entry,
|
tag: widget.heroTag,
|
||||||
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {
|
||||||
return TransitionImage(
|
return TransitionImage(
|
||||||
image: entry.getBestThumbnail(extent),
|
image: entry.getBestThumbnail(extent),
|
||||||
|
|
|
@ -10,13 +10,13 @@ import 'package:provider/provider.dart';
|
||||||
class VectorImageThumbnail extends StatelessWidget {
|
class VectorImageThumbnail extends StatelessWidget {
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
final double extent;
|
final double extent;
|
||||||
final bool canHero;
|
final Object heroTag;
|
||||||
|
|
||||||
const VectorImageThumbnail({
|
const VectorImageThumbnail({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.entry,
|
@required this.entry,
|
||||||
@required this.extent,
|
@required this.extent,
|
||||||
this.canHero = false,
|
this.heroTag,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -63,9 +63,9 @@ class VectorImageThumbnail extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return canHero
|
return heroTag != null
|
||||||
? Hero(
|
? Hero(
|
||||||
tag: entry,
|
tag: heroTag,
|
||||||
transitionOnUserGestures: true,
|
transitionOnUserGestures: true,
|
||||||
child: child,
|
child: child,
|
||||||
)
|
)
|
||||||
|
|
|
@ -77,7 +77,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
super.initState();
|
super.initState();
|
||||||
final entry = widget.initialEntry;
|
final entry = widget.initialEntry;
|
||||||
// opening hero, with viewer as target
|
// opening hero, with viewer as target
|
||||||
_heroInfoNotifier.value = HeroInfo(entry);
|
_heroInfoNotifier.value = HeroInfo(collection?.id, 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);
|
||||||
|
@ -421,7 +421,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing hero, with viewer as source
|
// closing hero, with viewer as source
|
||||||
final heroInfo = HeroInfo(_entryNotifier.value);
|
final heroInfo = HeroInfo(collection?.id, _entryNotifier.value);
|
||||||
if (_heroInfoNotifier.value != heroInfo) {
|
if (_heroInfoNotifier.value != heroInfo) {
|
||||||
_heroInfoNotifier.value = heroInfo;
|
_heroInfoNotifier.value = heroInfo;
|
||||||
// we post closing the viewer page so that hero animation source is ready
|
// we post closing the viewer page so that hero animation source is ready
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
class HeroInfo {
|
class HeroInfo {
|
||||||
|
// hero tag should include a collection identifier, so that it animates
|
||||||
|
// between different views of the entry in the same collection (e.g. thumbnails <-> viewer)
|
||||||
|
// but not between different collection instances, even with the same attributes (e.g. reloading collection page via drawer)
|
||||||
|
final int collectionId;
|
||||||
final AvesEntry entry;
|
final AvesEntry entry;
|
||||||
|
|
||||||
const HeroInfo(this.entry);
|
const HeroInfo(this.collectionId, this.entry);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (other.runtimeType != runtimeType) return false;
|
if (other.runtimeType != runtimeType) return false;
|
||||||
return other is HeroInfo && other.entry == entry;
|
return other is HeroInfo && other.collectionId == collectionId && other.entry == entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => entry.hashCode;
|
int get hashCode => hashValues(collectionId, entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ class _EntryPageViewState extends State<EntryPageView> {
|
||||||
|
|
||||||
return Consumer<HeroInfo>(
|
return Consumer<HeroInfo>(
|
||||||
builder: (context, info, child) => Hero(
|
builder: (context, info, child) => Hero(
|
||||||
tag: info?.entry == mainEntry ? mainEntry : hashCode,
|
tag: info?.entry == mainEntry ? hashValues(info.collectionId, mainEntry) : hashCode,
|
||||||
transitionOnUserGestures: true,
|
transitionOnUserGestures: true,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue