mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-08 03:54:49 +08:00
@@ -43,6 +43,7 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
required this.thumbGlowColor,
|
||||
this.thumbGlowRadius = 30.0,
|
||||
this.thumbCanPaintOutsideBar = true,
|
||||
this.strokeCap = .round,
|
||||
});
|
||||
|
||||
/// The elapsed playing time of the media.
|
||||
@@ -170,6 +171,8 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
/// is happening during this time, though.
|
||||
final bool thumbCanPaintOutsideBar;
|
||||
|
||||
final StrokeCap strokeCap;
|
||||
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) {
|
||||
return RenderProgressBar(
|
||||
@@ -189,6 +192,7 @@ class ProgressBar extends LeafRenderObjectWidget {
|
||||
thumbGlowColor: thumbGlowColor,
|
||||
thumbGlowRadius: thumbGlowRadius,
|
||||
thumbCanPaintOutsideBar: thumbCanPaintOutsideBar,
|
||||
strokeCap: strokeCap,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -336,6 +340,7 @@ class RenderProgressBar extends RenderBox implements MouseTrackerAnnotation {
|
||||
required this._thumbGlowColor,
|
||||
double thumbGlowRadius = 30.0,
|
||||
this._thumbCanPaintOutsideBar = true,
|
||||
required this._strokeCap,
|
||||
}) : _onDragStartUserCallback = onDragStart,
|
||||
_onDragUpdateUserCallback = onDragUpdate,
|
||||
_onDragEndUserCallback = onDragEnd,
|
||||
@@ -363,6 +368,8 @@ class RenderProgressBar extends RenderBox implements MouseTrackerAnnotation {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
final StrokeCap _strokeCap;
|
||||
|
||||
// This is the gesture recognizer used to move the thumb.
|
||||
_EagerHorizontalDragGestureRecognizer? _drag;
|
||||
|
||||
@@ -690,7 +697,9 @@ class RenderProgressBar extends RenderBox implements MouseTrackerAnnotation {
|
||||
_drawBaseBar(canvas, localSize);
|
||||
_drawBufferedBar(canvas, localSize);
|
||||
_drawCurrentProgressBar(canvas, localSize);
|
||||
_drawThumb(canvas, localSize);
|
||||
if (thumbRadius > 0.0) {
|
||||
_drawThumb(canvas, localSize);
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@@ -729,7 +738,7 @@ class RenderProgressBar extends RenderBox implements MouseTrackerAnnotation {
|
||||
}) {
|
||||
final baseBarPaint = Paint()
|
||||
..color = color
|
||||
..strokeCap = .square
|
||||
..strokeCap = _strokeCap
|
||||
..strokeWidth = _barHeight;
|
||||
final capRadius = _barHeight / 2;
|
||||
final adjustedWidth = availableSize.width - barHeight;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:flutter/gestures.dart' show PointerDeviceKind;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -16,17 +18,26 @@ class CustomScrollBehavior extends MaterialScrollBehavior {
|
||||
BuildContext context,
|
||||
Widget child,
|
||||
ScrollableDetails details,
|
||||
) => child;
|
||||
) {
|
||||
if (Platform.isAndroid) {
|
||||
return StretchingOverscrollIndicator(
|
||||
axisDirection: details.direction,
|
||||
clipBehavior: details.decorationClipBehavior ?? .hardEdge,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<PointerDeviceKind> get dragDevices => desktopDragDevices;
|
||||
}
|
||||
|
||||
const Set<PointerDeviceKind> desktopDragDevices = <PointerDeviceKind>{
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.stylus,
|
||||
PointerDeviceKind.invertedStylus,
|
||||
PointerDeviceKind.trackpad,
|
||||
PointerDeviceKind.unknown,
|
||||
PointerDeviceKind.mouse,
|
||||
const Set<PointerDeviceKind> desktopDragDevices = {
|
||||
.touch,
|
||||
.stylus,
|
||||
.invertedStylus,
|
||||
.trackpad,
|
||||
.unknown,
|
||||
.mouse,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:PiliPlus/http/browser_ua.dart';
|
||||
import 'package:PiliPlus/http/constants.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/video.dart';
|
||||
import 'package:PiliPlus/models/common/account_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||
import 'package:PiliPlus/models/user/danmaku_rule.dart';
|
||||
import 'package:PiliPlus/models/video/play/url.dart';
|
||||
@@ -64,10 +63,10 @@ class PlPlayerController with BlockConfigMixin {
|
||||
// StreamSubscription? _playerEventSubs;
|
||||
|
||||
/// [playerStatus] has a [status] observable
|
||||
final playerStatus = PlPlayerStatus(PlayerStatus.playing);
|
||||
final playerStatus = PlPlayerStatus(.playing);
|
||||
|
||||
///
|
||||
final Rx<DataStatus> dataStatus = Rx(DataStatus.none);
|
||||
final Rx<DataStatus> dataStatus = Rx(.none);
|
||||
|
||||
// bool controlsEnabled = false;
|
||||
|
||||
@@ -124,7 +123,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
bool _isVertical = false;
|
||||
|
||||
/// 视频比例
|
||||
final Rx<VideoFitType> videoFit = Rx(VideoFitType.contain);
|
||||
final Rx<VideoFitType> videoFit = Rx(.contain);
|
||||
|
||||
/// 后台播放
|
||||
late final RxBool continuePlayInBackground =
|
||||
@@ -142,12 +141,12 @@ class PlPlayerController with BlockConfigMixin {
|
||||
int? _epid;
|
||||
int? _seasonId;
|
||||
int? _pgcType;
|
||||
VideoType _videoType = VideoType.ugc;
|
||||
VideoType _videoType = .ugc;
|
||||
int _heartDuration = 0;
|
||||
int? width;
|
||||
int? height;
|
||||
|
||||
late final tryLook = !Accounts.get(AccountType.video).isLogin;
|
||||
late final tryLook = !Accounts.get(.video).isLogin;
|
||||
|
||||
late DataSource dataSource;
|
||||
|
||||
@@ -208,7 +207,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
Future<void> exitDesktopPip() {
|
||||
isDesktopPip = false;
|
||||
return Future.wait([
|
||||
windowManager.setTitleBarStyle(TitleBarStyle.normal),
|
||||
windowManager.setTitleBarStyle(.normal),
|
||||
windowManager.setMinimumSize(const Size(400, 700)),
|
||||
windowManager.setBounds(_lastWindowBounds),
|
||||
setAlwaysOnTop(false),
|
||||
@@ -223,7 +222,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
_lastWindowBounds = await windowManager.getBounds();
|
||||
|
||||
windowManager.setTitleBarStyle(TitleBarStyle.hidden);
|
||||
windowManager.setTitleBarStyle(.hidden);
|
||||
|
||||
final Size size;
|
||||
final state = videoPlayerController!.state;
|
||||
@@ -338,11 +337,11 @@ class PlPlayerController with BlockConfigMixin {
|
||||
backgroundColor: null,
|
||||
foreground: Paint()
|
||||
..color = Colors.black
|
||||
..style = PaintingStyle.stroke
|
||||
..style = .stroke
|
||||
..strokeWidth = subtitleStrokeWidth,
|
||||
)
|
||||
: null,
|
||||
padding: EdgeInsets.only(
|
||||
padding: .only(
|
||||
left: subtitlePaddingH.toDouble(),
|
||||
right: subtitlePaddingH.toDouble(),
|
||||
bottom: subtitlePaddingB.toDouble(),
|
||||
@@ -536,7 +535,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
}) async {
|
||||
try {
|
||||
this.isLive = isLive;
|
||||
_videoType = videoType ?? VideoType.ugc;
|
||||
_videoType = videoType ?? .ugc;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.dataSource = dataSource;
|
||||
@@ -544,7 +543,7 @@ class PlPlayerController with BlockConfigMixin {
|
||||
// 初始化视频倍速
|
||||
// _playbackSpeed.value = speed;
|
||||
// 初始化数据加载状态
|
||||
dataStatus.value = DataStatus.loading;
|
||||
dataStatus.value = .loading;
|
||||
// 初始化全屏方向
|
||||
_isVertical = isVertical ?? false;
|
||||
_aid = aid;
|
||||
@@ -582,12 +581,12 @@ class PlPlayerController with BlockConfigMixin {
|
||||
updateSliderPositionSecond();
|
||||
updateBufferedSecond();
|
||||
// 数据加载完成
|
||||
dataStatus.value = DataStatus.loaded;
|
||||
dataStatus.value = .loaded;
|
||||
|
||||
await _initializePlayer();
|
||||
onInit?.call();
|
||||
} catch (err, stackTrace) {
|
||||
dataStatus.value = DataStatus.error;
|
||||
dataStatus.value = .error;
|
||||
if (kDebugMode) {
|
||||
debugPrint(stackTrace.toString());
|
||||
debugPrint('plPlayer err: $err');
|
||||
@@ -739,9 +738,9 @@ class PlPlayerController with BlockConfigMixin {
|
||||
stream.playing.listen((event) {
|
||||
WakelockPlus.toggle(enable: event);
|
||||
if (event) {
|
||||
playerStatus.value = PlayerStatus.playing;
|
||||
playerStatus.value = .playing;
|
||||
} else {
|
||||
playerStatus.value = PlayerStatus.paused;
|
||||
playerStatus.value = .paused;
|
||||
}
|
||||
videoPlayerServiceHandler?.onStatusChange(
|
||||
playerStatus.value,
|
||||
@@ -751,24 +750,24 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
/// 触发回调事件
|
||||
for (final element in _statusListeners) {
|
||||
element(event ? PlayerStatus.playing : PlayerStatus.paused);
|
||||
element(event ? .playing : .paused);
|
||||
}
|
||||
if (videoPlayerController!.state.position.inSeconds != 0) {
|
||||
makeHeartBeat(positionSeconds.value, type: HeartBeatType.status);
|
||||
makeHeartBeat(positionSeconds.value, type: .status);
|
||||
}
|
||||
}),
|
||||
stream.completed.listen((event) {
|
||||
if (event) {
|
||||
playerStatus.value = PlayerStatus.completed;
|
||||
playerStatus.value = .completed;
|
||||
|
||||
/// 触发回调事件
|
||||
for (final element in _statusListeners) {
|
||||
element(PlayerStatus.completed);
|
||||
element(.completed);
|
||||
}
|
||||
} else {
|
||||
// playerStatus.value = PlayerStatus.playing;
|
||||
// playerStatus.value = .playing;
|
||||
}
|
||||
makeHeartBeat(positionSeconds.value, type: HeartBeatType.completed);
|
||||
makeHeartBeat(positionSeconds.value, type: .completed);
|
||||
}),
|
||||
stream.position.listen((event) {
|
||||
position = event;
|
||||
@@ -916,14 +915,14 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
audioSessionHandler?.setActive(true);
|
||||
|
||||
playerStatus.value = PlayerStatus.playing;
|
||||
playerStatus.value = .playing;
|
||||
// screenManager.setOverlays(false);
|
||||
}
|
||||
|
||||
/// 暂停播放
|
||||
Future<void> pause({bool notify = true, bool isInterrupt = false}) async {
|
||||
await _videoPlayerController?.pause();
|
||||
playerStatus.value = PlayerStatus.paused;
|
||||
playerStatus.value = .paused;
|
||||
|
||||
// 主动暂停时让出音频焦点
|
||||
if (!isInterrupt) {
|
||||
@@ -1102,14 +1101,14 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
void doubleTapFuc(DoubleTapType type) {
|
||||
switch (type) {
|
||||
case DoubleTapType.left:
|
||||
case .left:
|
||||
// 双击左边区域 👈
|
||||
onDoubleTapSeekBackward();
|
||||
break;
|
||||
case DoubleTapType.center:
|
||||
case .center:
|
||||
onDoubleTapCenter();
|
||||
break;
|
||||
case DoubleTapType.right:
|
||||
case .right:
|
||||
// 双击右边区域 👈
|
||||
onDoubleTapSeekForward();
|
||||
break;
|
||||
@@ -1414,22 +1413,22 @@ class PlPlayerController with BlockConfigMixin {
|
||||
);
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
alignment: .centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
padding: const .only(right: 12),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: min(DeviceUtils.size.width / 3, 350),
|
||||
),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
border: .all(
|
||||
width: 5,
|
||||
color: ThemeUtils.theme.colorScheme.surface,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
padding: const .all(5),
|
||||
child: Image.memory(value),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -80,7 +80,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
this.showEpisodes,
|
||||
this.showViewPoints,
|
||||
this.fill = Colors.black,
|
||||
this.alignment = Alignment.center,
|
||||
this.alignment = .center,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -351,12 +351,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
BottomControlType bottomControl,
|
||||
) => switch (bottomControl) {
|
||||
/// 播放暂停
|
||||
BottomControlType.playOrPause => PlayOrPauseButton(
|
||||
.playOrPause => PlayOrPauseButton(
|
||||
plPlayerController: plPlayerController,
|
||||
),
|
||||
|
||||
/// 上一集
|
||||
BottomControlType.pre => ComBtn(
|
||||
.pre => ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '上一集',
|
||||
@@ -373,7 +373,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 下一集
|
||||
BottomControlType.next => ComBtn(
|
||||
.next => ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '下一集',
|
||||
@@ -390,7 +390,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 时间进度
|
||||
BottomControlType.time => Obx(
|
||||
.time => Obx(
|
||||
() => _VideoTime(
|
||||
position: DurationUtils.formatDuration(
|
||||
plPlayerController.positionSeconds.value,
|
||||
@@ -402,7 +402,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 分段信息
|
||||
BottomControlType.viewPoints => Obx(
|
||||
.viewPoints => Obx(
|
||||
() {
|
||||
if (videoDetailController.viewPointList.isNotEmpty) {
|
||||
final show = videoDetailController.showVP.value;
|
||||
@@ -435,7 +435,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 选集
|
||||
BottomControlType.episode => ComBtn(
|
||||
.episode => ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: '选集',
|
||||
@@ -490,7 +490,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 画面比例
|
||||
BottomControlType.fit => Obx(
|
||||
.fit => Obx(
|
||||
() {
|
||||
final fit = plPlayerController.videoFit.value;
|
||||
return PopupMenuButton<VideoFitType>(
|
||||
@@ -503,7 +503,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
.map(
|
||||
(boxFit) => PopupMenuItem<VideoFitType>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
padding: const .only(left: 30),
|
||||
value: boxFit,
|
||||
onTap: () => plPlayerController.toggleVideoFit(boxFit),
|
||||
child: Text(
|
||||
@@ -518,7 +518,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
padding: const .symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
fit.desc,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
@@ -528,7 +528,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
},
|
||||
),
|
||||
|
||||
BottomControlType.aiTranslate => Obx(
|
||||
.aiTranslate => Obx(
|
||||
() {
|
||||
final list = videoDetailController.languages.value;
|
||||
if (list != null && list.isNotEmpty) {
|
||||
@@ -545,10 +545,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
onTap: () => videoDetailController.setLanguage(''),
|
||||
child: const Text(
|
||||
"关闭翻译",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
),
|
||||
style: TextStyle(color: Colors.white, fontSize: 13),
|
||||
),
|
||||
),
|
||||
...list.map((e) {
|
||||
@@ -583,7 +580,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 字幕
|
||||
BottomControlType.subtitle => Obx(
|
||||
.subtitle => Obx(
|
||||
() {
|
||||
if (videoDetailController.subtitles.isNotEmpty) {
|
||||
final val = videoDetailController.vttSubtitlesIndex.value;
|
||||
@@ -614,7 +611,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: Text(
|
||||
"${e.$2.lanDoc}",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
overflow: .ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
@@ -646,7 +643,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 播放速度
|
||||
BottomControlType.speed => Obx(
|
||||
.speed => Obx(
|
||||
() => PopupMenuButton<double>(
|
||||
tooltip: '倍速',
|
||||
requestFocus: false,
|
||||
@@ -657,7 +654,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
.map(
|
||||
(double speed) => PopupMenuItem<double>(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 30),
|
||||
padding: const .only(left: 30),
|
||||
value: speed,
|
||||
onTap: () => plPlayerController.setPlaybackSpeed(speed),
|
||||
child: Text(
|
||||
@@ -670,7 +667,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
.toList();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
padding: const .symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
"${plPlayerController.playbackSpeed}X",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
@@ -680,7 +677,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
),
|
||||
|
||||
BottomControlType.qa => Obx(
|
||||
.qa => Obx(
|
||||
() {
|
||||
final VideoQuality? currentVideoQa =
|
||||
videoDetailController.currentVideoQa.value;
|
||||
@@ -717,7 +714,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
return PopupMenuItem<int>(
|
||||
enabled: enabled,
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(left: 15, right: 10),
|
||||
padding: const .only(left: 15, right: 10),
|
||||
value: item.quality,
|
||||
onTap: () async {
|
||||
if (currentVideoQa.code == item.quality) {
|
||||
@@ -754,7 +751,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
padding: const .symmetric(horizontal: 8),
|
||||
child: Text(
|
||||
currentVideoQa.shortDesc,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
@@ -765,7 +762,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 全屏
|
||||
BottomControlType.fullscreen => ComBtn(
|
||||
.fullscreen => ComBtn(
|
||||
width: widgetWidth,
|
||||
height: 30,
|
||||
tooltip: isFullScreen ? '退出全屏' : '全屏',
|
||||
@@ -792,25 +789,22 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
final isNotFileSource = !plPlayerController.isFileSource;
|
||||
|
||||
List<BottomControlType> userSpecifyItemLeft = [
|
||||
BottomControlType.playOrPause,
|
||||
BottomControlType.time,
|
||||
if (!isNotFileSource || anySeason) ...[
|
||||
BottomControlType.pre,
|
||||
BottomControlType.next,
|
||||
],
|
||||
.playOrPause,
|
||||
.time,
|
||||
if (!isNotFileSource || anySeason) ...[.pre, .next],
|
||||
];
|
||||
|
||||
final flag =
|
||||
isFullScreen || plPlayerController.isDesktopPip || maxWidth >= 500;
|
||||
List<BottomControlType> userSpecifyItemRight = [
|
||||
if (isNotFileSource) BottomControlType.viewPoints,
|
||||
if (isNotFileSource && anySeason) BottomControlType.episode,
|
||||
if (flag) BottomControlType.fit,
|
||||
if (isNotFileSource) BottomControlType.aiTranslate,
|
||||
BottomControlType.subtitle,
|
||||
BottomControlType.speed,
|
||||
if (isNotFileSource && flag) BottomControlType.qa,
|
||||
if (!plPlayerController.isDesktopPip) BottomControlType.fullscreen,
|
||||
if (isNotFileSource) .viewPoints,
|
||||
if (isNotFileSource && anySeason) .episode,
|
||||
if (flag) .fit,
|
||||
if (isNotFileSource) .aiTranslate,
|
||||
.subtitle,
|
||||
.speed,
|
||||
if (isNotFileSource && flag) .qa,
|
||||
if (!plPlayerController.isDesktopPip) .fullscreen,
|
||||
];
|
||||
return PlayerBar(
|
||||
children: [
|
||||
@@ -906,27 +900,20 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.hasToast = true;
|
||||
SmartDialog.showAttach(
|
||||
targetContext: context,
|
||||
alignment: Alignment.center,
|
||||
alignment: .center,
|
||||
animationTime: const Duration(milliseconds: 200),
|
||||
animationType: SmartAnimationType.fade,
|
||||
animationType: .fade,
|
||||
displayTime: const Duration(milliseconds: 1500),
|
||||
maskColor: Colors.transparent,
|
||||
builder: (context) => Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
padding: const .symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(6),
|
||||
),
|
||||
borderRadius: const .all(.circular(6)),
|
||||
color: colorScheme.secondaryContainer,
|
||||
),
|
||||
child: Text(
|
||||
'松开手指,取消进退',
|
||||
style: TextStyle(
|
||||
color: colorScheme.onSecondaryContainer,
|
||||
),
|
||||
style: TextStyle(color: colorScheme.onSecondaryContainer),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -1008,18 +995,18 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
final double sectionWidth = maxWidth / 4;
|
||||
DoubleTapType type;
|
||||
if (tapPosition < sectionWidth) {
|
||||
type = DoubleTapType.left;
|
||||
type = .left;
|
||||
} else if (tapPosition < sectionWidth * 3) {
|
||||
type = DoubleTapType.center;
|
||||
type = .center;
|
||||
} else {
|
||||
type = DoubleTapType.right;
|
||||
type = .right;
|
||||
}
|
||||
plPlayerController.doubleTapFuc(type);
|
||||
}
|
||||
|
||||
void _onTapUp(TapUpDetails details) {
|
||||
switch (details.kind) {
|
||||
case ui.PointerDeviceKind.mouse when PlatformUtils.isDesktop:
|
||||
case .mouse when PlatformUtils.isDesktop:
|
||||
plPlayerController.onDoubleTapCenter();
|
||||
default:
|
||||
plPlayerController.controls = !plPlayerController.showControls.value;
|
||||
@@ -1028,7 +1015,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
void _onDoubleTapDown(TapDownDetails details) {
|
||||
switch (details.kind) {
|
||||
case ui.PointerDeviceKind.mouse when PlatformUtils.isDesktop:
|
||||
case .mouse when PlatformUtils.isDesktop:
|
||||
plPlayerController.triggerFullScreen(status: !isFullScreen);
|
||||
default:
|
||||
onDoubleTapDownMobile(details);
|
||||
@@ -1201,7 +1188,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
final child = Stack(
|
||||
key: _playerKey,
|
||||
fit: .passthrough,
|
||||
children: <Widget>[
|
||||
children: [
|
||||
_videoWidget,
|
||||
|
||||
if (widget.danmuWidget case final danmaku?)
|
||||
@@ -1225,7 +1212,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
IgnorePointer(
|
||||
ignoring: true,
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
alignment: .topCenter,
|
||||
child: FractionalTranslation(
|
||||
translation: isFullScreen
|
||||
? const Offset(0.0, 1.2)
|
||||
@@ -1238,10 +1225,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
: 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
padding: const .all(6),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x88000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
borderRadius: .all(.circular(16)),
|
||||
),
|
||||
child: Obx(
|
||||
() => Text(
|
||||
@@ -1264,7 +1251,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
IgnorePointer(
|
||||
ignoring: true,
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
alignment: .topCenter,
|
||||
child: FractionalTranslation(
|
||||
translation: isFullScreen
|
||||
? const Offset(0.0, 1.2)
|
||||
@@ -1279,16 +1266,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x88000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(64)),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 8,
|
||||
borderRadius: .all(.circular(64)),
|
||||
),
|
||||
padding: const .symmetric(horizontal: 10, vertical: 8),
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: .min,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
Obx(() {
|
||||
return Text(
|
||||
@@ -1325,7 +1309,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
IgnorePointer(
|
||||
ignoring: true,
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
alignment: .center,
|
||||
child: Obx(
|
||||
() {
|
||||
final volume = plPlayerController.volume.value;
|
||||
@@ -1334,18 +1318,15 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
opacity: plPlayerController.volumeIndicator.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const .symmetric(horizontal: 8, vertical: 5),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x88000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(64)),
|
||||
borderRadius: .all(.circular(64)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
mainAxisSize: .min,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
Icon(
|
||||
volume == 0.0
|
||||
? Icons.volume_off
|
||||
@@ -1376,25 +1357,22 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
IgnorePointer(
|
||||
ignoring: true,
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
alignment: .center,
|
||||
child: Obx(
|
||||
() => AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: _brightnessIndicator.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const .symmetric(horizontal: 8, vertical: 5),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x88000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(64)),
|
||||
borderRadius: .all(.circular(64)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
mainAxisSize: .min,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
Icon(
|
||||
_brightnessValue.value < 1.0 / 3.0
|
||||
? Icons.brightness_low
|
||||
@@ -1427,7 +1405,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: ClipRect(
|
||||
child: RepaintBoundary(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment: .spaceBetween,
|
||||
children: [
|
||||
AppBarAni(
|
||||
isTop: true,
|
||||
@@ -1483,19 +1461,19 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
() =>
|
||||
showRestoreScaleBtn.value && plPlayerController.showControls.value
|
||||
? Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
alignment: .bottomCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 95),
|
||||
padding: const .only(bottom: 95),
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
tapTargetSize: .shrinkWrap,
|
||||
backgroundColor: colorScheme.secondaryContainer
|
||||
.withValues(alpha: 0.8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.all(15),
|
||||
padding: const .all(15),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(6),
|
||||
borderRadius: .all(
|
||||
.circular(6),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1531,7 +1509,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
/// 进度条 live模式下禁用
|
||||
if (!isLive)
|
||||
Positioned(
|
||||
bottom: -2.2,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Obx(
|
||||
@@ -1539,8 +1517,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
return Offstage(
|
||||
offstage: plPlayerController.showControls.value,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.bottomCenter,
|
||||
clipBehavior: .none,
|
||||
alignment: .bottomCenter,
|
||||
children: [
|
||||
Obx(() {
|
||||
final int value =
|
||||
@@ -1558,8 +1536,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
bufferedBarColor: bufferedBarColor,
|
||||
thumbColor: primary,
|
||||
thumbGlowColor: thumbGlowColor,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: 2.5,
|
||||
barHeight: 1.4,
|
||||
thumbRadius: 0,
|
||||
strokeCap: .square,
|
||||
);
|
||||
}),
|
||||
if (plPlayerController.enableBlock &&
|
||||
@@ -1606,7 +1585,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
ViewSafeArea(
|
||||
right: false,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
alignment: .centerLeft,
|
||||
child: FractionalTranslation(
|
||||
translation: const Offset(1, -0.4),
|
||||
child: Obx(
|
||||
@@ -1615,7 +1594,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x45000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
borderRadius: .all(.circular(8)),
|
||||
),
|
||||
child: Obx(() {
|
||||
final controlsLock =
|
||||
@@ -1649,7 +1628,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
left: false,
|
||||
child: Obx(
|
||||
() => Align(
|
||||
alignment: Alignment.centerRight,
|
||||
alignment: .centerRight,
|
||||
child: FractionalTranslation(
|
||||
translation: const Offset(-1, -0.4),
|
||||
child: Offstage(
|
||||
@@ -1657,7 +1636,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x45000000),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
borderRadius: .all(.circular(8)),
|
||||
),
|
||||
child: ComBtn(
|
||||
tooltip: '截图',
|
||||
@@ -1684,15 +1663,15 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: GestureDetector(
|
||||
onTap: plPlayerController.refreshPlayer,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
padding: const .all(20),
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
shape: .circle,
|
||||
gradient: RadialGradient(
|
||||
colors: [Colors.black26, Colors.transparent],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize: .min,
|
||||
children: [
|
||||
Image.asset(
|
||||
Assets.buffering,
|
||||
@@ -1749,10 +1728,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
builder: (context, value, child) =>
|
||||
Opacity(opacity: value, child: child),
|
||||
child: BackwardSeekIndicator(
|
||||
duration:
|
||||
plPlayerController.fastForBackwardDuration,
|
||||
@@ -1768,10 +1745,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
builder: (context, value, child) =>
|
||||
Opacity(opacity: value, child: child),
|
||||
child: ForwardSeekIndicator(
|
||||
duration:
|
||||
plPlayerController.fastForBackwardDuration,
|
||||
|
||||
@@ -217,10 +217,10 @@ class _VideoShotImageState extends State<VideoShotImage> {
|
||||
}
|
||||
}
|
||||
|
||||
late final _imgPaint = Paint()..filterQuality = FilterQuality.medium;
|
||||
late final _imgPaint = Paint()..filterQuality = .medium;
|
||||
late final _borderPaint = Paint()
|
||||
..color = Colors.white
|
||||
..style = PaintingStyle.stroke
|
||||
..style = .stroke
|
||||
..strokeWidth = 1.5;
|
||||
|
||||
@override
|
||||
|
||||
@@ -23,11 +23,11 @@ class AppBarAni extends StatelessWidget {
|
||||
static const _topDecoration = LinearGradient(
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
colors: <Color>[
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Color(0xBF000000),
|
||||
],
|
||||
tileMode: TileMode.mirror,
|
||||
tileMode: .mirror,
|
||||
);
|
||||
|
||||
static final _bottomPos = Tween<Offset>(
|
||||
@@ -38,11 +38,11 @@ class AppBarAni extends StatelessWidget {
|
||||
static const _bottomDecoration = LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: <Color>[
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Color(0xBF000000),
|
||||
],
|
||||
tileMode: TileMode.mirror,
|
||||
tileMode: .mirror,
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -49,7 +49,7 @@ class BackwardSeekIndicatorState extends State<BackwardSeekIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
type: .transparency,
|
||||
child: InkWell(
|
||||
splashColor: const Color(0x44767676),
|
||||
onTap: increment,
|
||||
@@ -60,15 +60,15 @@ class BackwardSeekIndicatorState extends State<BackwardSeekIndicator> {
|
||||
Color(0x88767676),
|
||||
Color(0x00767676),
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
begin: .centerLeft,
|
||||
end: .centerRight,
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
alignment: .center,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: .min,
|
||||
mainAxisAlignment: .center,
|
||||
crossAxisAlignment: .center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.fast_rewind,
|
||||
@@ -78,10 +78,7 @@ class BackwardSeekIndicatorState extends State<BackwardSeekIndicator> {
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'快退${duration.inSeconds}秒',
|
||||
style: const TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: const TextStyle(fontSize: 12.0, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -52,18 +52,18 @@ class BottomControl extends StatelessWidget {
|
||||
final bufferedBarColor = primary.withValues(alpha: 0.4);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 12),
|
||||
padding: const .fromLTRB(10, 0, 10, 12),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize: .min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 7),
|
||||
padding: const .fromLTRB(10, 0, 10, 7),
|
||||
child: Obx(
|
||||
() => Offstage(
|
||||
offstage: !controller.showControls.value,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.bottomCenter,
|
||||
clipBehavior: .none,
|
||||
alignment: .bottomCenter,
|
||||
children: [
|
||||
Obx(() {
|
||||
final int value = controller.sliderPositionSeconds.value;
|
||||
|
||||
@@ -29,7 +29,7 @@ class ComBtn extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onSecondaryTap: onSecondaryTap,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
behavior: .opaque,
|
||||
child: icon,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -49,7 +49,7 @@ class ForwardSeekIndicatorState extends State<ForwardSeekIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
type: .transparency,
|
||||
child: InkWell(
|
||||
splashColor: const Color(0x44767676),
|
||||
onTap: increment,
|
||||
@@ -60,14 +60,14 @@ class ForwardSeekIndicatorState extends State<ForwardSeekIndicator> {
|
||||
Color(0x00767676),
|
||||
Color(0x88767676),
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
begin: .centerLeft,
|
||||
end: .centerRight,
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
alignment: .center,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: .center,
|
||||
crossAxisAlignment: .center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.fast_forward,
|
||||
@@ -77,10 +77,7 @@ class ForwardSeekIndicatorState extends State<ForwardSeekIndicator> {
|
||||
const SizedBox(height: 8.0),
|
||||
Text(
|
||||
'快进${duration.inSeconds}秒',
|
||||
style: const TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
style: const TextStyle(fontSize: 12.0, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -53,7 +53,7 @@ class PlayOrPauseButtonState extends State<PlayOrPauseButton>
|
||||
width: 42,
|
||||
height: 34,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
behavior: .opaque,
|
||||
onTap: widget.plPlayerController.onDoubleTapCenter,
|
||||
child: Center(
|
||||
child: AnimatedIcon(
|
||||
|
||||
Reference in New Issue
Block a user