diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index 1468023b..9bf67890 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:math'; import 'package:PiliPlus/common/constants.dart'; @@ -44,25 +43,17 @@ class _PgcIntroPageState extends State AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin, TripleAnimMixin { - late PgcIntroController pgcIntroController; + @override + late PgcIntroController introController; late VideoDetailController videoDetailCtr; - bool isProcessing = false; - Future handleState(FutureOr Function() action) async { - if (!isProcessing) { - isProcessing = true; - await action(); - isProcessing = false; - } - } - @override bool get wantKeepAlive => true; @override void initState() { super.initState(); - pgcIntroController = Get.put(PgcIntroController(), tag: widget.heroTag); + introController = Get.put(PgcIntroController(), tag: widget.heroTag); videoDetailCtr = Get.find(tag: widget.heroTag); } @@ -70,7 +61,7 @@ class _PgcIntroPageState extends State Widget build(BuildContext context) { super.build(context); final ThemeData theme = Theme.of(context); - final item = pgcIntroController.pgcItem; + final item = introController.pgcItem; final isLandscape = context.isLandscape; Widget sliver = SliverToBoxAdapter( child: Column( @@ -86,22 +77,21 @@ class _PgcIntroPageState extends State ), const SizedBox(height: 6), // 点赞收藏转发 布局样式2 - if (pgcIntroController.isPgc) - actionGrid(theme, item, pgcIntroController), + if (introController.isPgc) actionGrid(theme, item, introController), // 番剧分集 if (item.episodes?.isNotEmpty == true) PgcPanel( heroTag: widget.heroTag, pages: item.episodes!, cid: videoDetailCtr.cid.value, - onChangeEpisode: pgcIntroController.onChangeEpisode, + onChangeEpisode: introController.onChangeEpisode, showEpisodes: widget.showEpisodes, newEp: item.newEp, ), ], ), ); - if (!pgcIntroController.isPgc) { + if (!introController.isPgc) { sliver = SliverMainAxisGroup( slivers: [ sliver, @@ -181,18 +171,18 @@ class _PgcIntroPageState extends State bottom: 6, left: null, ), - if (!pgcIntroController.isPgc) + if (!introController.isPgc) Positioned( right: 6, bottom: 6, child: Obx(() { - final isFav = pgcIntroController.isFav.value; + final isFav = introController.isFav.value; return iconButton( context: context, size: 28, iconSize: 26, tooltip: '${isFav ? '取消' : ''}收藏', - onPressed: () => pgcIntroController.onFavPugv(isFav), + onPressed: () => introController.onFavPugv(isFav), icon: isFav ? Icons.star_rounded : Icons.star_border_rounded, bgColor: isFav ? null : theme.colorScheme.onInverseSurface, iconColor: isFav ? null : theme.colorScheme.onSurfaceVariant, @@ -204,11 +194,11 @@ class _PgcIntroPageState extends State } Widget _buildInfoPanel(bool isLandscape, ThemeData theme, PgcInfoModel item) { - if (pgcIntroController.isPgc) { + if (introController.isPgc) { Widget subBtn() => Obx( () { - final isFollowed = pgcIntroController.isFollowed.value; - final followStatus = pgcIntroController.followStatus.value; + final isFollowed = introController.isFollowed.value; + final followStatus = introController.followStatus.value; return FilledButton.tonal( style: FilledButton.styleFrom( tapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -228,26 +218,26 @@ class _PgcIntroPageState extends State if (isFollowed) { showPgcFollowDialog( context: context, - type: pgcIntroController.pgcType, + type: introController.pgcType, followStatus: followStatus, onUpdateStatus: (followStatus) { if (followStatus == -1) { - pgcIntroController.pgcDel(); + introController.pgcDel(); } else { - pgcIntroController.pgcUpdate( + introController.pgcUpdate( followStatus, ); } }, ); } else { - pgcIntroController.pgcAdd(); + introController.pgcAdd(); } }, child: Text( isFollowed - ? '已${pgcIntroController.pgcType}' - : pgcIntroController.pgcType, + ? '已${introController.pgcType}' + : introController.pgcType, ), ); }, @@ -309,7 +299,7 @@ class _PgcIntroPageState extends State return GestureDetector( onTap: () => widget.showIntroDetail( item, - pgcIntroController.videoTags.value, + introController.videoTags.value, ), behavior: HitTestBehavior.opaque, child: SizedBox( @@ -413,7 +403,7 @@ class _PgcIntroPageState extends State Widget actionGrid( ThemeData theme, PgcInfoModel item, - PgcIntroController pgcIntroController, + PgcIntroController introController, ) { return SizedBox( height: 48, @@ -423,9 +413,8 @@ class _PgcIntroPageState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), - onTap: () => handleState(pgcIntroController.actionLikeVideo), - onLongPress: () => handleState(pgcIntroController.actionTriple), - selectStatus: pgcIntroController.hasLike.value, + onTap: () => handleAction(introController.actionLikeVideo), + selectStatus: introController.hasLike.value, semanticsLabel: '点赞', text: NumUtil.numFormat(item.stat!.like), controller: animController, @@ -438,8 +427,8 @@ class _PgcIntroPageState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b), - onTap: () => handleState(pgcIntroController.actionCoinVideo), - selectStatus: pgcIntroController.hasCoin, + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, semanticsLabel: '投币', text: NumUtil.numFormat(item.stat!.coin), controller: animController, @@ -450,12 +439,12 @@ class _PgcIntroPageState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => pgcIntroController.showFavBottomSheet(context), - onLongPress: () => pgcIntroController.showFavBottomSheet( + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( context, isLongPress: true, ), - selectStatus: pgcIntroController.hasFav.value, + selectStatus: introController.hasFav.value, semanticsLabel: '收藏', text: NumUtil.numFormat(item.stat!.favorite), controller: animController, @@ -466,15 +455,15 @@ class _PgcIntroPageState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.clock), selectIcon: const Icon(FontAwesomeIcons.solidClock), - onTap: () => handleState(pgcIntroController.viewLater), - selectStatus: pgcIntroController.hasLater.value, + onTap: () => handleAction(introController.viewLater), + selectStatus: introController.hasLater.value, semanticsLabel: '再看', text: '再看', ), ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), - onTap: () => pgcIntroController.actionShareVideo(context), + onTap: () => introController.actionShareVideo(context), selectStatus: false, semanticsLabel: '转发', text: NumUtil.numFormat(item.stat!.share), @@ -483,16 +472,4 @@ class _PgcIntroPageState extends State ), ); } - - @override - bool get hasTriple => - pgcIntroController.hasLike.value && - pgcIntroController.hasCoin && - pgcIntroController.hasFav.value; - - @override - void onLike() => handleState(pgcIntroController.actionLikeVideo); - - @override - void onTriple() => handleState(pgcIntroController.actionTriple); } diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index 2c43706f..21fc55db 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; @@ -57,16 +55,15 @@ class _UgcIntroPanelState extends State AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin, TripleAnimMixin { - late UgcIntroController ugcIntroController; + @override + late UgcIntroController introController; late final VideoDetailController videoDetailCtr = Get.find(tag: widget.heroTag); - bool isProcessing = false; - @override void initState() { super.initState(); - ugcIntroController = Get.put(UgcIntroController(), tag: widget.heroTag); + introController = Get.put(UgcIntroController(), tag: widget.heroTag); } @override @@ -95,8 +92,7 @@ class _UgcIntroPanelState extends State ), sliver: Obx( () { - VideoDetailData videoDetail = - ugcIntroController.videoDetail.value; + VideoDetailData videoDetail = introController.videoDetail.value; bool isLoading = videoDetail.bvid == null; int? mid = videoDetail.owner?.mid; return SliverToBoxAdapter( @@ -107,7 +103,7 @@ class _UgcIntroPanelState extends State return; } feedBack(); - ugcIntroController.expandableCtr.toggle(); + introController.expandableCtr.toggle(); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -127,7 +123,7 @@ class _UgcIntroPanelState extends State if (mid != null) { feedBack(); if (!isPortrait && - ugcIntroController + introController .horizontalMemberPage) { widget.onShowMemberPage(mid); } else { @@ -146,7 +142,7 @@ class _UgcIntroPanelState extends State child: SingleChildScrollView( scrollDirection: Axis.horizontal, physics: ReloadScrollPhysics( - controller: ugcIntroController, + controller: introController, ), child: Row( spacing: 25, @@ -170,7 +166,7 @@ class _UgcIntroPanelState extends State context, isLoading, videoDetail, - ugcIntroController, + introController, ), ), ], @@ -182,7 +178,7 @@ class _UgcIntroPanelState extends State _buildVideoTitle(theme, videoDetail) else ExpandablePanel( - controller: ugcIntroController.expandableCtr, + controller: introController.expandableCtr, collapsed: GestureDetector( onLongPress: () { Feedback.forLongPress(context); @@ -208,11 +204,11 @@ class _UgcIntroPanelState extends State clipBehavior: Clip.none, children: [ _buildInfo(theme, videoDetail), - if (ugcIntroController.enableAi) _aiBtn, + if (introController.enableAi) _aiBtn, ], ), if (videoDetail.argueInfo?.argueMsg?.isNotEmpty == true && - ugcIntroController.showArgueMsg) ...[ + introController.showArgueMsg) ...[ const SizedBox(height: 2), Text.rich( TextSpan( @@ -238,7 +234,7 @@ class _UgcIntroPanelState extends State ), ], ExpandablePanel( - controller: ugcIntroController.expandableCtr, + controller: introController.expandableCtr, collapsed: const SizedBox.shrink(), expanded: Column( mainAxisSize: MainAxisSize.min, @@ -270,8 +266,7 @@ class _UgcIntroPanelState extends State ), ], Obx(() { - final videoTags = - ugcIntroController.videoTags.value; + final videoTags = introController.videoTags.value; if (videoTags.isNullOrEmpty) { return const SizedBox.shrink(); } @@ -282,13 +277,13 @@ class _UgcIntroPanelState extends State theme: expandTheme, ), Obx( - () => ugcIntroController.status.value + () => introController.status.value ? const SizedBox.shrink() : Center( child: TextButton.icon( icon: const Icon(Icons.refresh), onPressed: () { - ugcIntroController + introController ..status.value = true ..queryVideoIntro(); if (videoDetailCtr.videoUrl.isNullOrEmpty && @@ -307,7 +302,7 @@ class _UgcIntroPanelState extends State context, isLoading, videoDetail, - ugcIntroController, + introController, ), ], // 合集 @@ -320,7 +315,7 @@ class _UgcIntroPanelState extends State SeasonPanel( heroTag: widget.heroTag, showEpisodes: widget.showEpisodes, - ugcIntroController: ugcIntroController, + ugcIntroController: introController, ), if (!isLoading && videoDetail.pages != null && @@ -331,8 +326,8 @@ class _UgcIntroPanelState extends State .horizontalSeasonPanel)) ...[ PagesPanel( heroTag: widget.heroTag, - ugcIntroController: ugcIntroController, - bvid: ugcIntroController.bvid, + ugcIntroController: introController, + bvid: introController.bvid, showEpisodes: widget.showEpisodes, ), ], @@ -474,20 +469,12 @@ class _UgcIntroPanelState extends State return child(); } - Future handleState(FutureOr Function() action) async { - if (!isProcessing) { - isProcessing = true; - await action(); - isProcessing = false; - } - } - Widget followButton(BuildContext context, ThemeData t) { return Obx( () { - int attr = ugcIntroController.followStatus['attribute'] ?? 0; + int attr = introController.followStatus['attribute'] ?? 0; return TextButton( - onPressed: () => ugcIntroController.actionRelationMod(context), + onPressed: () => introController.actionRelationMod(context), style: TextButton.styleFrom( tapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity(vertical: -2.8), @@ -518,7 +505,7 @@ class _UgcIntroPanelState extends State BuildContext context, bool isLoading, VideoDetailData videoDetail, - UgcIntroController ugcIntroController, + UgcIntroController introController, ) { return SizedBox( height: 48, @@ -528,9 +515,8 @@ class _UgcIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), - onTap: () => handleState(ugcIntroController.actionLikeVideo), - onLongPress: () => handleState(ugcIntroController.actionTriple), - selectStatus: ugcIntroController.hasLike.value, + onTap: () => handleAction(introController.actionLikeVideo), + selectStatus: introController.hasLike.value, semanticsLabel: '点赞', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.like) @@ -545,8 +531,8 @@ class _UgcIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsDown), selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), - onTap: () => handleState(ugcIntroController.actionDislikeVideo), - selectStatus: ugcIntroController.hasDislike.value, + onTap: () => handleAction(introController.actionDislikeVideo), + selectStatus: introController.hasDislike.value, semanticsLabel: '点踩', text: "点踩", ), @@ -555,8 +541,8 @@ class _UgcIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b), - onTap: () => handleState(ugcIntroController.actionCoinVideo), - selectStatus: ugcIntroController.hasCoin, + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, semanticsLabel: '投币', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.coin) @@ -569,12 +555,12 @@ class _UgcIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => ugcIntroController.showFavBottomSheet(context), - onLongPress: () => ugcIntroController.showFavBottomSheet( + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( context, isLongPress: true, ), - selectStatus: ugcIntroController.hasFav.value, + selectStatus: introController.hasFav.value, semanticsLabel: '收藏', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.favorite) @@ -587,15 +573,15 @@ class _UgcIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.clock), selectIcon: const Icon(FontAwesomeIcons.solidClock), - onTap: () => handleState(ugcIntroController.viewLater), - selectStatus: ugcIntroController.hasLater.value, + onTap: () => handleAction(introController.viewLater), + selectStatus: introController.hasLater.value, semanticsLabel: '再看', text: '再看', ), ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), - onTap: () => ugcIntroController.actionShareVideo(context), + onTap: () => introController.actionShareVideo(context), selectStatus: false, semanticsLabel: '分享', text: !isLoading @@ -706,7 +692,7 @@ class _UgcIntroPanelState extends State onTap: () { if (item.mid == ownerMid && !isPortrait && - ugcIntroController.horizontalMemberPage) { + introController.horizontalMemberPage) { widget.onShowMemberPage(ownerMid); } else { Get.toNamed( @@ -750,9 +736,8 @@ class _UgcIntroPanelState extends State right: -6, child: Obx( () => - ugcIntroController.staffRelations['status'] == true && - ugcIntroController.staffRelations['${item.mid}'] == - null + introController.staffRelations['status'] == true && + introController.staffRelations['${item.mid}'] == null ? Material( type: MaterialType.transparency, shape: const CircleBorder(), @@ -763,8 +748,7 @@ class _UgcIntroPanelState extends State mid: item.mid, isFollow: false, callback: (val) { - ugcIntroController - .staffRelations['${item.mid}'] = + introController.staffRelations['${item.mid}'] = true; }, ), @@ -825,7 +809,7 @@ class _UgcIntroPanelState extends State behavior: HitTestBehavior.opaque, child: Obx( () { - final userStat = ugcIntroController.userStat.value; + final userStat = introController.userStat.value; final isVip = (userStat.card?.vip?.status ?? 0) > 0; return Row( mainAxisSize: MainAxisSize.min, @@ -895,10 +879,10 @@ class _UgcIntroPanelState extends State color: theme.colorScheme.outline, semanticLabel: '无痕', ), - if (ugcIntroController.isShowOnlineTotal) + if (introController.isShowOnlineTotal) Obx( () => Text( - '${ugcIntroController.total.value}人在看', + '${introController.total.value}人在看', style: TextStyle( fontSize: 12, color: theme.colorScheme.outline, @@ -917,15 +901,15 @@ class _UgcIntroPanelState extends State label: 'AI总结', child: GestureDetector( onTap: () async { - if (ugcIntroController.aiConclusionResult == null) { - await ugcIntroController.aiConclusion(); + if (introController.aiConclusionResult == null) { + await introController.aiConclusion(); } - if (ugcIntroController.aiConclusionResult == null) { + if (introController.aiConclusionResult == null) { return; } - if (ugcIntroController.aiConclusionResult!.summary?.isNotEmpty == + if (introController.aiConclusionResult!.summary?.isNotEmpty == true || - ugcIntroController.aiConclusionResult!.outline?.isNotEmpty == + introController.aiConclusionResult!.outline?.isNotEmpty == true) { widget.showAiBottomSheet(); } else { @@ -968,16 +952,4 @@ class _UgcIntroPanelState extends State @override bool get wantKeepAlive => true; - - @override - bool get hasTriple => - ugcIntroController.hasLike.value && - ugcIntroController.hasCoin && - ugcIntroController.hasFav.value; - - @override - void onLike() => handleState(ugcIntroController.actionLikeVideo); - - @override - void onTriple() => handleState(ugcIntroController.actionTriple); } diff --git a/lib/pages/video/introduction/ugc/widgets/action_item.dart b/lib/pages/video/introduction/ugc/widgets/action_item.dart index f0c4bd9f..8159e73f 100644 --- a/lib/pages/video/introduction/ugc/widgets/action_item.dart +++ b/lib/pages/video/introduction/ugc/widgets/action_item.dart @@ -1,6 +1,7 @@ -import 'dart:async' show Timer; +import 'dart:async' show Timer, FutureOr; import 'dart:math' show pi; +import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show HapticFeedback; @@ -8,15 +9,26 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; mixin TripleAnimMixin on SingleTickerProviderStateMixin { + CommonIntroController get introController; late AnimationController animController; late Animation animation; late int _lastTime; Timer? _timer; - bool get hasTriple; - void onTriple(); - void onLike(); + bool get _hasTriple => + introController.hasLike.value && + introController.hasCoin && + introController.hasFav.value; + + bool isProcessing = false; + Future handleAction(FutureOr Function() action) async { + if (!isProcessing) { + isProcessing = true; + await action(); + isProcessing = false; + } + } @override void initState() { @@ -38,13 +50,13 @@ mixin TripleAnimMixin void onStartTriple() { _lastTime = DateTime.now().millisecondsSinceEpoch; _timer ??= Timer(const Duration(milliseconds: 200), () { - if (hasTriple) { - HapticFeedback.lightImpact(); + HapticFeedback.lightImpact(); + if (_hasTriple) { SmartDialog.showToast('已经完成三连'); } else { animController.forward().whenComplete(() { animController.reset(); - onTriple(); + handleAction(introController.actionTriple); }); } cancelTimer(); @@ -54,14 +66,14 @@ mixin TripleAnimMixin void onCancelTriple(bool isCancel) { int duration = DateTime.now().millisecondsSinceEpoch - _lastTime; if (duration >= 200 && duration < 1500) { - if (!hasTriple) { + if (!_hasTriple) { animController.reverse(); } } else if (duration < 200) { cancelTimer(); if (!isCancel) { feedBack(); - onLike(); + handleAction(introController.actionLikeVideo); } } } diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 756b160c..d20745cf 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -72,6 +72,7 @@ class HeaderControlState extends State String get heroTag => widget.heroTag; late final UgcIntroController ugcIntroController; late final PgcIntroController pgcIntroController; + @override late final CommonIntroController introController = videoDetailCtr.isUgc ? ugcIntroController : pgcIntroController; @@ -2235,7 +2236,8 @@ class HeaderControlState extends State selectIcon: const Icon( FontAwesomeIcons.solidThumbsUp, ), - onTap: introController.actionLikeVideo, + onTap: () => + handleAction(introController.actionLikeVideo), selectStatus: introController.hasLike.value, semanticsLabel: '点赞', controller: animController, @@ -2267,7 +2269,9 @@ class HeaderControlState extends State selectIcon: const Icon( FontAwesomeIcons.solidThumbsDown, ), - onTap: ugcIntroController.actionDislikeVideo, + onTap: () => handleAction( + ugcIntroController.actionDislikeVideo, + ), selectStatus: ugcIntroController.hasDislike.value, semanticsLabel: '点踩', ), @@ -2342,18 +2346,6 @@ class HeaderControlState extends State ? Obx(() => _buildHeader(true)) : _buildHeader(false); } - - @override - bool get hasTriple => - introController.hasLike.value && - introController.hasCoin && - introController.hasFav.value; - - @override - void onLike() => introController.actionLikeVideo(); - - @override - void onTriple() => introController.actionTriple(); } class MSliderTrackShape extends RoundedRectSliderTrackShape {