diff --git a/lib/widgets/viewer/entry_viewer_stack.dart b/lib/widgets/viewer/entry_viewer_stack.dart index b122c1474..b74579cdf 100644 --- a/lib/widgets/viewer/entry_viewer_stack.dart +++ b/lib/widgets/viewer/entry_viewer_stack.dart @@ -248,8 +248,7 @@ class _EntryViewerStackState extends State with EntryViewContr _overlayVisible.value = true; } } else if (notification is ShowInfoPageNotification) { - // remove focus, if any, to prevent viewer shortcuts activation from the Info page - _showInfoPage(); + _goToVerticalPage(infoPage); } else if (notification is JumpToPreviousEntryNotification) { _jumpToHorizontalPageByDelta(-1); } else if (notification is JumpToNextEntryNotification) { @@ -516,12 +515,6 @@ class _EntryViewerStackState extends State with EntryViewContr ); } - void _showInfoPage() { - // remove focus, if any, to prevent viewer shortcuts activation from the Info page - FocusManager.instance.primaryFocus?.unfocus(); - _goToVerticalPage(infoPage); - } - Future _goToVerticalPage(int page) async { final animationDuration = context.read().viewerVerticalPageScrollAnimation; if (animationDuration > Duration.zero) { diff --git a/lib/widgets/viewer/info/info_page.dart b/lib/widgets/viewer/info/info_page.dart index 22c9516e3..e5b2b5c43 100644 --- a/lib/widgets/viewer/info/info_page.dart +++ b/lib/widgets/viewer/info/info_page.dart @@ -38,11 +38,50 @@ class InfoPage extends StatefulWidget { } class _InfoPageState extends State { + final FocusNode _focusNode = FocusNode(); final ScrollController _scrollController = ScrollController(); bool _scrollStartFromTop = false; static const splitScreenWidthThreshold = 600; + @override + void initState() { + super.initState(); + _registerWidget(widget); + _onScrollingChanged(); + } + + @override + void didUpdateWidget(covariant InfoPage oldWidget) { + super.didUpdateWidget(oldWidget); + _unregisterWidget(oldWidget); + _registerWidget(widget); + } + + @override + void dispose() { + _unregisterWidget(widget); + _focusNode.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + void _registerWidget(InfoPage widget) { + widget.isScrollingNotifier.addListener(_onScrollingChanged); + } + + void _unregisterWidget(InfoPage widget) { + widget.isScrollingNotifier.removeListener(_onScrollingChanged); + } + + void _onScrollingChanged() { + if (!widget.isScrollingNotifier.value) { + // using `autofocus` while scrolling seems to fail for widget built offscreen + // so we give focus to this page when the screen is no longer scrolling + _focusNode.requestFocus(); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -63,13 +102,16 @@ class _InfoPageState extends State { final targetEntry = pageEntry ?? mainEntry; return EmbeddedDataOpener( entry: targetEntry, - child: _InfoPageContent( - collection: widget.collection, - entry: targetEntry, - isScrollingNotifier: widget.isScrollingNotifier, - scrollController: _scrollController, - split: mqWidth > splitScreenWidthThreshold, - goToViewer: _goToViewer, + child: Focus( + focusNode: _focusNode, + child: _InfoPageContent( + collection: widget.collection, + entry: targetEntry, + isScrollingNotifier: widget.isScrollingNotifier, + scrollController: _scrollController, + split: mqWidth > splitScreenWidthThreshold, + goToViewer: _goToViewer, + ), ), ); } @@ -173,6 +215,8 @@ class _InfoPageContentState extends State<_InfoPageContent> { @override void dispose() { + _metadataNotifier.dispose(); + _isEditingMetadataNotifier.dispose(); _unregisterWidget(widget); super.dispose(); }