show entry in collection when leaving viewer
This commit is contained in:
parent
7ac6617154
commit
e9de80f887
3 changed files with 45 additions and 17 deletions
|
@ -6,17 +6,22 @@ class HighlightInfo extends ChangeNotifier {
|
|||
final EventBus eventBus = EventBus();
|
||||
|
||||
void trackItem<T>(
|
||||
T item, {
|
||||
T? item, {
|
||||
TrackPredicate? predicate,
|
||||
Alignment? alignment,
|
||||
bool? animate,
|
||||
Object? highlightItem,
|
||||
}) =>
|
||||
}) {
|
||||
if (item != null) {
|
||||
eventBus.fire(TrackEvent<T>(
|
||||
item,
|
||||
predicate ?? (_) => true,
|
||||
alignment ?? Alignment.center,
|
||||
animate ?? true,
|
||||
highlightItem,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Object? _item;
|
||||
|
||||
|
@ -43,14 +48,20 @@ class HighlightInfo extends ChangeNotifier {
|
|||
@immutable
|
||||
class TrackEvent<T> {
|
||||
final T item;
|
||||
final TrackPredicate predicate;
|
||||
final Alignment alignment;
|
||||
final bool animate;
|
||||
final Object? highlightItem;
|
||||
|
||||
const TrackEvent(
|
||||
this.item,
|
||||
this.predicate,
|
||||
this.alignment,
|
||||
this.animate,
|
||||
this.highlightItem,
|
||||
);
|
||||
}
|
||||
|
||||
// `itemVisibility`: percent of the item tracked already visible in viewport
|
||||
// return whether to proceed with tracking
|
||||
typedef TrackPredicate = bool Function(double itemVisibility);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
|
@ -36,12 +37,7 @@ mixin GridItemTrackerMixin<T, U extends StatefulWidget> on State<U>, WidgetsBind
|
|||
void initState() {
|
||||
super.initState();
|
||||
final highlightInfo = context.read<HighlightInfo>();
|
||||
_subscriptions.add(highlightInfo.eventBus.on<TrackEvent<T>>().listen((e) => _trackItem(
|
||||
e.item,
|
||||
alignment: e.alignment,
|
||||
animate: e.animate,
|
||||
highlightItem: e.highlightItem,
|
||||
)));
|
||||
_subscriptions.add(highlightInfo.eventBus.on<TrackEvent<T>>().listen(_trackItem));
|
||||
_lastOrientation = _windowOrientation;
|
||||
WidgetsBinding.instance!.addObserver(this);
|
||||
_saveLayoutMetrics();
|
||||
|
@ -66,22 +62,21 @@ mixin GridItemTrackerMixin<T, U extends StatefulWidget> on State<U>, WidgetsBind
|
|||
// `Scrollable.ensureVisible` only works on already rendered objects
|
||||
// `RenderViewport.showOnScreen` can find any `RenderSliver`, but not always a `RenderMetadata`
|
||||
// `RenderViewport.scrollOffsetOf` is a good alternative
|
||||
Future<void> _trackItem(
|
||||
T item, {
|
||||
required Alignment alignment,
|
||||
required bool animate,
|
||||
required Object? highlightItem,
|
||||
}) async {
|
||||
Future<void> _trackItem(TrackEvent event) async {
|
||||
final sectionedListLayout = context.read<SectionedListLayout<T>>();
|
||||
final tileRect = sectionedListLayout.getTileRect(item);
|
||||
final tileRect = sectionedListLayout.getTileRect(event.item);
|
||||
if (tileRect == null) return;
|
||||
|
||||
final viewportRect = Rect.fromLTWH(0, scrollController.offset, scrollableSize.width, scrollableSize.height);
|
||||
final itemVisibility = max(0, tileRect.intersect(viewportRect).height) / tileRect.height;
|
||||
if (!event.predicate(itemVisibility)) return;
|
||||
|
||||
// most of the time the app bar will be scrolled away after scaling,
|
||||
// so we compensate for it to center the focal point thumbnail
|
||||
final appBarHeight = appBarHeightNotifier.value;
|
||||
final scrollOffset = appBarHeight + tileRect.top + (tileRect.height - scrollableSize.height) * ((alignment.y + 1) / 2);
|
||||
final scrollOffset = appBarHeight + tileRect.top + (tileRect.height - scrollableSize.height) * ((event.alignment.y + 1) / 2);
|
||||
|
||||
if (animate) {
|
||||
if (event.animate) {
|
||||
if (scrollOffset > 0) {
|
||||
await scrollController.animateTo(
|
||||
scrollOffset,
|
||||
|
@ -95,6 +90,7 @@ mixin GridItemTrackerMixin<T, U extends StatefulWidget> on State<U>, WidgetsBind
|
|||
await Future.delayed(Durations.highlightJumpDelay);
|
||||
}
|
||||
|
||||
final highlightItem = event.highlightItem;
|
||||
if (highlightItem != null) {
|
||||
context.read<HighlightInfo>().set(highlightItem);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:math';
|
|||
import 'package:aves/model/actions/entry_actions.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/model/multipage.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
|
@ -62,6 +63,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
late EntryActionDelegate _actionDelegate;
|
||||
final List<Tuple2<String, ValueNotifier<ViewState>>> _viewStateNotifiers = [];
|
||||
final ValueNotifier<HeroInfo?> _heroInfoNotifier = ValueNotifier(null);
|
||||
bool _isEntryTracked = true;
|
||||
|
||||
CollectionLens? get collection => widget.collection;
|
||||
|
||||
|
@ -166,6 +168,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
// back from info to image
|
||||
_goToVerticalPage(imagePage);
|
||||
} else {
|
||||
if (!_isEntryTracked) _trackEntry();
|
||||
_popVisual();
|
||||
}
|
||||
return SynchronousFuture(false);
|
||||
|
@ -370,6 +373,9 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
}
|
||||
|
||||
void _onVerticalPageControllerChange() {
|
||||
if (!_isEntryTracked && _verticalPager.page?.floor() == transitionPage) {
|
||||
_trackEntry();
|
||||
}
|
||||
_verticalScrollNotifier.notifyListeners();
|
||||
}
|
||||
|
||||
|
@ -451,6 +457,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
final newEntry = _currentHorizontalPage < entries.length ? entries[_currentHorizontalPage] : null;
|
||||
if (_entryNotifier.value == newEntry) return;
|
||||
_entryNotifier.value = newEntry;
|
||||
_isEntryTracked = false;
|
||||
await _pauseVideoControllers();
|
||||
await _initEntryControllers();
|
||||
}
|
||||
|
@ -478,6 +485,20 @@ class _EntryViewerStackState extends State<EntryViewerStack> with SingleTickerPr
|
|||
}
|
||||
}
|
||||
|
||||
// track item when returning to collection,
|
||||
// if they are not fully visible already
|
||||
void _trackEntry() {
|
||||
_isEntryTracked = true;
|
||||
final entry = _entryNotifier.value;
|
||||
if (entry != null && hasCollection) {
|
||||
context.read<HighlightInfo>().trackItem(
|
||||
entry,
|
||||
predicate: (v) => v < 1,
|
||||
animate: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _onLeave() {
|
||||
_showSystemUI();
|
||||
if (settings.keepScreenOn == KeepScreenOn.viewerOnly) {
|
||||
|
|
Loading…
Reference in a new issue