diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 3420dbf00..ee0bea5a9 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -20,7 +20,6 @@ import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; -import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; @@ -559,7 +558,7 @@ class _LiveRoomPageState extends State onPressed: () { final newVal = !enableShowDanmaku; plPlayerController.enableShowDanmaku.value = newVal; - if (!Pref.tempPlayerConf) { + if (!plPlayerController.tempPlayerConf) { GStorage.setting.put( SettingBoxKey.enableShowDanmaku, newVal, diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index 127737e02..85ce98568 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -4,7 +4,6 @@ import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/play_pause_btn.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; -import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -89,7 +88,7 @@ class BottomControl extends StatelessWidget { onPressed: () { final newVal = !enableShowDanmaku; plPlayerController.enableShowDanmaku.value = newVal; - if (!Pref.tempPlayerConf) { + if (!plPlayerController.tempPlayerConf) { GStorage.setting.put( SettingBoxKey.enableShowDanmaku, newVal, diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index 8b1a9036e..5d1cc43d1 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -26,6 +26,7 @@ class PgcIntroPage extends StatefulWidget { final String heroTag; final Function showEpisodes; final Function showIntroDetail; + final double maxWidth; const PgcIntroPage({ super.key, @@ -33,14 +34,16 @@ class PgcIntroPage extends StatefulWidget { required this.heroTag, required this.showEpisodes, required this.showIntroDetail, + required this.maxWidth, }); @override State createState() => _PgcIntroPageState(); } -class _PgcIntroPageState extends State +class _PgcIntroPageState extends TripleState with AutomaticKeepAliveClientMixin { + @override late PgcIntroController introController; late VideoDetailController videoDetailCtr; @@ -89,12 +92,15 @@ class _PgcIntroPageState extends State ), ); if (!introController.isPgc) { - sliver = SliverMainAxisGroup( - slivers: [ - sliver, - ?_buildBreif(item), - ], - ); + final breif = _buildBreif(item); + if (breif != null) { + sliver = SliverMainAxisGroup( + slivers: [ + sliver, + breif, + ], + ); + } } return SliverPadding( padding: @@ -107,32 +113,28 @@ class _PgcIntroPageState extends State Widget? _buildBreif(PgcInfoModel item) { final img = item.brief?.img; if (img != null && img.isNotEmpty) { - return SliverLayoutBuilder( - builder: (context, constraints) { - final maxWidth = constraints.crossAxisExtent; - double padding = max(0, maxWidth - 400); - final imgWidth = maxWidth - padding; - padding = padding / 2; - return SliverPadding( - padding: EdgeInsetsGeometry.only( - top: 10, - left: padding, - right: padding, - ), - sliver: SliverMainAxisGroup( - slivers: img.map((e) { - return SliverToBoxAdapter( - child: NetworkImgLayer( - radius: 0, - src: e.url, - width: imgWidth, - height: imgWidth * e.aspectRatio, - ), - ); - }).toList(), - ), - ); - }, + final maxWidth = widget.maxWidth - 2 * StyleString.safeSpace; + double padding = max(0, maxWidth - 400); + final imgWidth = maxWidth - padding; + padding = padding / 2; + return SliverPadding( + padding: EdgeInsetsGeometry.only( + top: 10, + left: padding, + right: padding, + ), + sliver: SliverMainAxisGroup( + slivers: img.map((e) { + return SliverToBoxAdapter( + child: NetworkImgLayer( + radius: 0, + src: e.url, + width: imgWidth, + height: imgWidth * e.aspectRatio, + ), + ); + }).toList(), + ), ); } return null; @@ -404,75 +406,65 @@ class _PgcIntroPageState extends State ) { return SizedBox( height: 48, - child: TripleBuilder( - introController: introController, - builder: (context, tripleAnimation, onStartTriple, onCancelTriple) { - return Row( - children: [ - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.thumbsUp), - selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), - onTap: () => introController.handleAction( - introController.actionLikeVideo, - ), - selectStatus: introController.hasLike.value, - semanticsLabel: '点赞', - text: NumUtil.numFormat(item.stat!.like), - onStartTriple: onStartTriple, - onCancelTriple: onCancelTriple, - ), + child: Row( + children: [ + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.thumbsUp), + selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), + selectStatus: introController.hasLike.value, + semanticsLabel: '点赞', + text: NumUtil.numFormat(item.stat!.like), + onStartTriple: onStartTriple, + onCancelTriple: onCancelTriple, + ), + ), + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.b), + selectIcon: const Icon(FontAwesomeIcons.b), + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, + semanticsLabel: '投币', + text: NumUtil.numFormat(item.stat!.coin), + ), + ), + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.star), + selectIcon: const Icon(FontAwesomeIcons.solidStar), + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( + context, + isLongPress: true, ), - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.b), - selectIcon: const Icon(FontAwesomeIcons.b), - onTap: () => introController.handleAction( - introController.actionCoinVideo, - ), - selectStatus: introController.hasCoin, - semanticsLabel: '投币', - text: NumUtil.numFormat(item.stat!.coin), - ), - ), - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.star), - selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => introController.showFavBottomSheet(context), - onLongPress: () => introController.showFavBottomSheet( - context, - isLongPress: true, - ), - selectStatus: introController.hasFav.value, - semanticsLabel: '收藏', - text: NumUtil.numFormat(item.stat!.favorite), - ), - ), - Obx( - () => ActionItem( - icon: const Icon(FontAwesomeIcons.clock), - selectIcon: const Icon(FontAwesomeIcons.solidClock), - onTap: () => - introController.handleAction(introController.viewLater), - selectStatus: introController.hasLater.value, - semanticsLabel: '再看', - text: '再看', - ), - ), - ActionItem( - icon: const Icon(FontAwesomeIcons.shareFromSquare), - onTap: () => introController.actionShareVideo(context), - selectStatus: false, - semanticsLabel: '转发', - text: NumUtil.numFormat(item.stat!.share), - ), - ], - ); - }, + selectStatus: introController.hasFav.value, + semanticsLabel: '收藏', + text: NumUtil.numFormat(item.stat!.favorite), + ), + ), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.clock), + selectIcon: const Icon(FontAwesomeIcons.solidClock), + onTap: () => + introController.handleAction(introController.viewLater), + selectStatus: introController.hasLater.value, + semanticsLabel: '再看', + text: '再看', + ), + ), + ActionItem( + icon: const Icon(FontAwesomeIcons.shareFromSquare), + onTap: () => introController.actionShareVideo(context), + selectStatus: false, + semanticsLabel: '转发', + text: NumUtil.numFormat(item.stat!.share), + ), + ], ), ); } diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index 42609be6f..ff82ab237 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -41,18 +41,21 @@ class UgcIntroPanel extends StatefulWidget { required this.showAiBottomSheet, required this.showEpisodes, required this.onShowMemberPage, + required this.isHorizontal, }); final String heroTag; final Function showAiBottomSheet; final Function showEpisodes; final ValueChanged onShowMemberPage; + final bool isHorizontal; @override State createState() => _UgcIntroPanelState(); } -class _UgcIntroPanelState extends State +class _UgcIntroPanelState extends TripleState with AutomaticKeepAliveClientMixin { + @override late UgcIntroController introController; late final VideoDetailController videoDetailCtr = Get.find(tag: widget.heroTag); @@ -75,267 +78,258 @@ class _UgcIntroPanelState extends State sizeCurve: Curves.linear, ); final isPortrait = context.isPortrait; - return SliverLayoutBuilder( - builder: (context, constraints) { - bool isHorizontal = - !isPortrait && - constraints.crossAxisExtent > - constraints.viewportMainAxisExtent * 1.25; - return SliverPadding( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - top: 10, - ), - sliver: Obx( - () { - VideoDetailData videoDetail = introController.videoDetail.value; - bool isLoading = videoDetail.bvid == null; - int? mid = videoDetail.owner?.mid; - return SliverToBoxAdapter( - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - if (isLoading) { - return; - } - feedBack(); - introController.expandableCtr.toggle(); - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () {}, - child: Row( - children: [ - if (videoDetail.staff.isNullOrEmpty) ...[ - Expanded( - child: Align( - alignment: Alignment.centerLeft, - child: _buildAvatar( - theme, - () { - if (mid != null) { - feedBack(); - if (!isPortrait && - introController - .horizontalMemberPage) { - widget.onShowMemberPage(mid); - } else { - Get.toNamed( - '/member?mid=$mid&from_view_aid=${videoDetailCtr.aid}', - ); - } - } - }, - ), - ), - ), - followButton(context, theme), - ] else - Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: ReloadScrollPhysics( - controller: introController, - ), - child: Row( - spacing: 25, - children: videoDetail.staff! - .map( - (e) => _buildStaff( - theme, - isPortrait, - mid, - e, - ), - ) - .toList(), - ), - ), - ), - if (isHorizontal) ...[ - const SizedBox(width: 10), - Expanded( - child: actionGrid( - context, - isLoading, - videoDetail, - introController, - ), - ), - ], - ], - ), - ), - const SizedBox(height: 8), - if (isLoading) - _buildVideoTitle(theme, videoDetail) - else - ExpandablePanel( - controller: introController.expandableCtr, - collapsed: GestureDetector( - onLongPress: () { - Feedback.forLongPress(context); - Utils.copyText(videoDetail.title ?? ''); - }, - child: _buildVideoTitle(theme, videoDetail), - ), - expanded: GestureDetector( - onLongPress: () { - Feedback.forLongPress(context); - Utils.copyText(videoDetail.title ?? ''); - }, - child: _buildVideoTitle( - theme, - videoDetail, - isExpand: true, - ), - ), - theme: expandTheme, - ), - const SizedBox(height: 8), - Stack( - clipBehavior: Clip.none, - children: [ - _buildInfo(theme, videoDetail), - if (introController.enableAi) _aiBtn, - ], - ), - if (videoDetail.argueInfo?.argueMsg?.isNotEmpty == true && - introController.showArgueMsg) ...[ - const SizedBox(height: 2), - Text.rich( - TextSpan( - children: [ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - size: 13, - Icons.error_outline, - color: theme.colorScheme.outline, - ), - ), - const WidgetSpan(child: SizedBox(width: 2)), - TextSpan( - text: '${videoDetail.argueInfo!.argueMsg}', - ), - ], - ), - style: TextStyle( - fontSize: 12, - color: theme.colorScheme.outline, - ), - ), - ], - ExpandablePanel( - controller: introController.expandableCtr, - collapsed: const SizedBox.shrink(), - expanded: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 8), - GestureDetector( - onTap: () => - Utils.copyText('${videoDetail.bvid}'), - child: Text( - videoDetail.bvid ?? '', - style: TextStyle( - fontSize: 14, - color: theme.colorScheme.secondary, - ), - ), - ), - if (videoDetail.descV2?.isNotEmpty == true) ...[ - const SizedBox(height: 8), - SelectableText.rich( - style: const TextStyle( - height: 1.4, - ), - TextSpan( - children: [ - buildContent(theme, videoDetail), - ], - ), - ), - ], - Obx(() { - final videoTags = introController.videoTags.value; - if (videoTags.isNullOrEmpty) { - return const SizedBox.shrink(); - } - return _buildTags(videoTags!); - }), - ], - ), - theme: expandTheme, - ), - Obx( - () => introController.status.value - ? const SizedBox.shrink() - : Center( - child: TextButton.icon( - icon: const Icon(Icons.refresh), - onPressed: () { - introController - ..status.value = true - ..queryVideoIntro(); - if (videoDetailCtr.videoUrl.isNullOrEmpty && - !videoDetailCtr.isQuerying) { - videoDetailCtr.queryVideoUrl(); + final isHorizontal = !isPortrait && widget.isHorizontal; + return SliverPadding( + padding: const EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + top: 10, + ), + sliver: Obx( + () { + VideoDetailData videoDetail = introController.videoDetail.value; + bool isLoading = videoDetail.bvid == null; + int? mid = videoDetail.owner?.mid; + return SliverToBoxAdapter( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (isLoading) { + return; + } + feedBack(); + introController.expandableCtr.toggle(); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () {}, + child: Row( + children: [ + if (videoDetail.staff.isNullOrEmpty) ...[ + Expanded( + child: Align( + alignment: Alignment.centerLeft, + child: _buildAvatar( + theme, + () { + if (mid != null) { + feedBack(); + if (!isPortrait && + introController.horizontalMemberPage) { + widget.onShowMemberPage(mid); + } else { + Get.toNamed( + '/member?mid=$mid&from_view_aid=${videoDetailCtr.aid}', + ); } - }, - label: const Text("点此重新加载"), - ), + } + }, ), + ), + ), + followButton(context, theme), + ] else + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: ReloadScrollPhysics( + controller: introController, + ), + child: Row( + spacing: 25, + children: videoDetail.staff! + .map( + (e) => _buildStaff( + theme, + isPortrait, + mid, + e, + ), + ) + .toList(), + ), + ), + ), + if (isHorizontal) ...[ + const SizedBox(width: 10), + Expanded( + child: actionGrid( + context, + isLoading, + videoDetail, + introController, + ), + ), + ], + ], + ), + ), + const SizedBox(height: 8), + if (isLoading) + _buildVideoTitle(theme, videoDetail) + else + ExpandablePanel( + controller: introController.expandableCtr, + collapsed: GestureDetector( + onLongPress: () { + Feedback.forLongPress(context); + Utils.copyText(videoDetail.title ?? ''); + }, + child: _buildVideoTitle(theme, videoDetail), ), - // 点赞收藏转发 布局样式2 - if (!isHorizontal) ...[ - const SizedBox(height: 8), - actionGrid( - context, - isLoading, + expanded: GestureDetector( + onLongPress: () { + Feedback.forLongPress(context); + Utils.copyText(videoDetail.title ?? ''); + }, + child: _buildVideoTitle( + theme, videoDetail, - introController, + isExpand: true, ), - ], - // 合集 - if (!isLoading && - videoDetail.ugcSeason != null && - (isPortrait || - !videoDetailCtr - .plPlayerController - .horizontalSeasonPanel)) - SeasonPanel( - heroTag: widget.heroTag, - showEpisodes: widget.showEpisodes, - ugcIntroController: introController, - ), - if (!isLoading && - videoDetail.pages != null && - videoDetail.pages!.length > 1 && - (isPortrait || - !videoDetailCtr - .plPlayerController - .horizontalSeasonPanel)) ...[ - PagesPanel( - heroTag: widget.heroTag, - ugcIntroController: introController, - bvid: introController.bvid, - showEpisodes: widget.showEpisodes, - ), - ], + ), + theme: expandTheme, + ), + const SizedBox(height: 8), + Stack( + clipBehavior: Clip.none, + children: [ + _buildInfo(theme, videoDetail), + if (introController.enableAi) _aiBtn, ], ), - ), - ); - }, - ), - ); - }, + if (videoDetail.argueInfo?.argueMsg?.isNotEmpty == true && + introController.showArgueMsg) ...[ + const SizedBox(height: 2), + Text.rich( + TextSpan( + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + size: 13, + Icons.error_outline, + color: theme.colorScheme.outline, + ), + ), + const WidgetSpan(child: SizedBox(width: 2)), + TextSpan( + text: '${videoDetail.argueInfo!.argueMsg}', + ), + ], + ), + style: TextStyle( + fontSize: 12, + color: theme.colorScheme.outline, + ), + ), + ], + ExpandablePanel( + controller: introController.expandableCtr, + collapsed: const SizedBox.shrink(), + expanded: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + GestureDetector( + onTap: () => Utils.copyText('${videoDetail.bvid}'), + child: Text( + videoDetail.bvid ?? '', + style: TextStyle( + fontSize: 14, + color: theme.colorScheme.secondary, + ), + ), + ), + if (videoDetail.descV2?.isNotEmpty == true) ...[ + const SizedBox(height: 8), + SelectableText.rich( + style: const TextStyle( + height: 1.4, + ), + TextSpan( + children: [ + buildContent(theme, videoDetail), + ], + ), + ), + ], + Obx(() { + final videoTags = introController.videoTags.value; + if (videoTags.isNullOrEmpty) { + return const SizedBox.shrink(); + } + return _buildTags(videoTags!); + }), + ], + ), + theme: expandTheme, + ), + Obx( + () => introController.status.value + ? const SizedBox.shrink() + : Center( + child: TextButton.icon( + icon: const Icon(Icons.refresh), + onPressed: () { + introController + ..status.value = true + ..queryVideoIntro(); + if (videoDetailCtr.videoUrl.isNullOrEmpty && + !videoDetailCtr.isQuerying) { + videoDetailCtr.queryVideoUrl(); + } + }, + label: const Text("点此重新加载"), + ), + ), + ), + // 点赞收藏转发 布局样式2 + if (!isHorizontal) ...[ + const SizedBox(height: 8), + actionGrid( + context, + isLoading, + videoDetail, + introController, + ), + ], + // 合集 + if (!isLoading && + videoDetail.ugcSeason != null && + (isPortrait || + !videoDetailCtr + .plPlayerController + .horizontalSeasonPanel)) + SeasonPanel( + heroTag: widget.heroTag, + showEpisodes: widget.showEpisodes, + ugcIntroController: introController, + ), + if (!isLoading && + videoDetail.pages != null && + videoDetail.pages!.length > 1 && + (isPortrait || + !videoDetailCtr + .plPlayerController + .horizontalSeasonPanel)) ...[ + PagesPanel( + heroTag: widget.heroTag, + ugcIntroController: introController, + bvid: introController.bvid, + showEpisodes: widget.showEpisodes, + ), + ], + ], + ), + ), + ); + }, + ), ); } @@ -506,95 +500,85 @@ class _UgcIntroPanelState extends State ) { return SizedBox( height: 48, - child: TripleBuilder( - introController: introController, - builder: (context, tripleAnimation, onStartTriple, onCancelTriple) { - return Row( - children: [ - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.thumbsUp), - selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), - onTap: () => introController.handleAction( - introController.actionLikeVideo, - ), - selectStatus: introController.hasLike.value, - semanticsLabel: '点赞', - text: !isLoading - ? NumUtil.numFormat(videoDetail.stat!.like) - : null, - onStartTriple: onStartTriple, - onCancelTriple: onCancelTriple, - ), + child: Row( + children: [ + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.thumbsUp), + selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), + selectStatus: introController.hasLike.value, + semanticsLabel: '点赞', + text: !isLoading + ? NumUtil.numFormat(videoDetail.stat!.like) + : null, + onStartTriple: onStartTriple, + onCancelTriple: onCancelTriple, + ), + ), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.thumbsDown), + selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), + onTap: () => introController.handleAction( + introController.actionDislikeVideo, ), - Obx( - () => ActionItem( - icon: const Icon(FontAwesomeIcons.thumbsDown), - selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), - onTap: () => introController.handleAction( - introController.actionDislikeVideo, - ), - selectStatus: introController.hasDislike.value, - semanticsLabel: '点踩', - text: "点踩", - ), + selectStatus: introController.hasDislike.value, + semanticsLabel: '点踩', + text: "点踩", + ), + ), + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.b), + selectIcon: const Icon(FontAwesomeIcons.b), + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, + semanticsLabel: '投币', + text: !isLoading + ? NumUtil.numFormat(videoDetail.stat!.coin) + : null, + ), + ), + Obx( + () => ActionItem( + animation: tripleAnimation, + icon: const Icon(FontAwesomeIcons.star), + selectIcon: const Icon(FontAwesomeIcons.solidStar), + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( + context, + isLongPress: true, ), - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.b), - selectIcon: const Icon(FontAwesomeIcons.b), - onTap: () => introController.handleAction( - introController.actionCoinVideo, - ), - selectStatus: introController.hasCoin, - semanticsLabel: '投币', - text: !isLoading - ? NumUtil.numFormat(videoDetail.stat!.coin) - : null, - ), - ), - Obx( - () => ActionItem( - animation: tripleAnimation, - icon: const Icon(FontAwesomeIcons.star), - selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => introController.showFavBottomSheet(context), - onLongPress: () => introController.showFavBottomSheet( - context, - isLongPress: true, - ), - selectStatus: introController.hasFav.value, - semanticsLabel: '收藏', - text: !isLoading - ? NumUtil.numFormat(videoDetail.stat!.favorite) - : null, - ), - ), - Obx( - () => ActionItem( - icon: const Icon(FontAwesomeIcons.clock), - selectIcon: const Icon(FontAwesomeIcons.solidClock), - onTap: () => - introController.handleAction(introController.viewLater), - selectStatus: introController.hasLater.value, - semanticsLabel: '再看', - text: '再看', - ), - ), - ActionItem( - icon: const Icon(FontAwesomeIcons.shareFromSquare), - onTap: () => introController.actionShareVideo(context), - selectStatus: false, - semanticsLabel: '分享', - text: !isLoading - ? NumUtil.numFormat(videoDetail.stat!.share!) - : null, - ), - ], - ); - }, + selectStatus: introController.hasFav.value, + semanticsLabel: '收藏', + text: !isLoading + ? NumUtil.numFormat(videoDetail.stat!.favorite) + : null, + ), + ), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.clock), + selectIcon: const Icon(FontAwesomeIcons.solidClock), + onTap: () => + introController.handleAction(introController.viewLater), + selectStatus: introController.hasLater.value, + semanticsLabel: '再看', + text: '再看', + ), + ), + ActionItem( + icon: const Icon(FontAwesomeIcons.shareFromSquare), + onTap: () => introController.actionShareVideo(context), + selectStatus: false, + semanticsLabel: '分享', + text: !isLoading + ? NumUtil.numFormat(videoDetail.stat!.share!) + : null, + ), + ], ), ); } diff --git a/lib/pages/video/introduction/ugc/widgets/action_item.dart b/lib/pages/video/introduction/ugc/widgets/action_item.dart index 1789a724a..4bae792a3 100644 --- a/lib/pages/video/introduction/ugc/widgets/action_item.dart +++ b/lib/pages/video/introduction/ugc/widgets/action_item.dart @@ -79,9 +79,7 @@ class ActionItem extends StatelessWidget { ) : child, ); - return expand - ? Expanded(child: child) - : Material(type: MaterialType.transparency, child: child); + return expand ? Expanded(child: child) : child; } Widget _buildText(ThemeData theme) { @@ -135,7 +133,7 @@ class _ArcPainter extends CustomPainter { } @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return false; + bool shouldRepaint(covariant _ArcPainter oldDelegate) { + return sweepAngle != oldDelegate.sweepAngle || color != oldDelegate.color; } } diff --git a/lib/pages/video/introduction/ugc/widgets/triple_state.dart b/lib/pages/video/introduction/ugc/widgets/triple_state.dart index bd18397b9..94cc882df 100644 --- a/lib/pages/video/introduction/ugc/widgets/triple_state.dart +++ b/lib/pages/video/introduction/ugc/widgets/triple_state.dart @@ -9,29 +9,26 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; abstract class TripleState extends State with SingleTickerProviderStateMixin { - late final tripleAnimCtr = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 1000), - reverseDuration: const Duration(milliseconds: 400), - ); + CommonIntroController get introController; - late final tripleAnimation = Tween( + // no need for pugv + AnimationController? _tripleAnimCtr; + Animation? _tripleAnimation; + + AnimationController get tripleAnimCtr => + _tripleAnimCtr ??= AnimationController( + vsync: this, + duration: const Duration(milliseconds: 1200), + reverseDuration: const Duration(milliseconds: 400), + ); + + Animation get tripleAnimation => _tripleAnimation ??= Tween( begin: 0, end: -2 * pi, ).animate(CurvedAnimation(parent: tripleAnimCtr, curve: Curves.easeInOut)); - CommonIntroController get introController; - Timer? _timer; - // @mustCallSuper - // void tripleListener(AnimationStatus status) { - // if (status == AnimationStatus.completed) { - // tripleAnimCtr.reset(); - // onTriple(); - // } - // } - void _cancelTimer() { _timer?.cancel(); _timer = null; @@ -40,14 +37,14 @@ abstract class TripleState extends State @override void dispose() { _cancelTimer(); - tripleAnimCtr.dispose(); + _tripleAnimCtr?.dispose(); super.dispose(); } void onStartTriple() { _timer ??= Timer(const Duration(milliseconds: 200), () { + HapticFeedback.lightImpact(); if (introController.hasTriple) { - HapticFeedback.lightImpact(); SmartDialog.showToast('已完成三连'); } else { tripleAnimCtr.forward().whenComplete(() { @@ -71,39 +68,3 @@ abstract class TripleState extends State } } } - -class TripleBuilder extends StatefulWidget { - const TripleBuilder({ - super.key, - required this.builder, - required this.introController, - // this.tripleListener, - }); - final CommonIntroController introController; - final Widget Function( - BuildContext context, - Animation tripleAnimation, - void Function() onStartTriple, - void Function([bool]) onCancelTriple, - ) - builder; - // final AnimationStatusListener? tripleListener; - - @override - State createState() => _TripleBuilderState(); -} - -class _TripleBuilderState extends TripleState { - @override - Widget build(BuildContext context) => - widget.builder(context, tripleAnimation, onStartTriple, onCancelTriple); - - @override - late final CommonIntroController introController = widget.introController; - - // @override - // void tripleListener(AnimationStatus status) { - // super.tripleListener(status); - // widget.tripleListener?.call(status); - // } -} diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 906e995d1..a6331e332 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -43,14 +43,12 @@ import 'package:PiliPlus/plugin/pl_player/view.dart'; import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/services/shutdown_timer_service.dart'; import 'package:PiliPlus/utils/accounts.dart'; -import 'package:PiliPlus/utils/context_ext.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/image_util.dart'; import 'package:PiliPlus/utils/num_util.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; -import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:auto_orientation/auto_orientation.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -105,19 +103,17 @@ class _VideoDetailPageVState extends State bool get isFullScreen => plPlayerController?.isFullScreen.value ?? false; bool get _shouldShowSeasonPanel { - if (!videoDetailController.isUgc) { + if (isPortrait || !videoDetailController.isUgc) { return false; } late final videoDetail = ugcIntroController.videoDetail.value; return videoDetailController.plPlayerController.horizontalSeasonPanel && (videoDetail.ugcSeason != null || - ((videoDetail.pages?.length ?? 0) > 1)) && - context.isLandscape; + ((videoDetail.pages?.length ?? 0) > 1)); } bool get _horizontalPreview => - videoDetailController.plPlayerController.horizontalPreview && - context.isLandscape; + !isPortrait && videoDetailController.plPlayerController.horizontalPreview; StreamSubscription? _listenerFS; @@ -203,11 +199,10 @@ class _VideoDetailPageVState extends State final isVertical = videoDetailController.isVertical.value; final mode = plPlayerController?.mode; - late final size = Get.size; if (!(mode == FullScreenMode.vertical || (mode == FullScreenMode.auto && isVertical) || (mode == FullScreenMode.ratio && - (isVertical || size.height / size.width < 1.25)))) { + (isVertical || maxHeight / maxWidth < 1.25)))) { landScape(); } }); @@ -543,11 +538,8 @@ class _VideoDetailPageVState extends State } Widget get childWhenDisabled { - final isPortrait = context.isPortrait; + final isFullScreen = this.isFullScreen; final useSafeArea = !removeSafeArea && isPortrait && isFullScreen; - final size = MediaQuery.sizeOf(context); - final double width = size.width; - final double height = size.height; return SafeArea( top: useSafeArea, bottom: useSafeArea, @@ -611,8 +603,8 @@ class _VideoDetailPageVState extends State controller: videoDetailController.scrollCtr, onlyOneScrollInBody: true, pinnedHeaderSliverHeightBuilder: () { - double pinnedHeight = isFullScreen || context.isLandscape - ? MediaQuery.sizeOf(context).height + double pinnedHeight = this.isFullScreen || !isPortrait + ? maxHeight : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight @@ -638,6 +630,7 @@ class _VideoDetailPageVState extends State return pinnedHeight; }, headerSliverBuilder: (context, innerBoxIsScrolled) { + final isFullScreen = this.isFullScreen; return [ SliverAppBar( elevation: 0, @@ -646,7 +639,7 @@ class _VideoDetailPageVState extends State automaticallyImplyLeading: false, pinned: true, expandedHeight: isFullScreen || !isPortrait - ? height + ? maxHeight : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight @@ -674,21 +667,19 @@ class _VideoDetailPageVState extends State } return SizedBox( height: !isPortrait || isFullScreen - ? height - + ? maxHeight - (!isPortrait || removeSafeArea ? 0 - : MediaQuery.paddingOf( - this.context, - ).top) + : padding.top) : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight : videoDetailController.videoHeight, - width: width, + width: maxWidth, child: videoPlayer( - width, + maxWidth, !isPortrait || isFullScreen - ? height + ? maxHeight : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight @@ -952,7 +943,7 @@ class _VideoDetailPageVState extends State child: videoTabBarView( controller: videoDetailController.tabCtr, children: [ - videoIntro(true, false), + videoIntro(isHorizontal: false, needCtr: false), if (videoDetailController.showReply) videoReplyPanel(false), if (_shouldShowSeasonPanel) seasonPanel, @@ -969,20 +960,17 @@ class _VideoDetailPageVState extends State Widget get childWhenDisabledAlmostSquareInner => Obx( () { - final size = MediaQuery.sizeOf(context); - final double width = size.width; - final double height = size.height; - final padding = MediaQuery.paddingOf(context); + final isFullScreen = this.isFullScreen; if (videoDetailController.isVertical.value && enableVerticalExpand) { final double videoHeight = - height - (removeSafeArea ? 0 : padding.vertical); + maxHeight - (removeSafeArea ? 0 : padding.vertical); final double videoWidth = videoHeight * 9 / 16; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: videoHeight, - width: isFullScreen ? width : videoWidth, + width: isFullScreen ? maxWidth : videoWidth, child: videoPlayer(videoWidth, videoHeight), ), Expanded( @@ -997,7 +985,10 @@ class _VideoDetailPageVState extends State child: videoTabBarView( controller: videoDetailController.tabCtr, children: [ - videoIntro(), + videoIntro( + width: maxWidth - videoWidth, + height: maxHeight, + ), if (videoDetailController.showReply) videoReplyPanel(), if (_shouldShowSeasonPanel) seasonPanel, @@ -1011,15 +1002,16 @@ class _VideoDetailPageVState extends State ], ); } - final double videoHeight = height / 2.5; + final double videoHeight = maxHeight / 2.5; + final shouldShowSeasonPanel = _shouldShowSeasonPanel; return Column( children: [ SizedBox( - width: width, + width: maxWidth, height: isFullScreen - ? height - (removeSafeArea ? 0 : padding.vertical) + ? maxHeight - (removeSafeArea ? 0 : padding.vertical) : videoHeight, - child: videoPlayer(width, videoHeight), + child: videoPlayer(maxWidth, videoHeight), ), Expanded( child: Scaffold( @@ -1032,11 +1024,20 @@ class _VideoDetailPageVState extends State Expanded( child: Row( children: [ - Expanded(child: videoIntro()), + Expanded( + child: videoIntro( + width: () { + double flex = 1; + if (videoDetailController.showReply) flex++; + if (shouldShowSeasonPanel) flex++; + return maxWidth / flex; + }(), + height: maxHeight - videoHeight, + ), + ), if (videoDetailController.showReply) Expanded(child: videoReplyPanel()), - if (_shouldShowSeasonPanel) - Expanded(child: seasonPanel), + if (shouldShowSeasonPanel) Expanded(child: seasonPanel), ], ), ), @@ -1051,21 +1052,23 @@ class _VideoDetailPageVState extends State Widget get childWhenDisabledLandscapeInner => Obx( () { - final size = MediaQuery.sizeOf(context); - final double width = size.width; - final double height = size.height; - final padding = MediaQuery.paddingOf(context); + final isFullScreen = this.isFullScreen; if (videoDetailController.isVertical.value && enableVerticalExpand) { - final double videoHeight = height - (removeSafeArea ? 0 : padding.top); + final double videoHeight = + maxHeight - (removeSafeArea ? 0 : padding.top); final double videoWidth = videoHeight * 9 / 16; return Row( children: [ - Expanded( - child: isFullScreen ? const SizedBox.shrink() : videoIntro(), - ), + if (!isFullScreen) + Expanded( + child: videoIntro( + width: (maxWidth - videoWidth) / 2, + height: maxHeight, + ), + ), SizedBox( height: videoHeight, - width: isFullScreen ? width : videoWidth, + width: isFullScreen ? maxWidth : videoWidth, child: videoPlayer(videoWidth, videoHeight), ), Expanded( @@ -1093,27 +1096,34 @@ class _VideoDetailPageVState extends State ], ); } - double videoWidth = clampDouble(height / width * 1.08, 0.5, 0.7) * width; - if (width >= 560) { - videoWidth = min(videoWidth, width - 280); + double videoWidth = + clampDouble(maxHeight / maxWidth * 1.08, 0.5, 0.7) * maxWidth; + if (maxWidth >= 560) { + videoWidth = min(videoWidth, maxWidth - 280); } final double videoHeight = videoWidth * 9 / 16; + final introHeight = + maxHeight - videoHeight - (removeSafeArea ? 0 : padding.top); return Row( children: [ Column( children: [ SizedBox( - width: isFullScreen ? width : videoWidth, - height: isFullScreen ? height : videoHeight, + width: isFullScreen ? maxWidth : videoWidth, + height: isFullScreen ? maxHeight : videoHeight, child: videoPlayer(videoWidth, videoHeight), ), Offstage( offstage: isFullScreen, child: SizedBox( width: videoWidth, - height: - height - videoHeight - (removeSafeArea ? 0 : padding.top), - child: videoIntro(false, false), + height: introHeight, + child: videoIntro( + width: videoWidth, + height: introHeight, + needRelated: false, + needCtr: false, + ), ), ), ], @@ -1122,10 +1132,10 @@ class _VideoDetailPageVState extends State offstage: isFullScreen, child: SizedBox( width: - width - + maxWidth - videoWidth - (removeSafeArea ? 0 : padding.horizontal), - height: height - (removeSafeArea ? 0 : padding.top), + height: maxHeight - (removeSafeArea ? 0 : padding.top), child: Scaffold( key: videoDetailController.childKey, resizeToAvoidBottomInset: false, @@ -1173,46 +1183,52 @@ class _VideoDetailPageVState extends State }, ); - Widget get childWhenDisabledLandscape => Stack( - clipBehavior: Clip.none, - children: [ - Scaffold( - resizeToAvoidBottomInset: false, - key: videoDetailController.scaffoldKey, - appBar: (removeSafeArea || isFullScreen) - ? null - : AppBar( - backgroundColor: Colors.black, - toolbarHeight: 0, - ), - body: SafeArea( - left: !removeSafeArea && !isFullScreen, - right: !removeSafeArea && !isFullScreen, - top: !removeSafeArea && !isFullScreen, - bottom: false, - child: childWhenDisabledLandscapeInner, - ), - ), - ], - ); - - Widget get childWhenDisabledAlmostSquare => Scaffold( - resizeToAvoidBottomInset: false, - key: videoDetailController.scaffoldKey, - appBar: (removeSafeArea || isFullScreen) - ? null - : AppBar( - backgroundColor: Colors.black, - toolbarHeight: 0, + Widget get childWhenDisabledLandscape { + final isFullScreen = this.isFullScreen; + return Stack( + clipBehavior: Clip.none, + children: [ + Scaffold( + resizeToAvoidBottomInset: false, + key: videoDetailController.scaffoldKey, + appBar: (removeSafeArea || isFullScreen) + ? null + : AppBar( + backgroundColor: Colors.black, + toolbarHeight: 0, + ), + body: SafeArea( + left: !removeSafeArea && !isFullScreen, + right: !removeSafeArea && !isFullScreen, + top: !removeSafeArea && !isFullScreen, + bottom: false, + child: childWhenDisabledLandscapeInner, ), - body: SafeArea( - left: !removeSafeArea && !isFullScreen, - right: !removeSafeArea && !isFullScreen, - top: !removeSafeArea && !isFullScreen, - bottom: false, - child: childWhenDisabledAlmostSquareInner, - ), - ); + ), + ], + ); + } + + Widget get childWhenDisabledAlmostSquare { + final isFullScreen = this.isFullScreen; + return Scaffold( + resizeToAvoidBottomInset: false, + key: videoDetailController.scaffoldKey, + appBar: (removeSafeArea || isFullScreen) + ? null + : AppBar( + backgroundColor: Colors.black, + toolbarHeight: 0, + ), + body: SafeArea( + left: !removeSafeArea && !isFullScreen, + right: !removeSafeArea && !isFullScreen, + top: !removeSafeArea && !isFullScreen, + bottom: false, + child: childWhenDisabledAlmostSquareInner, + ), + ); + } Widget get manualPlayerWidget => Obx(() { if (!videoDetailController.autoPlay.value) { @@ -1400,28 +1416,33 @@ class _VideoDetailPageVState extends State } late ThemeData themeData; - - Widget get child { - if (!videoDetailController.horizontalScreen) { - return autoChoose(childWhenDisabled); - } - - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if (constraints.maxWidth > constraints.maxHeight * 1.25) { - return autoChoose(childWhenDisabledLandscape); - } else if (constraints.maxWidth * (9 / 16) < - (2 / 5) * constraints.maxHeight) { - return autoChoose(childWhenDisabled); - } else { - return autoChoose(childWhenDisabledAlmostSquare); - } - }, - ); - } + late bool isPortrait; + late double maxWidth; + late double maxHeight; + late EdgeInsets padding; @override Widget build(BuildContext context) { + padding = MediaQuery.paddingOf(context); + Widget child = LayoutBuilder( + builder: (context, constraints) { + maxWidth = constraints.maxWidth; + maxHeight = constraints.maxHeight; + isPortrait = maxHeight > maxWidth; + + if (!videoDetailController.horizontalScreen) { + return autoChoose(childWhenDisabled); + } + + if (maxWidth > maxHeight * 1.25) { + return autoChoose(childWhenDisabledLandscape); + } + if (maxWidth * (9 / 16) < (2 / 5) * maxHeight) { + return autoChoose(childWhenDisabled); + } + return autoChoose(childWhenDisabledAlmostSquare); + }, + ); return videoDetailController.plPlayerController.darkVideoPage ? Theme(data: themeData, child: child) : child; @@ -1542,19 +1563,13 @@ class _VideoDetailPageVState extends State height: 38, child: Obx( () { - final enableShowDanmaku = videoDetailController - .plPlayerController - .enableShowDanmaku - .value; + final ctr = videoDetailController.plPlayerController; + final enableShowDanmaku = ctr.enableShowDanmaku.value; return IconButton( onPressed: () { final newVal = !enableShowDanmaku; - videoDetailController - .plPlayerController - .enableShowDanmaku - .value = - newVal; - if (!Pref.tempPlayerConf) { + ctr.enableShowDanmaku.value = newVal; + if (!ctr.tempPlayerConf) { GStorage.setting.put( SettingBoxKey.enableShowDanmaku, newVal, @@ -1585,10 +1600,11 @@ class _VideoDetailPageVState extends State } Widget videoPlayer(double videoWidth, double videoHeight) { + final isFullScreen = this.isFullScreen; return PopScope( canPop: !isFullScreen && - (videoDetailController.horizontalScreen || context.isPortrait), + (videoDetailController.horizontalScreen || isPortrait), onPopInvokedWithResult: _onPopInvokedWithResult, child: Stack( clipBehavior: Clip.none, @@ -1627,7 +1643,7 @@ class _VideoDetailPageVState extends State videoDetailController.continuePlayingPart) Positioned( left: 16, - bottom: isFullScreen ? max(75, Get.height * 0.25) : 75, + bottom: isFullScreen ? max(75, maxHeight * 0.25) : 75, child: SizedBox( width: MediaQuery.textScalerOf(context).scale(120), child: AnimatedList( @@ -1746,8 +1762,13 @@ class _VideoDetailPageVState extends State ); } - Widget videoIntro([bool needRelated = true, bool needCtr = true]) { - final bottom = MediaQuery.paddingOf(context).bottom; + Widget videoIntro({ + double? width, + double? height, + bool? isHorizontal, + bool needRelated = true, + bool needCtr = true, + }) { Widget introPanel() => CustomScrollView( key: const PageStorageKey('简介'), controller: needCtr ? introScrollController : null, @@ -1762,6 +1783,7 @@ class _VideoDetailPageVState extends State showAiBottomSheet: showAiBottomSheet, showEpisodes: showEpisodes, onShowMemberPage: onShowMemberPage, + isHorizontal: isHorizontal ?? width! > height! * 1.25, ), if (needRelated && videoDetailController.plPlayerController.showRelatedVideo) ...[ @@ -1779,9 +1801,7 @@ class _VideoDetailPageVState extends State RelatedVideoPanel(key: relatedVideoPanelKey, heroTag: heroTag), ] else SliverToBoxAdapter( - child: SizedBox( - height: bottom + StyleString.safeSpace, - ), + child: SizedBox(height: padding.bottom + StyleString.safeSpace), ), ] else PgcIntroPage( @@ -1790,14 +1810,13 @@ class _VideoDetailPageVState extends State cid: videoDetailController.cid.value, showEpisodes: showEpisodes, showIntroDetail: showIntroDetail, + maxWidth: width ?? maxWidth, ), SliverToBoxAdapter( child: SizedBox( height: - bottom + - (videoDetailController.isPlayAll && context.isLandscape - ? 75 - : 0), + padding.bottom + + (videoDetailController.isPlayAll && !isPortrait ? 75 : 0), ), ), ], @@ -1810,7 +1829,7 @@ class _VideoDetailPageVState extends State Positioned( left: 12, right: 12, - bottom: bottom + 12, + bottom: padding.bottom + 12, child: Material( type: MaterialType.transparency, child: InkWell( @@ -2013,6 +2032,7 @@ class _VideoDetailPageVState extends State } void showEpisodes([int? index, season, episodes, bvid, aid, cid]) { + final isFullScreen = this.isFullScreen; if (cid == null) { videoDetailController.showMediaListPanel(context); return; @@ -2180,7 +2200,7 @@ class _VideoDetailPageVState extends State if (isFullScreen) { plPlayerController!.triggerFullScreen(status: false); } - if (!videoDetailController.horizontalScreen && context.isLandscape) { + if (!videoDetailController.horizontalScreen && !isPortrait) { verticalScreenForTwoSeconds(); } } diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 0784b7bd3..b500a587d 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -29,7 +29,6 @@ import 'package:PiliPlus/utils/image_util.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; -import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/utils/video_utils.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; @@ -63,7 +62,7 @@ class HeaderControl extends StatefulWidget { State createState() => HeaderControlState(); } -class HeaderControlState extends State { +class HeaderControlState extends TripleState { late final PlPlayerController plPlayerController = widget.controller; late final VideoDetailController videoDetailCtr = widget.videoDetailCtr; late final PlayUrlModel videoInfo = videoDetailCtr.data; @@ -72,6 +71,7 @@ class HeaderControlState extends State { String get heroTag => widget.heroTag; late final UgcIntroController ugcIntroController; late final PgcIntroController pgcIntroController; + @override late CommonIntroController introController = videoDetailCtr.isUgc ? ugcIntroController : pgcIntroController; @@ -664,7 +664,7 @@ class HeaderControlState extends State { ..updatePlayer(); // update - if (!Pref.tempPlayerConf) { + if (!plPlayerController.tempPlayerConf) { final res = await Connectivity().checkConnectivity(); if (res.contains(ConnectivityResult.wifi)) { setting.put( @@ -741,7 +741,7 @@ class HeaderControlState extends State { ..updatePlayer(); // update - if (!Pref.tempPlayerConf) { + if (!plPlayerController.tempPlayerConf) { final res = await Connectivity().checkConnectivity(); if (res.contains(ConnectivityResult.wifi)) { setting.put( @@ -2102,7 +2102,7 @@ class HeaderControlState extends State { onPressed: () { final newVal = !enableShowDanmaku; plPlayerController.enableShowDanmaku.value = newVal; - if (!Pref.tempPlayerConf) { + if (!plPlayerController.tempPlayerConf) { setting.put(SettingBoxKey.enableShowDanmaku, newVal); } }, @@ -2228,118 +2228,112 @@ class HeaderControlState extends State { ], ), if (showFSActionItem && isFullScreen) - TripleBuilder( - introController: introController, - builder: (context, tripleAnimation, onStartTriple, onCancelTriple) { - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( - expand: false, - icon: const Icon( - FontAwesomeIcons.thumbsUp, - color: Colors.white, - ), - selectIcon: const Icon( - FontAwesomeIcons.solidThumbsUp, - ), - selectStatus: introController.hasLike.value, - semanticsLabel: '点赞', - animation: tripleAnimation, - onStartTriple: () { - plPlayerController.tripling = true; - onStartTriple(); - }, - onCancelTriple: ([bool isTap = false]) { - plPlayerController - ..tripling = false - ..hideTaskControls(); - onCancelTriple(isTap); - }, - ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + icon: const Icon( + FontAwesomeIcons.thumbsUp, + color: Colors.white, ), + selectIcon: const Icon( + FontAwesomeIcons.solidThumbsUp, + ), + selectStatus: introController.hasLike.value, + semanticsLabel: '点赞', + animation: tripleAnimation, + onStartTriple: () { + plPlayerController.tripling = true; + onStartTriple(); + }, + onCancelTriple: ([bool isTap = false]) { + plPlayerController + ..tripling = false + ..hideTaskControls(); + onCancelTriple(isTap); + }, ), - if (introController case UgcIntroController ugc) - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( - expand: false, - icon: const Icon( - FontAwesomeIcons.thumbsDown, - color: Colors.white, - ), - selectIcon: const Icon( - FontAwesomeIcons.solidThumbsDown, - ), - onTap: ugc.actionDislikeVideo, - selectStatus: ugc.hasDislike.value, - semanticsLabel: '点踩', - ), - ), - ), - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( - expand: false, - animation: tripleAnimation, - icon: const Icon( - FontAwesomeIcons.b, - color: Colors.white, - ), - selectIcon: const Icon(FontAwesomeIcons.b), - onTap: introController.actionCoinVideo, - selectStatus: introController.hasCoin, - semanticsLabel: '投币', - ), - ), - ), - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( - expand: false, - animation: tripleAnimation, - icon: const Icon( - FontAwesomeIcons.star, - color: Colors.white, - ), - selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => - introController.showFavBottomSheet(context), - onLongPress: () => introController.showFavBottomSheet( - context, - isLongPress: true, - ), - selectStatus: introController.hasFav.value, - semanticsLabel: '收藏', - ), - ), - ), - SizedBox( - width: 42, - height: 34, - child: ActionItem( + ), + ), + if (introController case UgcIntroController ugc) + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( expand: false, icon: const Icon( - FontAwesomeIcons.shareFromSquare, + FontAwesomeIcons.thumbsDown, color: Colors.white, ), - onTap: () => introController.actionShareVideo(context), - semanticsLabel: '分享', + selectIcon: const Icon( + FontAwesomeIcons.solidThumbsDown, + ), + onTap: () => ugc.handleAction(ugc.actionDislikeVideo), + selectStatus: ugc.hasDislike.value, + semanticsLabel: '点踩', ), ), - ], - ); - }, + ), + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + animation: tripleAnimation, + icon: const Icon( + FontAwesomeIcons.b, + color: Colors.white, + ), + selectIcon: const Icon(FontAwesomeIcons.b), + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, + semanticsLabel: '投币', + ), + ), + ), + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + animation: tripleAnimation, + icon: const Icon( + FontAwesomeIcons.star, + color: Colors.white, + ), + selectIcon: const Icon(FontAwesomeIcons.solidStar), + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( + context, + isLongPress: true, + ), + selectStatus: introController.hasFav.value, + semanticsLabel: '收藏', + ), + ), + ), + SizedBox( + width: 42, + height: 34, + child: ActionItem( + expand: false, + icon: const Icon( + FontAwesomeIcons.shareFromSquare, + color: Colors.white, + ), + onTap: () => introController.actionShareVideo(context), + semanticsLabel: '分享', + ), + ), + ], ), ], ), diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 54350463c..78f1cbec3 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -336,6 +336,8 @@ class PlPlayerController { late final bool pipNoDanmaku = Pref.pipNoDanmaku; late final bool removeSafeArea = Pref.removeSafeArea; + late final bool tempPlayerConf = Pref.tempPlayerConf; + int? cacheVideoQa; late int cacheAudioQa; bool enableHeart = true; @@ -656,7 +658,7 @@ class PlPlayerController { type ??= superResolutionType; } else { superResolutionType = type; - if (isAnim && !Pref.tempPlayerConf) { + if (isAnim && !tempPlayerConf) { GStorage.setting.put(SettingBoxKey.superResolutionType, type); } } @@ -1314,7 +1316,7 @@ class PlPlayerController { /// 设置后台播放 Future setBackgroundPlay(bool val) async { videoPlayerServiceHandler.enableBackgroundPlay = val; - if (!Pref.tempPlayerConf) { + if (!tempPlayerConf) { setting.put(SettingBoxKey.enableBackgroundPlay, val); } } @@ -1596,7 +1598,7 @@ class PlPlayerController { void setContinuePlayInBackground() { _continuePlayInBackground.value = !_continuePlayInBackground.value; - if (!Pref.tempPlayerConf) { + if (!tempPlayerConf) { setting.put( SettingBoxKey.continuePlayInBackground, _continuePlayInBackground.value,