refa video action item

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-09 19:01:18 +08:00
parent 27c9c266c1
commit 85c72731f6
7 changed files with 252 additions and 329 deletions

View File

@@ -54,6 +54,11 @@ abstract class CommonIntroController extends GetxController {
bool prevPlay(); bool prevPlay();
bool nextPlay(); bool nextPlay();
void actionLikeVideo();
void actionCoinVideo();
void actionTriple();
void actionShareVideo(BuildContext context);
// 同时观看 // 同时观看
final bool isShowOnlineTotal = Pref.enableOnlineTotal; final bool isShowOnlineTotal = Pref.enableOnlineTotal;
late final RxString total = '1'.obs; late final RxString total = '1'.obs;

View File

@@ -98,6 +98,7 @@ class PgcIntroController extends CommonIntroController {
} }
// (取消)点赞 // (取消)点赞
@override
Future<void> actionLikeVideo() async { Future<void> actionLikeVideo() async {
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
@@ -115,6 +116,7 @@ class PgcIntroController extends CommonIntroController {
} }
// 投币 // 投币
@override
void actionCoinVideo() { void actionCoinVideo() {
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
@@ -138,6 +140,7 @@ class PgcIntroController extends CommonIntroController {
} }
// 分享视频 // 分享视频
@override
void actionShareVideo(BuildContext context) { void actionShareVideo(BuildContext context) {
showDialog( showDialog(
context: context, context: context,
@@ -408,7 +411,8 @@ class PgcIntroController extends CommonIntroController {
} }
// 一键三连 // 一键三连
Future<void> actionOneThree() async { @override
Future<void> actionTriple() async {
feedBack(); feedBack();
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');

View File

@@ -18,7 +18,6 @@ import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/utils/num_util.dart'; import 'package:PiliPlus/utils/num_util.dart';
import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback;
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -41,13 +40,13 @@ class PgcIntroPage extends StatefulWidget {
} }
class _PgcIntroPageState extends State<PgcIntroPage> class _PgcIntroPageState extends State<PgcIntroPage>
with AutomaticKeepAliveClientMixin { with
AutomaticKeepAliveClientMixin,
SingleTickerProviderStateMixin,
TripleAnimMixin {
late PgcIntroController pgcIntroController; late PgcIntroController pgcIntroController;
late VideoDetailController videoDetailCtr; late VideoDetailController videoDetailCtr;
late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>();
bool isProcessing = false; bool isProcessing = false;
Future<void> handleState(FutureOr Function() action) async { Future<void> handleState(FutureOr Function() action) async {
if (!isProcessing) { if (!isProcessing) {
@@ -65,6 +64,13 @@ class _PgcIntroPageState extends State<PgcIntroPage>
super.initState(); super.initState();
pgcIntroController = Get.put(PgcIntroController(), tag: widget.heroTag); pgcIntroController = Get.put(PgcIntroController(), tag: widget.heroTag);
videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag); videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag);
initTriple();
}
@override
void dispose() {
disposeTriple();
super.dispose();
} }
@override @override
@@ -425,42 +431,30 @@ class _PgcIntroPageState extends State<PgcIntroPage>
icon: const Icon(FontAwesomeIcons.thumbsUp), icon: const Icon(FontAwesomeIcons.thumbsUp),
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
onTap: () => handleState(pgcIntroController.actionLikeVideo), onTap: () => handleState(pgcIntroController.actionLikeVideo),
onLongPress: pgcIntroController.actionOneThree, onLongPress: () => handleState(pgcIntroController.actionTriple),
selectStatus: pgcIntroController.hasLike.value, selectStatus: pgcIntroController.hasLike.value,
semanticsLabel: '点赞', semanticsLabel: '点赞',
text: NumUtil.numFormat(item.stat!.like), text: NumUtil.numFormat(item.stat!.like),
needAnim: true, controller: animController,
hasTriple: animation: animation,
pgcIntroController.hasLike.value && onStartTriple: onStartTriple,
pgcIntroController.hasCoin && onCancelTriple: onCancelTriple,
pgcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
}
},
), ),
), ),
Obx( Obx(
() => ActionItem( () => ActionItem(
key: _coinKey,
icon: const Icon(FontAwesomeIcons.b), icon: const Icon(FontAwesomeIcons.b),
selectIcon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(pgcIntroController.actionCoinVideo), onTap: () => handleState(pgcIntroController.actionCoinVideo),
selectStatus: pgcIntroController.hasCoin, selectStatus: pgcIntroController.hasCoin,
semanticsLabel: '投币', semanticsLabel: '投币',
text: NumUtil.numFormat(item.stat!.coin), text: NumUtil.numFormat(item.stat!.coin),
needAnim: true, controller: animController,
animation: animation,
), ),
), ),
Obx( Obx(
() => ActionItem( () => ActionItem(
key: _favKey,
icon: const Icon(FontAwesomeIcons.star), icon: const Icon(FontAwesomeIcons.star),
selectIcon: const Icon(FontAwesomeIcons.solidStar), selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => pgcIntroController.showFavBottomSheet(context), onTap: () => pgcIntroController.showFavBottomSheet(context),
@@ -471,7 +465,8 @@ class _PgcIntroPageState extends State<PgcIntroPage>
selectStatus: pgcIntroController.hasFav.value, selectStatus: pgcIntroController.hasFav.value,
semanticsLabel: '收藏', semanticsLabel: '收藏',
text: NumUtil.numFormat(item.stat!.favorite), text: NumUtil.numFormat(item.stat!.favorite),
needAnim: true, controller: animController,
animation: animation,
), ),
), ),
Obx( Obx(
@@ -495,4 +490,16 @@ class _PgcIntroPageState extends State<PgcIntroPage>
), ),
); );
} }
@override
bool get hasTriple =>
pgcIntroController.hasLike.value &&
pgcIntroController.hasCoin &&
pgcIntroController.hasFav.value;
@override
void onLike() => handleState(pgcIntroController.actionLikeVideo);
@override
void onTriple() => handleState(pgcIntroController.actionTriple);
} }

View File

@@ -181,7 +181,8 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
} }
// 一键三连 // 一键三连
Future<void> actionOneThree() async { @override
Future<void> actionTriple() async {
feedBack(); feedBack();
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
@@ -217,6 +218,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
} }
// (取消)点赞 // (取消)点赞
@override
Future<void> actionLikeVideo() async { Future<void> actionLikeVideo() async {
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
@@ -266,7 +268,8 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
} }
// 投币 // 投币
Future<void> actionCoinVideo() async { @override
void actionCoinVideo() {
if (!accountService.isLogin.value) { if (!accountService.isLogin.value) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
return; return;
@@ -297,6 +300,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
StatDetail? getStat() => videoDetail.value.stat; StatDetail? getStat() => videoDetail.value.stat;
// 分享视频 // 分享视频
@override
void actionShareVideo(BuildContext context) { void actionShareVideo(BuildContext context) {
showDialog( showDialog(
context: context, context: context,

View File

@@ -30,7 +30,6 @@ import 'package:PiliPlus/utils/utils.dart';
import 'package:expandable/expandable.dart'; import 'package:expandable/expandable.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart' hide ContextExtensionss; import 'package:get/get.dart' hide ContextExtensionss;
@@ -54,20 +53,27 @@ class UgcIntroPanel extends StatefulWidget {
} }
class _UgcIntroPanelState extends State<UgcIntroPanel> class _UgcIntroPanelState extends State<UgcIntroPanel>
with AutomaticKeepAliveClientMixin { with
AutomaticKeepAliveClientMixin,
SingleTickerProviderStateMixin,
TripleAnimMixin {
late UgcIntroController ugcIntroController; late UgcIntroController ugcIntroController;
late final VideoDetailController videoDetailCtr = late final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: widget.heroTag); Get.find<VideoDetailController>(tag: widget.heroTag);
late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>();
bool isProcessing = false; bool isProcessing = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
ugcIntroController = Get.put(UgcIntroController(), tag: widget.heroTag); ugcIntroController = Get.put(UgcIntroController(), tag: widget.heroTag);
initTriple();
}
@override
void dispose() {
disposeTriple();
super.dispose();
} }
@override @override
@@ -530,27 +536,16 @@ class _UgcIntroPanelState extends State<UgcIntroPanel>
icon: const Icon(FontAwesomeIcons.thumbsUp), icon: const Icon(FontAwesomeIcons.thumbsUp),
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
onTap: () => handleState(ugcIntroController.actionLikeVideo), onTap: () => handleState(ugcIntroController.actionLikeVideo),
onLongPress: () => handleState(ugcIntroController.actionOneThree), onLongPress: () => handleState(ugcIntroController.actionTriple),
selectStatus: ugcIntroController.hasLike.value, selectStatus: ugcIntroController.hasLike.value,
semanticsLabel: '点赞', semanticsLabel: '点赞',
text: !isLoading text: !isLoading
? NumUtil.numFormat(videoDetail.stat!.like) ? NumUtil.numFormat(videoDetail.stat!.like)
: null, : null,
needAnim: true, controller: animController,
hasTriple: animation: animation,
ugcIntroController.hasLike.value && onStartTriple: onStartTriple,
ugcIntroController.hasCoin && onCancelTriple: onCancelTriple,
ugcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
}
},
), ),
), ),
Obx( Obx(
@@ -565,7 +560,6 @@ class _UgcIntroPanelState extends State<UgcIntroPanel>
), ),
Obx( Obx(
() => ActionItem( () => ActionItem(
key: _coinKey,
icon: const Icon(FontAwesomeIcons.b), icon: const Icon(FontAwesomeIcons.b),
selectIcon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(ugcIntroController.actionCoinVideo), onTap: () => handleState(ugcIntroController.actionCoinVideo),
@@ -574,12 +568,12 @@ class _UgcIntroPanelState extends State<UgcIntroPanel>
text: !isLoading text: !isLoading
? NumUtil.numFormat(videoDetail.stat!.coin) ? NumUtil.numFormat(videoDetail.stat!.coin)
: null, : null,
needAnim: true, controller: animController,
animation: animation,
), ),
), ),
Obx( Obx(
() => ActionItem( () => ActionItem(
key: _favKey,
icon: const Icon(FontAwesomeIcons.star), icon: const Icon(FontAwesomeIcons.star),
selectIcon: const Icon(FontAwesomeIcons.solidStar), selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => ugcIntroController.showFavBottomSheet(context), onTap: () => ugcIntroController.showFavBottomSheet(context),
@@ -592,7 +586,8 @@ class _UgcIntroPanelState extends State<UgcIntroPanel>
text: !isLoading text: !isLoading
? NumUtil.numFormat(videoDetail.stat!.favorite) ? NumUtil.numFormat(videoDetail.stat!.favorite)
: null, : null,
needAnim: true, controller: animController,
animation: animation,
), ),
), ),
Obx( Obx(
@@ -980,4 +975,16 @@ class _UgcIntroPanelState extends State<UgcIntroPanel>
@override @override
bool get wantKeepAlive => true; 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);
} }

View File

@@ -1,106 +1,65 @@
import 'dart:async'; import 'dart:async' show Timer;
import 'dart:math'; import 'dart:math' show pi;
import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/feed_back.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback; import 'package:flutter/services.dart' show HapticFeedback;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
class ActionItem extends StatefulWidget { mixin TripleAnimMixin<T extends StatefulWidget>
final Icon icon; on SingleTickerProviderStateMixin<T> {
final Icon? selectIcon; late AnimationController animController;
final VoidCallback? onTap; late Animation<double> animation;
final VoidCallback? onLongPress;
final String? text;
final bool selectStatus;
final String semanticsLabel;
final bool needAnim;
final bool hasTriple;
final ValueChanged<bool>? callBack;
final bool expand;
const ActionItem({
super.key,
required this.icon,
this.selectIcon,
this.onTap,
this.onLongPress,
this.text,
this.selectStatus = false,
this.needAnim = false,
this.hasTriple = false,
this.callBack,
required this.semanticsLabel,
this.expand = true,
});
@override
State<ActionItem> createState() => ActionItemState();
}
class ActionItemState extends State<ActionItem>
with SingleTickerProviderStateMixin {
AnimationController? controller;
Animation<double>? _animation;
late final _isThumbsUp = widget.semanticsLabel == '点赞';
late int _lastTime; late int _lastTime;
Timer? _timer; Timer? _timer;
void _startLongPress() { bool get hasTriple;
void onTriple();
void onLike();
void initTriple() {
animController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
reverseDuration: const Duration(milliseconds: 400),
);
animation = Tween<double>(begin: 0, end: -2 * pi).animate(
CurvedAnimation(
parent: animController,
curve: Curves.easeInOut,
),
);
}
void onStartTriple() {
_lastTime = DateTime.now().millisecondsSinceEpoch; _lastTime = DateTime.now().millisecondsSinceEpoch;
_timer ??= Timer(const Duration(milliseconds: 200), () { _timer ??= Timer(const Duration(milliseconds: 200), () {
if (widget.hasTriple) { if (hasTriple) {
HapticFeedback.lightImpact(); HapticFeedback.lightImpact();
SmartDialog.showToast('已经完成三连'); SmartDialog.showToast('已经完成三连');
} else { } else {
controller?.forward(); animController.forward().whenComplete(() {
widget.callBack?.call(true); animController.reset();
onTriple();
});
} }
cancelTimer(); cancelTimer();
}); });
} }
void _cancelLongPress([bool isCancel = false]) { void onCancelTriple(bool isCancel) {
int duration = DateTime.now().millisecondsSinceEpoch - _lastTime; int duration = DateTime.now().millisecondsSinceEpoch - _lastTime;
if (duration >= 200 && duration < 1500) { if (duration >= 200 && duration < 1500) {
if (!widget.hasTriple) { if (!hasTriple) {
controller?.reverse(); animController.reverse();
widget.callBack?.call(false);
} }
} else if (duration < 200) { } else if (duration < 200) {
cancelTimer(); cancelTimer();
if (!isCancel) { if (!isCancel) {
feedBack(); feedBack();
widget.onTap?.call(); onLike();
}
}
}
@override
void initState() {
super.initState();
if (widget.needAnim) {
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
reverseDuration: const Duration(milliseconds: 400),
)..addListener(listener);
_animation = Tween<double>(begin: 0, end: -2 * pi).animate(
CurvedAnimation(
parent: controller!,
curve: Curves.easeInOut,
),
);
}
}
void listener() {
if (controller!.value == 1) {
controller!.reset();
if (_isThumbsUp) {
widget.onLongPress?.call();
} }
} }
} }
@@ -110,13 +69,49 @@ class ActionItemState extends State<ActionItem>
_timer = null; _timer = null;
} }
@override void disposeTriple() {
void dispose() {
cancelTimer(); cancelTimer();
controller?.removeListener(listener); animController.dispose();
controller?.dispose();
super.dispose();
} }
}
class ActionItem extends StatefulWidget {
const ActionItem({
super.key,
required this.icon,
this.selectIcon,
this.onTap,
this.onLongPress,
this.text,
this.selectStatus = false,
required this.semanticsLabel,
this.expand = true,
this.controller,
this.animation,
this.onStartTriple,
this.onCancelTriple,
});
final Icon icon;
final Icon? selectIcon;
final VoidCallback? onTap;
final VoidCallback? onLongPress;
final String? text;
final bool selectStatus;
final String semanticsLabel;
final bool expand;
final AnimationController? controller;
final Animation<double>? animation;
final VoidCallback? onStartTriple;
final ValueChanged<bool>? onCancelTriple;
@override
State<ActionItem> createState() => ActionItemState();
}
class ActionItemState extends State<ActionItem>
with SingleTickerProviderStateMixin {
late final _isThumbsUp = widget.onStartTriple != null;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -155,9 +150,11 @@ class ActionItemState extends State<ActionItem>
widget.onTap?.call(); widget.onTap?.call();
}, },
onLongPress: _isThumbsUp ? null : widget.onLongPress, onLongPress: _isThumbsUp ? null : widget.onLongPress,
onTapDown: _isThumbsUp ? (details) => _startLongPress() : null, onTapDown: _isThumbsUp ? (details) => widget.onStartTriple!() : null,
onTapUp: _isThumbsUp ? (details) => _cancelLongPress() : null, onTapUp: _isThumbsUp
onTapCancel: _isThumbsUp ? () => _cancelLongPress(true) : null, ? (details) => widget.onCancelTriple!(false)
: null,
onTapCancel: _isThumbsUp ? () => widget.onCancelTriple!(true) : null,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@@ -165,14 +162,14 @@ class ActionItemState extends State<ActionItem>
clipBehavior: Clip.none, clipBehavior: Clip.none,
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
if (widget.needAnim) if (widget.animation != null)
AnimatedBuilder( AnimatedBuilder(
animation: _animation!, animation: widget.animation!,
builder: (context, child) => CustomPaint( builder: (context, child) => CustomPaint(
size: const Size(28, 28), size: const Size(28, 28),
painter: _ArcPainter( painter: _ArcPainter(
color: theme.colorScheme.primary, color: theme.colorScheme.primary,
sweepAngle: _animation!.value, sweepAngle: widget.animation!.value,
), ),
), ),
) )

View File

@@ -37,7 +37,6 @@ import 'package:dio/dio.dart';
import 'package:document_file_save_plus/document_file_save_plus_platform_interface.dart'; import 'package:document_file_save_plus/document_file_save_plus_platform_interface.dart';
import 'package:floating/floating.dart'; import 'package:floating/floating.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show HapticFeedback;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -63,7 +62,8 @@ class HeaderControl extends StatefulWidget {
State<HeaderControl> createState() => HeaderControlState(); State<HeaderControl> createState() => HeaderControlState();
} }
class HeaderControlState extends State<HeaderControl> { class HeaderControlState extends State<HeaderControl>
with SingleTickerProviderStateMixin, TripleAnimMixin {
late final PlPlayerController plPlayerController = widget.controller; late final PlPlayerController plPlayerController = widget.controller;
late final VideoDetailController videoDetailCtr = widget.videoDetailCtr; late final VideoDetailController videoDetailCtr = widget.videoDetailCtr;
late final PlayUrlModel videoInfo = videoDetailCtr.data; late final PlayUrlModel videoInfo = videoDetailCtr.data;
@@ -80,8 +80,6 @@ class HeaderControlState extends State<HeaderControl> {
Timer? clock; Timer? clock;
bool get isFullScreen => widget.controller.isFullScreen.value; bool get isFullScreen => widget.controller.isFullScreen.value;
Box setting = GStorage.setting; Box setting = GStorage.setting;
late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>();
@override @override
void initState() { void initState() {
@@ -91,11 +89,13 @@ class HeaderControlState extends State<HeaderControl> {
} else { } else {
pgcIntroController = Get.find<PgcIntroController>(tag: heroTag); pgcIntroController = Get.find<PgcIntroController>(tag: heroTag);
} }
initTriple();
} }
@override @override
void dispose() { void dispose() {
clock?.cancel(); clock?.cancel();
disposeTriple();
super.dispose(); super.dispose();
} }
@@ -2224,51 +2224,38 @@ class HeaderControlState extends State<HeaderControl> {
? Row( ? Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
if (videoDetailCtr.isUgc) ...[ SizedBox(
SizedBox( width: 42,
width: 42, height: 34,
height: 34, child: Obx(
child: Obx( () => ActionItem(
() => ActionItem( expand: false,
expand: false, icon: const Icon(
icon: const Icon( FontAwesomeIcons.thumbsUp,
FontAwesomeIcons.thumbsUp, color: Colors.white,
color: Colors.white,
),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsUp,
),
onTap: ugcIntroController.actionLikeVideo,
onLongPress: () {
ugcIntroController.actionOneThree();
plPlayerController
..isTriple = null
..hideTaskControls();
},
selectStatus: ugcIntroController.hasLike.value,
semanticsLabel: '点赞',
needAnim: true,
hasTriple:
ugcIntroController.hasLike.value &&
ugcIntroController.hasCoin &&
ugcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
plPlayerController.isTriple = true;
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
plPlayerController
..isTriple = null
..hideTaskControls();
}
},
), ),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsUp,
),
onTap: introController.actionLikeVideo,
selectStatus: introController.hasLike.value,
semanticsLabel: '点赞',
controller: animController,
animation: animation,
onStartTriple: () {
plPlayerController.isTriple = true;
onStartTriple();
},
onCancelTriple: (value) {
plPlayerController
..isTriple = null
..hideTaskControls();
onCancelTriple(value);
},
), ),
), ),
),
if (videoDetailCtr.isUgc)
SizedBox( SizedBox(
width: 42, width: 42,
height: 34, height: 34,
@@ -2288,162 +2275,62 @@ class HeaderControlState extends State<HeaderControl> {
), ),
), ),
), ),
SizedBox( SizedBox(
width: 42, width: 42,
height: 34, height: 34,
child: Obx( child: Obx(
() => ActionItem( () => ActionItem(
key: _coinKey,
expand: false,
icon: const Icon(
FontAwesomeIcons.b,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: ugcIntroController.actionCoinVideo,
selectStatus: ugcIntroController.hasCoin,
semanticsLabel: '投币',
needAnim: true,
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
key: _favKey,
expand: false,
icon: const Icon(
FontAwesomeIcons.star,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () =>
ugcIntroController.showFavBottomSheet(context),
onLongPress: () => ugcIntroController
.showFavBottomSheet(context, isLongPress: true),
selectStatus: ugcIntroController.hasFav.value,
semanticsLabel: '收藏',
needAnim: true,
),
),
),
SizedBox(
width: 42,
height: 34,
child: ActionItem(
expand: false, expand: false,
icon: const Icon( icon: const Icon(
FontAwesomeIcons.shareFromSquare, FontAwesomeIcons.b,
color: Colors.white, color: Colors.white,
), ),
onTap: () => selectIcon: const Icon(FontAwesomeIcons.b),
ugcIntroController.actionShareVideo(context), onTap: introController.actionCoinVideo,
semanticsLabel: '分享', selectStatus: introController.hasCoin,
semanticsLabel: '投币',
controller: animController,
animation: animation,
), ),
), ),
] else ...[ ),
SizedBox( SizedBox(
width: 42, width: 42,
height: 34, height: 34,
child: Obx( child: Obx(
() => ActionItem( () => ActionItem(
expand: false,
icon: const Icon(
FontAwesomeIcons.thumbsUp,
color: Colors.white,
),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsUp,
),
onTap: pgcIntroController.actionLikeVideo,
onLongPress: () {
pgcIntroController.actionOneThree();
plPlayerController
..isTriple = null
..hideTaskControls();
},
selectStatus: pgcIntroController.hasLike.value,
semanticsLabel: '点赞',
needAnim: true,
hasTriple:
pgcIntroController.hasLike.value &&
pgcIntroController.hasCoin &&
pgcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
plPlayerController.isTriple = true;
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
plPlayerController
..isTriple = null
..hideTaskControls();
}
},
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
key: _coinKey,
icon: const Icon(
FontAwesomeIcons.b,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: pgcIntroController.actionCoinVideo,
selectStatus: pgcIntroController.hasCoin,
semanticsLabel: '投币',
needAnim: true,
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
key: _favKey,
expand: false,
icon: const Icon(
FontAwesomeIcons.star,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () =>
pgcIntroController.showFavBottomSheet(context),
onLongPress: () => pgcIntroController
.showFavBottomSheet(context, isLongPress: true),
selectStatus: pgcIntroController.hasFav.value,
semanticsLabel: '收藏',
needAnim: true,
),
),
),
SizedBox(
width: 42,
height: 34,
child: ActionItem(
expand: false, expand: false,
icon: const Icon( icon: const Icon(
FontAwesomeIcons.shareFromSquare, FontAwesomeIcons.star,
color: Colors.white, color: Colors.white,
), ),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => onTap: () =>
pgcIntroController.actionShareVideo(context), introController.showFavBottomSheet(context),
semanticsLabel: '转发', onLongPress: () => introController.showFavBottomSheet(
context,
isLongPress: true,
),
selectStatus: introController.hasFav.value,
semanticsLabel: '收藏',
controller: animController,
animation: animation,
), ),
), ),
], ),
SizedBox(
width: 42,
height: 34,
child: ActionItem(
expand: false,
icon: const Icon(
FontAwesomeIcons.shareFromSquare,
color: Colors.white,
),
onTap: () => introController.actionShareVideo(context),
semanticsLabel: '分享',
),
),
], ],
) )
: const SizedBox.shrink(), : const SizedBox.shrink(),
@@ -2457,6 +2344,18 @@ class HeaderControlState extends State<HeaderControl> {
? Obx(() => _buildHeader(true)) ? Obx(() => _buildHeader(true))
: _buildHeader(false); : _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 { class MSliderTrackShape extends RoundedRectSliderTrackShape {