diff --git a/lib/widget/image_viewer.dart b/lib/widget/image_viewer.dart index 0f1f379e..1ec79234 100644 --- a/lib/widget/image_viewer.dart +++ b/lib/widget/image_viewer.dart @@ -50,7 +50,7 @@ class _ImageViewerState extends State minScale: 1.0, maxScale: 3.0, transformationController: _transformationController, - panEnabled: widget.canZoom, + panEnabled: widget.canZoom && _isZoomed, scaleEnabled: widget.canZoom, // allow the image to be zoomed to fill the whole screen child: Container( diff --git a/lib/widget/viewer.dart b/lib/widget/viewer.dart index ed331ed9..0c6ddb94 100644 --- a/lib/widget/viewer.dart +++ b/lib/widget/viewer.dart @@ -233,13 +233,12 @@ class _ViewerState extends State onNotification: (notif) => _onPageContentScrolled(notif, index), child: SingleChildScrollView( controller: _pageStates[index]!.scrollController, - physics: - _isDetailPaneActive ? null : const NeverScrollableScrollPhysics(), + physics: !_isZoomed ? null : const NeverScrollableScrollPhysics(), child: Stack( children: [ _buildItemView(context, index), Visibility( - visible: _isDetailPaneActive, + visible: !_isZoomed, child: AnimatedOpacity( opacity: _isShowDetailPane ? 1 : 0, duration: k.animationDurationNormal, @@ -260,11 +259,17 @@ class _ViewerState extends State const BorderRadius.vertical(top: Radius.circular(4)), ), margin: EdgeInsets.only(top: _calcDetailPaneOffset(index)), - child: ViewerDetailPane( - account: widget.account, - file: widget.streamFiles[index], - album: widget.album, - onSlideshowPressed: _onSlideshowPressed, + // this visibility widget avoids loading the detail pane + // until it's actually opened, otherwise swiping between + // photos will slow down severely + child: Visibility( + visible: _isShowDetailPane, + child: ViewerDetailPane( + account: widget.account, + file: widget.streamFiles[index], + album: widget.album, + onSlideshowPressed: _onSlideshowPressed, + ), ), ), ), @@ -350,6 +355,14 @@ class _ViewerState extends State }); } } + } else if (notification is ScrollUpdateNotification) { + if (!_isShowDetailPane) { + Future.delayed(Duration.zero, () { + setState(() { + _isShowDetailPane = true; + }); + }); + } } return false; } diff --git a/lib/widget/viewer_detail_pane.dart b/lib/widget/viewer_detail_pane.dart index 25626082..4228790a 100644 --- a/lib/widget/viewer_detail_pane.dart +++ b/lib/widget/viewer_detail_pane.dart @@ -30,6 +30,7 @@ import 'package:nc_photos/theme.dart'; import 'package:nc_photos/use_case/remove_from_album.dart'; import 'package:nc_photos/use_case/update_album.dart'; import 'package:nc_photos/use_case/update_property.dart'; +import 'package:nc_photos/widget/animated_visibility.dart'; import 'package:nc_photos/widget/gps_map.dart'; import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart'; import 'package:nc_photos/widget/photo_date_time_edit_dialog.dart'; @@ -71,6 +72,15 @@ class _ViewerDetailPaneState extends State { _initMetadata(); } } + + // postpone loading map to improve responsiveness + Future.delayed(const Duration(milliseconds: 750)).then((_) { + if (mounted) { + setState(() { + _shouldBlockGpsMap = false; + }); + } + }); } @override @@ -239,12 +249,17 @@ class _ViewerDetailPaneState extends State { subtitle: cameraSubStr.isNotEmpty ? Text(cameraSubStr) : null, ), if (features.isSupportMapView && _gps != null) - SizedBox( - height: 256, - child: GpsMap( - center: _gps!, - zoom: 16, - onTap: _onMapTap, + AnimatedVisibility( + opacity: _shouldBlockGpsMap ? 0 : 1, + curve: Curves.easeInOut, + duration: k.animationDurationNormal, + child: SizedBox( + height: 256, + child: GpsMap( + center: _gps!, + zoom: 16, + onTap: _onMapTap, + ), ), ), ], @@ -489,6 +504,8 @@ class _ViewerDetailPaneState extends State { late final bool _canRemoveFromAlbum = _checkCanRemoveFromAlbum(); + var _shouldBlockGpsMap = true; + static final _log = Logger("widget.viewer_detail_pane._ViewerDetailPaneState"); }