diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 50908ee6..d533e9f4 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -2433,15 +2433,15 @@ class DefaultAssetPickerBuilderDelegate } }); } - return AnnotatedRegion( - value: overlayStyle, - child: Theme( - data: theme, + return Theme( + data: theme, + child: AnnotatedRegion( + value: overlayStyle, child: CNP.value( value: provider, - builder: (BuildContext context, _) => Material( - color: theme.canvasColor, - child: Stack( + builder: (BuildContext context, _) => Scaffold( + backgroundColor: theme.scaffoldBackgroundColor, + body: Stack( fit: StackFit.expand, children: [ if (isAppleOS(context)) diff --git a/lib/src/delegates/asset_picker_viewer_builder_delegate.dart b/lib/src/delegates/asset_picker_viewer_builder_delegate.dart index 0d884751..e4c83491 100644 --- a/lib/src/delegates/asset_picker_viewer_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_viewer_builder_delegate.dart @@ -1010,9 +1010,9 @@ class DefaultAssetPickerViewerBuilderDelegate (themeData.effectiveBrightness.isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark), - child: Material( - color: themeData.scaffoldBackgroundColor, - child: Stack( + child: Scaffold( + resizeToAvoidBottomInset: false, + body: Stack( children: [ Positioned.fill(child: _pageViewBuilder(context)), if (isWeChatMoment && hasVideo) ...[ diff --git a/lib/src/widget/builder/image_page_builder.dart b/lib/src/widget/builder/image_page_builder.dart index 62de6eb8..c774ec48 100644 --- a/lib/src/widget/builder/image_page_builder.dart +++ b/lib/src/widget/builder/image_page_builder.dart @@ -10,6 +10,7 @@ import 'package:flutter/services.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager_image_provider/photo_manager_image_provider.dart'; import 'package:video_player/video_player.dart'; +import 'package:visibility_detector/visibility_detector.dart'; import 'package:wechat_picker_library/wechat_picker_library.dart'; import '../../constants/constants.dart'; @@ -174,29 +175,45 @@ class _LivePhotoWidgetState extends State<_LivePhotoWidget> { final _showVideo = ValueNotifier(false); late final _controller = widget.controller; + ScrollNotificationObserverState? _scrollNotificationObserver; + bool _scrolling = false; + @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - _controller.play().then((_) { - HapticFeedback.lightImpact(); - _showVideo.value = true; - }); - }); _controller.addListener(_notify); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _scrollNotificationObserver?.removeListener(_handleScrollNotification); + _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context); + _scrollNotificationObserver?.addListener(_handleScrollNotification); + } + @override void dispose() { + _scrollNotificationObserver?.removeListener(_handleScrollNotification); _controller.pause(); _controller.removeListener(_notify); super.dispose(); } - Future continuePlay() async { - if (_showVideo.value && _controller.value.position != Duration.zero) { - HapticFeedback.lightImpact(); - await _controller.play(); + void _handleScrollNotification(ScrollNotification notification) { + if (notification is ScrollStartNotification) { + _scrolling = true; + } else if (notification is ScrollEndNotification) { + _scrolling = false; + } + } + + void _onVisibilityChanged(VisibilityInfo info) { + final fraction = info.visibleFraction; + if (fraction == 1 && !_showVideo.value && !_scrolling) { + _showVideoAndPlay(); + } else if (fraction < 1 && _showVideo.value) { + _hideVideoAndStop(); } } @@ -218,75 +235,80 @@ class _LivePhotoWidgetState extends State<_LivePhotoWidget> { } Future _hideVideoAndStop() async { + _showVideo.value = false; + await Future.delayed(kThemeChangeDuration); await _controller.pause(); await _controller.seekTo(Duration.zero); - _showVideo.value = false; } @override Widget build(BuildContext context) { - return GestureDetector( - onLongPress: () { - _showVideoAndPlay(); - }, - onLongPressUp: () { - _hideVideoAndStop(); - }, - child: ExtendedImageGesture( - widget.state, - imageBuilder: ( - Widget image, { - ExtendedImageGestureState? imageGestureState, - }) { - return ValueListenableBuilder( - valueListenable: _showVideo, - builder: (context, showVideo, child) { - if (imageGestureState == null || - widget.state.extendedImageInfo == null) { - return child!; - } - final size = MediaQuery.sizeOf(context); - final rect = GestureWidgetDelegateFromState.getRectFormState( - Offset.zero & size, - imageGestureState, - width: _controller.value.size.width, - height: _controller.value.size.height, - copy: true, - ); - return Stack( - children: [ - imageGestureState.wrapGestureWidget( - FittedBox( - fit: BoxFit.cover, - clipBehavior: Clip.hardEdge, - child: SizedBox( - width: rect.width, - height: rect.height, - child: VideoPlayer(_controller), + return VisibilityDetector( + key: ValueKey(widget.state), + onVisibilityChanged: _onVisibilityChanged, + child: GestureDetector( + onLongPress: () { + _showVideoAndPlay(); + }, + onLongPressUp: () { + _hideVideoAndStop(); + }, + child: ExtendedImageGesture( + widget.state, + imageBuilder: ( + Widget image, { + ExtendedImageGestureState? imageGestureState, + }) { + return ValueListenableBuilder( + valueListenable: _showVideo, + builder: (context, showVideo, child) { + if (imageGestureState == null || + widget.state.extendedImageInfo == null) { + return child!; + } + final size = MediaQuery.sizeOf(context); + final rect = GestureWidgetDelegateFromState.getRectFormState( + Offset.zero & size, + imageGestureState, + width: _controller.value.size.width, + height: _controller.value.size.height, + copy: true, + ); + return Stack( + children: [ + imageGestureState.wrapGestureWidget( + FittedBox( + fit: BoxFit.cover, + clipBehavior: Clip.hardEdge, + child: SizedBox( + width: rect.width, + height: rect.height, + child: VideoPlayer(_controller), + ), ), ), - ), - Positioned.fill( - child: AnimatedOpacity( - duration: kThemeChangeDuration, - opacity: showVideo ? 0.0 : 1.0, - child: child!, + Positioned.fill( + child: AnimatedOpacity( + duration: kThemeChangeDuration, + opacity: showVideo ? 0.0 : 1.0, + child: child!, + ), ), - ), - Positioned.fromRect( - rect: rect, - child: AnimatedOpacity( - duration: kThemeChangeDuration, - opacity: showVideo ? 0.0 : 1.0, - child: _buildLivePhotoIndicator(context), + Positioned.fromRect( + rect: rect, + child: AnimatedOpacity( + duration: kThemeChangeDuration, + opacity: showVideo ? 0.0 : 1.0, + child: _buildLivePhotoIndicator(context), + ), ), - ), - ], - ); - }, - child: image, - ); - }, + ], + ); + }, + child: image, + ); + }, + ), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 825ce532..08288533 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: photo_manager_image_provider: ^2.0.0 provider: ^6.0.5 video_player: ^2.7.0 + visibility_detector: ^0.4.0 dev_dependencies: flutter_lints: any