diff --git a/lib/common/widgets/image/custom_grid_view.dart b/lib/common/widgets/image/custom_grid_view.dart index 688dc7a0..e6c65c6b 100644 --- a/lib/common/widgets/image/custom_grid_view.dart +++ b/lib/common/widgets/image/custom_grid_view.dart @@ -21,7 +21,6 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/custom_layout.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; -import 'package:PiliPlus/common/widgets/marquee.dart' show ContextSingleTicker; import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/utils/context_ext.dart'; @@ -65,7 +64,6 @@ class CustomGridView extends StatelessWidget { required this.maxWidth, required this.picArr, this.onViewImage, - this.onDismissed, this.fullScreen = false, }); @@ -73,7 +71,6 @@ class CustomGridView extends StatelessWidget { final double space; final List picArr; final VoidCallback? onViewImage; - final ValueChanged? onDismissed; final bool fullScreen; static bool horizontalPreview = Pref.horizontalPreview; @@ -96,20 +93,18 @@ class CustomGridView extends StatelessWidget { !context.mediaQuerySize.isPortrait) { final scaffoldState = Scaffold.maybeOf(context); if (scaffoldState != null) { + onViewImage?.call(); PageUtils.onHorizontalPreviewState( scaffoldState, - ContextSingleTicker(scaffoldState.context), imgList, index, ); return; } } - onViewImage?.call(); PageUtils.imageView( initialPage: index, imgList: imgList, - onDismissed: onDismissed, ); } diff --git a/lib/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart b/lib/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart index 238bc3bf..04e6beeb 100644 --- a/lib/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart +++ b/lib/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart @@ -8,10 +8,10 @@ import 'package:flutter/material.dart'; /// show a [Hero] animation. class HeroDialogRoute extends PageRoute { HeroDialogRoute({ - required this.builder, + required this.pageBuilder, }); - final WidgetBuilder builder; + final RoutePageBuilder pageBuilder; @override bool get opaque => false; @@ -50,12 +50,10 @@ class HeroDialogRoute extends PageRoute { Animation animation, Animation secondaryAnimation, ) { - final Widget child = builder(context); - final Widget result = Semantics( + return Semantics( scopesRoute: true, explicitChildNodes: true, - child: child, + child: pageBuilder(context, animation, secondaryAnimation), ); - return result; } } diff --git a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart index 53d60f5d..2900d7df 100644 --- a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart +++ b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart @@ -44,16 +44,12 @@ class InteractiveviewerGallery extends StatefulWidget { this.itemBuilder, this.maxScale = 8, this.minScale = 1.0, - this.onPageChanged, - this.onDismissed, - this.onClose, required this.quality, + this.onClose, }); final int quality; - final ValueChanged? onClose; - /// The sources to show. final List sources; @@ -67,9 +63,7 @@ class InteractiveviewerGallery extends StatefulWidget { final double minScale; - final ValueChanged? onPageChanged; - - final ValueChanged? onDismissed; + final VoidCallback? onClose; @override State createState() => @@ -121,7 +115,7 @@ class _InteractiveviewerGalleryState extends State @override void dispose() { - widget.onClose?.call(true); + widget.onClose?.call(); _player?.dispose(); _pageController.dispose(); _animationController @@ -206,7 +200,6 @@ class _InteractiveviewerGalleryState extends State if (item.sourceType == SourceType.livePhoto) { _onPlay(item.liveUrl!); } - widget.onPageChanged?.call(page); if (_transformationController.value != Matrix4.identity()) { // animate the reset for the transformation of the interactive viewer @@ -228,15 +221,6 @@ class _InteractiveviewerGalleryState extends State : url.http2https; } - void onClose() { - if (widget.onClose != null) { - widget.onClose!(false); - } else { - Get.back(); - widget.onDismissed?.call(_pageController.page!.floor()); - } - } - Player? _player; VideoController? _videoController; @@ -254,7 +238,7 @@ class _InteractiveviewerGalleryState extends State onNoBoundaryHit: _onNoBoundaryHit, maxScale: widget.maxScale, minScale: widget.minScale, - onDismissed: onClose, + onDismissed: Get.back, onReset: () { if (!_enablePageView) { setState(() { @@ -277,7 +261,7 @@ class _InteractiveviewerGalleryState extends State onTap: () => EasyThrottle.throttle( 'preview', const Duration(milliseconds: 555), - onClose, + Get.back, ), onDoubleTapDown: (TapDownDetails details) { _doubleTapLocalPosition = details.localPosition; diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 27dc70f5..7f7f81f1 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -98,7 +98,7 @@ class VideoDetailController extends GetxController final Rx videoState = LoadingState.loading().obs; /// 播放器配置 画质 音质 解码格式 - late Rx currentVideoQa; + final Rxn currentVideoQa = Rxn(); AudioQuality? currentAudioQa; late VideoDecodeFormatType currentDecodeFormats; @@ -239,15 +239,7 @@ class VideoDetailController extends GetxController } } - bool imageStatus = false; - - void onViewImage() { - imageStatus = true; - } - - void onDismissed(int _) { - imageStatus = false; - } + bool imageview = false; final isLoginVideo = Accounts.get(AccountType.video).isLogin; @@ -993,7 +985,7 @@ class VideoDetailController extends GetxController SmartDialog.showToast('UP主已关闭弹幕'); return; } - final isPlaying = plPlayerController.playerStatus.playing; + final isPlaying = autoPlay.value && plPlayerController.playerStatus.playing; if (isPlaying) { await plPlayerController.pause(); } @@ -1063,6 +1055,8 @@ class VideoDetailController extends GetxController /// 更新画质、音质 void updatePlayer() { + final currentVideoQa = this.currentVideoQa.value; + if (currentVideoQa == null) return; autoPlay.value = true; playedTime = plPlayerController.position.value; plPlayerController @@ -1070,7 +1064,7 @@ class VideoDetailController extends GetxController ..isBuffering.value = false ..buffered.value = Duration.zero; - final video = findVideoByQa(currentVideoQa.value.code); + final video = findVideoByQa(currentVideoQa.code); if (firstVideo.codecs != video.codecs) { currentDecodeFormats = VideoDecodeFormatType.fromString(video.codecs!); } @@ -1089,6 +1083,15 @@ class VideoDetailController extends GetxController playerInit(); } + FutureOr _initPlayerIfNeeded() { + if ((autoPlay.value || + (plPlayerController.preInitPlayer && + !plPlayerController.processing)) && + childKey.currentState?.mounted == true) { + return playerInit(); + } + } + Future playerInit({ String? video, String? audio, @@ -1248,10 +1251,8 @@ class VideoDetailController extends GetxController ); setVideoHeight(); currentDecodeFormats = VideoDecodeFormatType.fromString('avc1'); - currentVideoQa = Rx(VideoQuality.fromCode(data.quality!)); - if (autoPlay.value || plPlayerController.preInitPlayer) { - await playerInit(); - } + currentVideoQa.value = VideoQuality.fromCode(data.quality!); + await _initPlayerIfNeeded(); isQuerying = false; return; } @@ -1282,7 +1283,7 @@ class VideoDetailController extends GetxController numbers, ); } - currentVideoQa = Rx(VideoQuality.fromCode(resVideoQa)); + currentVideoQa.value = VideoQuality.fromCode(resVideoQa); /// 取出符合当前画质的videoList final List videosList = allVideosList @@ -1354,9 +1355,7 @@ class VideoDetailController extends GetxController firstAudio = AudioItem(); audioUrl = ''; } - if (autoPlay.value || plPlayerController.preInitPlayer) { - await playerInit(); - } + await _initPlayerIfNeeded(); } else { autoPlay.value = false; videoState.value = result..toast(); diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index da4e8a4d..1281094d 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -145,10 +145,8 @@ class _PgcIntroPageState extends State { children: [ GestureDetector( onTap: () { - videoDetailCtr.onViewImage(); PageUtils.imageView( imgList: [SourceModel(url: item.cover!)], - onDismissed: videoDetailCtr.onDismissed, ); }, child: Hero( diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index 4feb063f..630da948 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -398,10 +398,8 @@ class _HorizontalMemberPageState extends State { Widget _buildAvatar(String face) => GestureDetector( onTap: () { - widget.videoDetailController.onViewImage(); PageUtils.imageView( imgList: [SourceModel(url: face)], - onDismissed: widget.videoDetailController.onDismissed, ); }, child: NetworkImgLayer( diff --git a/lib/pages/video/reply/view.dart b/lib/pages/video/reply/view.dart index 58e13e12..05158fdd 100644 --- a/lib/pages/video/reply/view.dart +++ b/lib/pages/video/reply/view.dart @@ -20,15 +20,11 @@ class VideoReplyPanel extends StatefulWidget { super.key, this.replyLevel = 1, required this.heroTag, - this.onViewImage, - this.onDismissed, required this.isNested, }); final int replyLevel; final String heroTag; - final VoidCallback? onViewImage; - final ValueChanged? onDismissed; final bool isNested; @override @@ -216,8 +212,6 @@ class _VideoReplyPanelState extends State _videoReplyController.onRemove(index, item, subIndex), upMid: _videoReplyController.upMid, getTag: () => heroTag, - onViewImage: widget.onViewImage, - onDismissed: widget.onDismissed, onCheckReply: (item) => _videoReplyController .onCheckReply(item, isManual: true), onToggleTop: (item) => _videoReplyController.onToggleTop( @@ -258,8 +252,6 @@ class _VideoReplyPanelState extends State firstFloor: replyItem, replyType: _videoReplyController.videoType.replyType, isVideoDetail: true, - onViewImage: widget.onViewImage, - onDismissed: widget.onDismissed, isNested: widget.isNested, ), ); diff --git a/lib/pages/video/reply/widgets/reply_item_grpc.dart b/lib/pages/video/reply/widgets/reply_item_grpc.dart index 8dbfa64c..ec60d8c7 100644 --- a/lib/pages/video/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/reply/widgets/reply_item_grpc.dart @@ -50,7 +50,6 @@ class ReplyItemGrpc extends StatelessWidget { this.showDialogue, this.getTag, this.onViewImage, - this.onDismissed, this.onCheckReply, this.onToggleTop, this.jumpToDialogue, @@ -65,7 +64,6 @@ class ReplyItemGrpc extends StatelessWidget { final VoidCallback? showDialogue; final Function? getTag; final VoidCallback? onViewImage; - final ValueChanged? onDismissed; final ValueChanged? onCheckReply; final ValueChanged? onToggleTop; final VoidCallback? jumpToDialogue; @@ -317,7 +315,6 @@ class ReplyItemGrpc extends StatelessWidget { ) .toList(), onViewImage: onViewImage, - onDismissed: onDismissed, ), ), ), diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index aaecdbb8..bf314290 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -29,8 +29,6 @@ class VideoReplyReplyPanel extends CommonSlidePage { this.firstFloor, required this.isVideoDetail, required this.replyType, - this.onViewImage, - this.onDismissed, this.isNested = false, }); final int? id; @@ -40,8 +38,6 @@ class VideoReplyReplyPanel extends CommonSlidePage { final ReplyInfo? firstFloor; final bool isVideoDetail; final int replyType; - final VoidCallback? onViewImage; - final ValueChanged? onDismissed; final bool isNested; @override @@ -231,8 +227,6 @@ class _VideoReplyReplyPanelState extends State index: -1, ), upMid: _controller.upMid, - onViewImage: widget.onViewImage, - onDismissed: widget.onDismissed, onCheckReply: (item) => _controller.onCheckReply(item, isManual: true), ), @@ -390,8 +384,6 @@ class _VideoReplyReplyPanelState extends State SmartDialog.showToast('评论可能已被删除'); } }, - onViewImage: widget.onViewImage, - onDismissed: widget.onDismissed, onCheckReply: (item) => _controller.onCheckReply(item, isManual: true), ); } diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 1f5f1e5c..8b4211dd 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -6,6 +6,7 @@ import 'dart:ui'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -364,7 +365,8 @@ class _VideoDetailPageVState extends State @override // 离开当前页面时 Future didPushNext() async { - if (videoDetailController.imageStatus) { + if (Get.routing.route is HeroDialogRoute) { + videoDetailController.imageview = true; return; } @@ -395,7 +397,8 @@ class _VideoDetailPageVState extends State @override // 返回当前页面时 Future didPopNext() async { - if (videoDetailController.imageStatus) { + if (videoDetailController.imageview) { + videoDetailController.imageview = false; return; } @@ -519,7 +522,7 @@ class _VideoDetailPageVState extends State ..addListener(animListener); if (Utils.isMobile && mounted && isShowing && !isFullScreen) { if (isPortrait) { - if (!videoDetailController.imageStatus) { + if (!videoDetailController.imageview) { showStatusBar(); } } else if (!videoDetailController.horizontalScreen) { @@ -1944,8 +1947,6 @@ class _VideoDetailPageVState extends State key: videoReplyPanelKey, isNested: isNested, heroTag: heroTag, - onViewImage: videoDetailController.onViewImage, - onDismissed: videoDetailController.onDismissed, ); // ai总结 diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 0d87505e..5964bcb3 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -493,7 +493,7 @@ class HeaderControlState extends State { leading: const Icon(Icons.play_circle_outline, size: 20), title: const Text('选择画质', style: titleStyle), subtitle: Text( - '当前画质 ${videoDetailCtr.currentVideoQa.value.desc}', + '当前画质 ${videoDetailCtr.currentVideoQa.value?.desc}', style: subTitleStyle, ), ), @@ -759,7 +759,8 @@ class HeaderControlState extends State { return; } final List videoFormat = videoInfo.supportFormats!; - final VideoQuality currentVideoQa = videoDetailCtr.currentVideoQa.value; + final VideoQuality? currentVideoQa = videoDetailCtr.currentVideoQa.value; + if (currentVideoQa == null) return; /// 总质量分类 final int totalQaSam = videoFormat.length; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index fd4f6e07..5224e09c 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -621,6 +621,9 @@ class PlPlayerController { return _instance!; } + bool _processing = false; + bool get processing => _processing; + // 初始化资源 Future setDataSource( DataSource dataSource, { @@ -649,6 +652,7 @@ class PlPlayerController { Volume? volume, }) async { try { + _processing = true; this.isLive = isLive; _videoType = videoType ?? VideoType.ugc; this.width = width; @@ -709,6 +713,8 @@ class PlPlayerController { debugPrint(stackTrace.toString()); debugPrint('plPlayer err: $err'); } + } finally { + _processing = false; } } diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 2d6727fa..0ac33854 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -717,8 +717,11 @@ class _PLVideoPlayerState extends State BottomControlType.qa => Obx( () { - final VideoQuality currentVideoQa = + final VideoQuality? currentVideoQa = videoDetailController.currentVideoQa.value; + if (currentVideoQa == null) { + return const SizedBox.shrink(); + } final PlayUrlModel videoInfo = videoDetailController.data; if (videoInfo.dash == null) { return const SizedBox.shrink(); diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index 0da89479..f96c3dbc 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -41,17 +41,16 @@ abstract class PageUtils { static Future imageView({ int initialPage = 0, required List imgList, - ValueChanged? onDismissed, int? quality, }) { return Get.key.currentState!.push( HeroDialogRoute( - builder: (context) => InteractiveviewerGallery( - sources: imgList, - initIndex: initialPage, - onDismissed: onDismissed, - quality: quality ?? GlobalData().imgQuality, - ), + pageBuilder: (context, animation, secondaryAnimation) => + InteractiveviewerGallery( + sources: imgList, + initIndex: initialPage, + quality: quality ?? GlobalData().imgQuality, + ), ), ); } @@ -555,42 +554,28 @@ abstract class PageUtils { static void onHorizontalPreviewState( ScaffoldState state, - TickerProvider vsync, List imgList, int index, ) { - final ctr = AnimationController( - vsync: vsync, - duration: const Duration(milliseconds: 200), + final animController = AnimationController( + vsync: state, + duration: Duration.zero, + reverseDuration: Duration.zero, )..forward(); state.showBottomSheet( constraints: const BoxConstraints(), (context) { - return FadeTransition( - opacity: Tween(begin: 0, end: 1).animate(ctr), - child: InteractiveviewerGallery( - sources: imgList, - initIndex: index, - onClose: (value) async { - if (!value) { - try { - await ctr.reverse(); - } catch (_) {} - } - try { - ctr.dispose(); - } catch (_) {} - if (!value) { - Get.back(); - } - }, - quality: GlobalData().imgQuality, - ), + return InteractiveviewerGallery( + sources: imgList, + initIndex: index, + quality: GlobalData().imgQuality, + onClose: animController.dispose, ); }, enableDrag: false, elevation: 0.0, backgroundColor: Colors.transparent, + transitionAnimationController: animController, sheetAnimationStyle: const AnimationStyle(duration: Duration.zero), ); }