mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08:00
@@ -6,6 +6,7 @@ import 'dart:ui' as ui;
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/cropped_image.dart';
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/disabled_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/gesture/immediate_tap_gesture_recognizer.dart';
|
||||
import 'package:PiliPlus/common/widgets/gesture/mouse_interactive_viewer.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
@@ -414,34 +415,20 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
() {
|
||||
final list = videoDetailController.dmTrend.value?.dataOrNull;
|
||||
if (list != null && list.isNotEmpty) {
|
||||
final show = videoDetailController.showDmTrendChart.value;
|
||||
return ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '高能进度条',
|
||||
icon: videoDetailController.showDmTrendChart.value
|
||||
? const Icon(
|
||||
Icons.show_chart,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
)
|
||||
: const Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.show_chart,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
Icon(
|
||||
Icons.hide_source,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => videoDetailController.showDmTrendChart.value =
|
||||
!videoDetailController.showDmTrendChart.value,
|
||||
icon: DisabledIcon(
|
||||
disable: !show,
|
||||
child: const Icon(
|
||||
Icons.show_chart,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
onTap: () => videoDetailController.showDmTrendChart.value = !show,
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
@@ -450,64 +437,76 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
/// 超分辨率
|
||||
BottomControlType.superResolution => Obx(
|
||||
() => PopupMenuButton<SuperResolutionType>(
|
||||
tooltip: '超分辨率',
|
||||
requestFocus: false,
|
||||
initialValue: plPlayerController.superResolutionType.value,
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return SuperResolutionType.values
|
||||
.map(
|
||||
(type) => PopupMenuItem<SuperResolutionType>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
value: type,
|
||||
onTap: () => plPlayerController.setShader(type),
|
||||
child: Text(
|
||||
type.title,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
() {
|
||||
final type = plPlayerController.superResolutionType.value;
|
||||
return PopupMenuButton<SuperResolutionType>(
|
||||
tooltip: '超分辨率',
|
||||
requestFocus: false,
|
||||
initialValue: type,
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return SuperResolutionType.values
|
||||
.map(
|
||||
(type) => PopupMenuItem<SuperResolutionType>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
value: type,
|
||||
onTap: () => plPlayerController.setShader(type),
|
||||
child: Text(
|
||||
type.title,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
plPlayerController.superResolutionType.value.title,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
type.title,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
/// 分段信息
|
||||
BottomControlType.viewPoints => Obx(
|
||||
() => videoDetailController.viewPointList.isEmpty
|
||||
? const SizedBox.shrink()
|
||||
: ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '分段信息',
|
||||
icon: Transform.rotate(
|
||||
() {
|
||||
if (videoDetailController.viewPointList.isNotEmpty) {
|
||||
final show = videoDetailController.showVP.value;
|
||||
return ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '分段信息',
|
||||
icon: DisabledIcon(
|
||||
iconSize: 22,
|
||||
disable: !show,
|
||||
child: Transform.rotate(
|
||||
angle: math.pi / 2,
|
||||
child: const Icon(
|
||||
MdiIcons.viewHeadline,
|
||||
Icons.reorder,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
onTap: widget.showViewPoints,
|
||||
onLongPress: () {
|
||||
Feedback.forLongPress(context);
|
||||
videoDetailController.showVP.value =
|
||||
!videoDetailController.showVP.value;
|
||||
},
|
||||
onSecondaryTap: PlatformUtils.isMobile
|
||||
? null
|
||||
: () => videoDetailController.showVP.value =
|
||||
!videoDetailController.showVP.value,
|
||||
),
|
||||
onTap: widget.showViewPoints,
|
||||
onLongPress: () {
|
||||
Feedback.forLongPress(context);
|
||||
videoDetailController.showVP.value = !show;
|
||||
},
|
||||
onSecondaryTap: PlatformUtils.isMobile
|
||||
? null
|
||||
: () => videoDetailController.showVP.value = !show,
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
|
||||
/// 选集
|
||||
@@ -567,35 +566,41 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
/// 画面比例
|
||||
BottomControlType.fit => Obx(
|
||||
() => PopupMenuButton<VideoFitType>(
|
||||
tooltip: '画面比例',
|
||||
requestFocus: false,
|
||||
initialValue: plPlayerController.videoFit.value,
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return VideoFitType.values
|
||||
.map(
|
||||
(boxFit) => PopupMenuItem<VideoFitType>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
value: boxFit,
|
||||
onTap: () => plPlayerController.toggleVideoFit(boxFit),
|
||||
child: Text(
|
||||
boxFit.desc,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
() {
|
||||
final fit = plPlayerController.videoFit.value;
|
||||
return PopupMenuButton<VideoFitType>(
|
||||
tooltip: '画面比例',
|
||||
requestFocus: false,
|
||||
initialValue: fit,
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return VideoFitType.values
|
||||
.map(
|
||||
(boxFit) => PopupMenuItem<VideoFitType>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
value: boxFit,
|
||||
onTap: () => plPlayerController.toggleVideoFit(boxFit),
|
||||
child: Text(
|
||||
boxFit.desc,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
plPlayerController.videoFit.value.desc,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
fit.desc,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
BottomControlType.aiTranslate => Obx(
|
||||
@@ -654,66 +659,65 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
/// 字幕
|
||||
BottomControlType.subtitle => Obx(
|
||||
() => videoDetailController.subtitles.isEmpty
|
||||
? const SizedBox.shrink()
|
||||
: PopupMenuButton<int>(
|
||||
tooltip: '字幕',
|
||||
requestFocus: false,
|
||||
initialValue: videoDetailController.vttSubtitlesIndex.value
|
||||
.clamp(
|
||||
0,
|
||||
videoDetailController.subtitles.length,
|
||||
() {
|
||||
if (videoDetailController.subtitles.isNotEmpty) {
|
||||
final val = videoDetailController.vttSubtitlesIndex.value;
|
||||
return PopupMenuButton<int>(
|
||||
tooltip: '字幕',
|
||||
requestFocus: false,
|
||||
initialValue: val,
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem<int>(
|
||||
value: 0,
|
||||
height: 35,
|
||||
onTap: () => videoDetailController.setSubtitle(0),
|
||||
child: const Text(
|
||||
"关闭字幕",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
color: Colors.black.withValues(alpha: 0.8),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem<int>(
|
||||
value: 0,
|
||||
),
|
||||
...videoDetailController.subtitles.indexed.map((e) {
|
||||
return PopupMenuItem<int>(
|
||||
value: e.$1 + 1,
|
||||
height: 35,
|
||||
onTap: () => videoDetailController.setSubtitle(0),
|
||||
child: const Text(
|
||||
"关闭字幕",
|
||||
style: TextStyle(
|
||||
onTap: () => videoDetailController.setSubtitle(e.$1 + 1),
|
||||
child: Text(
|
||||
"${e.$2.lanDoc}",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
),
|
||||
...videoDetailController.subtitles.indexed.map((e) {
|
||||
return PopupMenuItem<int>(
|
||||
value: e.$1 + 1,
|
||||
height: 35,
|
||||
onTap: () =>
|
||||
videoDetailController.setSubtitle(e.$1 + 1),
|
||||
child: Text(
|
||||
"${e.$2.lanDoc}",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
];
|
||||
},
|
||||
child: SizedBox(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
child: videoDetailController.vttSubtitlesIndex.value == 0
|
||||
? const Icon(
|
||||
Icons.closed_caption_off_outlined,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.closed_caption_off_rounded,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
];
|
||||
},
|
||||
child: SizedBox(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
child: val == 0
|
||||
? const Icon(
|
||||
Icons.closed_caption_off_outlined,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.closed_caption_off_rounded,
|
||||
size: 22,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
|
||||
/// 播放速度
|
||||
@@ -1701,15 +1705,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 255),
|
||||
);
|
||||
final anim =
|
||||
Matrix4Tween(
|
||||
begin: transformationController.value,
|
||||
end: Matrix4.identity(),
|
||||
).animate(
|
||||
CurveTween(
|
||||
curve: Curves.easeOut,
|
||||
).animate(animController),
|
||||
);
|
||||
final anim = animController.drive(
|
||||
Matrix4Tween(
|
||||
begin: transformationController.value,
|
||||
end: Matrix4.identity(),
|
||||
).chain(CurveTween(curve: Curves.easeOut)),
|
||||
);
|
||||
void listener() {
|
||||
transformationController.value = anim.value;
|
||||
}
|
||||
@@ -2748,17 +2749,20 @@ class _DanmakuTip extends SingleChildRenderObjectWidget {
|
||||
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) {
|
||||
return RenderDanmakuTip(offset: offset);
|
||||
return _RenderDanmakuTip(offset: offset);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderDanmakuTip renderObject) {
|
||||
void updateRenderObject(
|
||||
BuildContext context,
|
||||
_RenderDanmakuTip renderObject,
|
||||
) {
|
||||
renderObject.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
class RenderDanmakuTip extends RenderProxyBox {
|
||||
RenderDanmakuTip({
|
||||
class _RenderDanmakuTip extends RenderProxyBox {
|
||||
_RenderDanmakuTip({
|
||||
required double offset,
|
||||
}) : _offset = offset;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class AppBarAni extends StatelessWidget {
|
||||
final bool isFullScreen;
|
||||
|
||||
static final _topPos = Tween<Offset>(
|
||||
begin: const Offset(0, -1),
|
||||
begin: const Offset(0.0, -1.0),
|
||||
end: Offset.zero,
|
||||
);
|
||||
|
||||
@@ -49,8 +49,8 @@ class AppBarAni extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return SlideTransition(
|
||||
position: isTop
|
||||
? _topPos.animate(controller)
|
||||
: _bottomPos.animate(controller),
|
||||
? controller.drive(_topPos)
|
||||
: controller.drive(_bottomPos),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: isTop ? _topDecoration : _bottomDecoration,
|
||||
|
||||
Reference in New Issue
Block a user