mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-27 22:10:14 +08:00
opt: video page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -129,7 +129,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
if (snapshot.hasData && snapshot.data['status']) {
|
if (snapshot.hasData && snapshot.data['status']) {
|
||||||
return PLVideoPlayer(
|
return PLVideoPlayer(
|
||||||
controller: plPlayerController,
|
plPlayerController: plPlayerController,
|
||||||
bottomControl: BottomControl(
|
bottomControl: BottomControl(
|
||||||
controller: plPlayerController,
|
controller: plPlayerController,
|
||||||
liveRoomCtr: _liveRoomController,
|
liveRoomCtr: _liveRoomController,
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ class _RecommendSettingState extends State<RecommendSetting> {
|
|||||||
children: [
|
children: [
|
||||||
const Text('使用|隔开,如:尝试|测试'),
|
const Text('使用|隔开,如:尝试|测试'),
|
||||||
TextField(
|
TextField(
|
||||||
|
autofocus: true,
|
||||||
controller: textController,
|
controller: textController,
|
||||||
textInputAction: TextInputAction.newline,
|
textInputAction: TextInputAction.newline,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
|
|||||||
@@ -892,7 +892,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
() => !videoDetailController.autoPlay.value
|
() => !videoDetailController.autoPlay.value
|
||||||
? const SizedBox()
|
? const SizedBox()
|
||||||
: PLVideoPlayer(
|
: PLVideoPlayer(
|
||||||
controller: plPlayerController!,
|
plPlayerController: plPlayerController!,
|
||||||
videoIntroController:
|
videoIntroController:
|
||||||
videoDetailController.videoType == SearchType.video
|
videoDetailController.videoType == SearchType.video
|
||||||
? videoIntroController
|
? videoIntroController
|
||||||
@@ -936,38 +936,73 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
primary: false,
|
primary: false,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
actions: videoDetailController.userInfo == null
|
// automaticallyImplyLeading: false,
|
||||||
? null
|
// title: Row(
|
||||||
: [
|
// children: [
|
||||||
PopupMenuButton<String>(
|
// SizedBox(
|
||||||
onSelected: (String type) async {
|
// width: 42,
|
||||||
switch (type) {
|
// height: 34,
|
||||||
case 'later':
|
// child: IconButton(
|
||||||
var res = await UserHttp.toViewLater(
|
// tooltip: '返回',
|
||||||
bvid: videoDetailController.bvid);
|
// icon: const Icon(
|
||||||
SmartDialog.showToast(res['msg']);
|
// FontAwesomeIcons.arrowLeft,
|
||||||
break;
|
// size: 15,
|
||||||
case 'report':
|
// color: Colors.white,
|
||||||
Get.toNamed('/webviewnew', parameters: {
|
// ),
|
||||||
'url':
|
// onPressed: Get.back,
|
||||||
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(videoDetailController.bvid)}&bvid=${videoDetailController.bvid}'
|
// ),
|
||||||
});
|
// ),
|
||||||
break;
|
// SizedBox(
|
||||||
}
|
// width: 42,
|
||||||
},
|
// height: 34,
|
||||||
itemBuilder: (BuildContext context) =>
|
// child: IconButton(
|
||||||
<PopupMenuEntry<String>>[
|
// tooltip: '返回主页',
|
||||||
const PopupMenuItem<String>(
|
// icon: const Icon(
|
||||||
value: 'later',
|
// FontAwesomeIcons.house,
|
||||||
child: Text('稍后再看'),
|
// size: 15,
|
||||||
),
|
// color: Colors.white,
|
||||||
const PopupMenuItem<String>(
|
// ),
|
||||||
value: 'report',
|
// onPressed: () {
|
||||||
child: Text('举报'),
|
// Get.until((route) => route.isFirst);
|
||||||
),
|
// },
|
||||||
],
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
|
// ),
|
||||||
|
actions: [
|
||||||
|
PopupMenuButton<String>(
|
||||||
|
onSelected: (String type) async {
|
||||||
|
switch (type) {
|
||||||
|
case 'later':
|
||||||
|
var res = await UserHttp.toViewLater(
|
||||||
|
bvid: videoDetailController.bvid);
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
break;
|
||||||
|
case 'report':
|
||||||
|
if (videoDetailController.userInfo == null) {
|
||||||
|
SmartDialog.showToast('账号未登录');
|
||||||
|
} else {
|
||||||
|
Get.toNamed('/webviewnew', parameters: {
|
||||||
|
'url':
|
||||||
|
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(videoDetailController.bvid)}&bvid=${videoDetailController.bvid}'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (BuildContext context) =>
|
||||||
|
<PopupMenuEntry<String>>[
|
||||||
|
const PopupMenuItem<String>(
|
||||||
|
value: 'later',
|
||||||
|
child: Text('稍后再看'),
|
||||||
|
),
|
||||||
|
const PopupMenuItem<String>(
|
||||||
|
value: 'report',
|
||||||
|
child: Text('举报'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
@@ -998,7 +1033,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
plPlayerController!.videoController == null
|
plPlayerController!.videoController == null
|
||||||
? nil
|
? nil
|
||||||
: PLVideoPlayer(
|
: PLVideoPlayer(
|
||||||
controller: plPlayerController!,
|
plPlayerController: plPlayerController!,
|
||||||
videoIntroController:
|
videoIntroController:
|
||||||
videoDetailController.videoType == SearchType.video
|
videoDetailController.videoType == SearchType.video
|
||||||
? videoIntroController
|
? videoIntroController
|
||||||
|
|||||||
@@ -132,7 +132,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: EdgeInsets.only(
|
||||||
|
left: 12,
|
||||||
|
top: 12,
|
||||||
|
right: 12,
|
||||||
|
bottom: 12 + MediaQuery.paddingOf(context).bottom,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -152,331 +157,367 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
child: ListView(
|
child: MediaQuery.removePadding(
|
||||||
children: [
|
context: context,
|
||||||
// ListTile(
|
removeBottom: true,
|
||||||
// onTap: () {},
|
child: ListView(
|
||||||
// dense: true,
|
children: [
|
||||||
// enabled: false,
|
// ListTile(
|
||||||
// leading:
|
// onTap: () {},
|
||||||
// const Icon(Icons.network_cell_outlined, size: 20),
|
// dense: true,
|
||||||
// title: Text('省流模式', style: titleStyle),
|
// enabled: false,
|
||||||
// subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle),
|
// leading:
|
||||||
// trailing: Transform.scale(
|
// const Icon(Icons.network_cell_outlined, size: 20),
|
||||||
// scale: 0.75,
|
// title: Text('省流模式', style: titleStyle),
|
||||||
// child: Switch(
|
// subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle),
|
||||||
// thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
|
// trailing: Transform.scale(
|
||||||
// (Set<WidgetState> states) {
|
// scale: 0.75,
|
||||||
// if (states.isNotEmpty &&
|
// child: Switch(
|
||||||
// states.first == WidgetState.selected) {
|
// thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
|
||||||
// return const Icon(Icons.done);
|
// (Set<WidgetState> states) {
|
||||||
// }
|
// if (states.isNotEmpty &&
|
||||||
// return null; // All other states will use the default thumbIcon.
|
// states.first == WidgetState.selected) {
|
||||||
// }),
|
// return const Icon(Icons.done);
|
||||||
// value: false,
|
// }
|
||||||
// onChanged: (value) => {},
|
// return null; // All other states will use the default thumbIcon.
|
||||||
// ),
|
// }),
|
||||||
// ),
|
// value: false,
|
||||||
// ),
|
// onChanged: (value) => {},
|
||||||
if (widget.videoDetailCtr?.userInfo != null)
|
// ),
|
||||||
ListTile(
|
// ),
|
||||||
onTap: () {
|
// ),
|
||||||
Get.back();
|
// if (widget.videoDetailCtr?.userInfo != null)
|
||||||
Get.toNamed('/webviewnew', parameters: {
|
ListTile(
|
||||||
'url':
|
dense: true,
|
||||||
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr!.bvid)}&bvid=${widget.videoDetailCtr!.bvid}'
|
onTap: () {
|
||||||
});
|
if (widget.videoDetailCtr?.userInfo == null) {
|
||||||
},
|
SmartDialog.showToast('账号未登录');
|
||||||
dense: true,
|
return;
|
||||||
leading: const Icon(Icons.error_outline, size: 20),
|
}
|
||||||
title: const Text('举报', style: titleStyle),
|
Get.back();
|
||||||
),
|
Get.toNamed('/webviewnew', parameters: {
|
||||||
ListTile(
|
'url':
|
||||||
onTap: () async {
|
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr!.bvid)}&bvid=${widget.videoDetailCtr!.bvid}'
|
||||||
Get.back();
|
});
|
||||||
final res = await UserHttp.toViewLater(
|
|
||||||
bvid: widget.videoDetailCtr!.bvid);
|
|
||||||
SmartDialog.showToast(res['msg']);
|
|
||||||
},
|
|
||||||
dense: true,
|
|
||||||
leading: const Icon(Icons.watch_later_outlined, size: 20),
|
|
||||||
title: const Text('添加至「稍后再看」', style: titleStyle),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
onTap: () => {Get.back(), scheduleExit()},
|
|
||||||
dense: true,
|
|
||||||
leading:
|
|
||||||
const Icon(Icons.hourglass_top_outlined, size: 20),
|
|
||||||
title: const Text('定时关闭', style: titleStyle),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
onTap: () =>
|
|
||||||
{Get.back(), widget.videoDetailCtr!.queryVideoUrl()},
|
|
||||||
dense: true,
|
|
||||||
leading: const Icon(Icons.refresh_outlined, size: 20),
|
|
||||||
title: const Text('重载视频', style: titleStyle),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title: const Text('CDN 设置', style: titleStyle),
|
|
||||||
leading: Icon(MdiIcons.cloudPlusOutline, size: 20),
|
|
||||||
subtitle: Text(
|
|
||||||
'当前:${CDNServiceCode.fromCode(defaultCDNService)!.description},无法播放请切换',
|
|
||||||
style: subTitleStyle,
|
|
||||||
),
|
|
||||||
onTap: () async {
|
|
||||||
Get.back();
|
|
||||||
String? result = await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return SelectDialog<String>(
|
|
||||||
title: 'CDN 设置',
|
|
||||||
value: defaultCDNService,
|
|
||||||
values: CDNService.values.map((e) {
|
|
||||||
return {
|
|
||||||
'title': e.description,
|
|
||||||
'value': e.code
|
|
||||||
};
|
|
||||||
}).toList());
|
|
||||||
},
|
},
|
||||||
);
|
leading: const Icon(Icons.error_outline, size: 20),
|
||||||
if (result != null) {
|
title: const Text('举报', style: titleStyle),
|
||||||
defaultCDNService = result;
|
),
|
||||||
setting.put(SettingBoxKey.CDNService, result);
|
ListTile(
|
||||||
SmartDialog.showToast(
|
dense: true,
|
||||||
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
|
onTap: () async {
|
||||||
setState(() {});
|
Get.back();
|
||||||
widget.videoDetailCtr!.queryVideoUrl();
|
final res = await UserHttp.toViewLater(
|
||||||
}
|
bvid: widget.videoDetailCtr!.bvid);
|
||||||
},
|
SmartDialog.showToast(res['msg']);
|
||||||
),
|
},
|
||||||
ListTile(
|
leading:
|
||||||
onTap: () {
|
const Icon(Icons.watch_later_outlined, size: 20),
|
||||||
Get.back();
|
title: const Text('添加至「稍后再看」', style: titleStyle),
|
||||||
Player? player =
|
),
|
||||||
widget.controller?.videoPlayerController;
|
ListTile(
|
||||||
if (player == null) {
|
dense: true,
|
||||||
SmartDialog.showToast('播放器未初始化');
|
onTap: () => {Get.back(), scheduleExit()},
|
||||||
return;
|
leading: const Icon(Icons.hourglass_top_outlined,
|
||||||
}
|
size: 20),
|
||||||
var pp = player.platform as NativePlayer;
|
title: const Text('定时关闭', style: titleStyle),
|
||||||
pp.setProperty("video", "no");
|
),
|
||||||
},
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
leading: const Icon(Icons.headphones_outlined, size: 20),
|
onTap: () => {
|
||||||
title: const Text('听视频(需返回首页才能终止该状态)', style: titleStyle),
|
Get.back(),
|
||||||
),
|
widget.videoDetailCtr!.queryVideoUrl()
|
||||||
ListTile(
|
},
|
||||||
onTap: () => {Get.back(), showSetVideoQa()},
|
leading: const Icon(Icons.refresh_outlined, size: 20),
|
||||||
dense: true,
|
title: const Text('重载视频', style: titleStyle),
|
||||||
leading: const Icon(Icons.play_circle_outline, size: 20),
|
),
|
||||||
title: const Text('选择画质', style: titleStyle),
|
ListTile(
|
||||||
subtitle: Text(
|
dense: true,
|
||||||
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
title: const Text('CDN 设置', style: titleStyle),
|
||||||
style: subTitleStyle),
|
leading: Icon(MdiIcons.cloudPlusOutline, size: 20),
|
||||||
),
|
subtitle: Text(
|
||||||
if (widget.videoDetailCtr!.currentAudioQa != null)
|
'当前:${CDNServiceCode.fromCode(defaultCDNService)!.description},无法播放请切换',
|
||||||
ListTile(
|
style: subTitleStyle,
|
||||||
onTap: () => {Get.back(), showSetAudioQa()},
|
),
|
||||||
dense: true,
|
onTap: () async {
|
||||||
leading: const Icon(Icons.album_outlined, size: 20),
|
Get.back();
|
||||||
title: const Text('选择音质', style: titleStyle),
|
String? result = await showDialog(
|
||||||
subtitle: Text(
|
context: context,
|
||||||
'当前音质 ${widget.videoDetailCtr!.currentAudioQa!.description}',
|
builder: (context) {
|
||||||
style: subTitleStyle),
|
return SelectDialog<String>(
|
||||||
),
|
title: 'CDN 设置',
|
||||||
ListTile(
|
value: defaultCDNService,
|
||||||
onTap: () => {Get.back(), showSetDecodeFormats()},
|
values: CDNService.values.map((e) {
|
||||||
dense: true,
|
return {
|
||||||
leading: const Icon(Icons.av_timer_outlined, size: 20),
|
'title': e.description,
|
||||||
title: const Text('解码格式', style: titleStyle),
|
'value': e.code
|
||||||
subtitle: Text(
|
};
|
||||||
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
}).toList());
|
||||||
style: subTitleStyle),
|
},
|
||||||
),
|
);
|
||||||
ListTile(
|
if (result != null) {
|
||||||
onTap: () => {Get.back(), showSetRepeat()},
|
defaultCDNService = result;
|
||||||
dense: true,
|
setting.put(SettingBoxKey.CDNService, result);
|
||||||
leading: const Icon(Icons.repeat, size: 20),
|
SmartDialog.showToast(
|
||||||
title: const Text('播放顺序', style: titleStyle),
|
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
|
||||||
subtitle: Text(widget.controller!.playRepeat.description,
|
setState(() {});
|
||||||
style: subTitleStyle),
|
widget.videoDetailCtr!.queryVideoUrl();
|
||||||
),
|
}
|
||||||
ListTile(
|
},
|
||||||
onTap: () => {Get.back(), showSetDanmaku()},
|
),
|
||||||
dense: true,
|
ListTile(
|
||||||
leading: const Icon(Icons.subtitles_outlined, size: 20),
|
dense: true,
|
||||||
title: const Text('弹幕设置', style: titleStyle),
|
onTap: () {
|
||||||
),
|
Get.back();
|
||||||
ListTile(
|
Player? player =
|
||||||
title: const Text('播放信息', style: titleStyle),
|
widget.controller?.videoPlayerController;
|
||||||
leading: const Icon(Icons.info_outline, size: 20),
|
if (player == null) {
|
||||||
onTap: () {
|
SmartDialog.showToast('播放器未初始化');
|
||||||
Player? player =
|
return;
|
||||||
widget.controller?.videoPlayerController;
|
}
|
||||||
if (player == null) {
|
var pp = player.platform as NativePlayer;
|
||||||
SmartDialog.showToast('播放器未初始化');
|
pp.setProperty("video", "no");
|
||||||
return;
|
},
|
||||||
}
|
leading:
|
||||||
showDialog(
|
const Icon(Icons.headphones_outlined, size: 20),
|
||||||
context: context,
|
title: const Text('听视频(需返回首页才能终止该状态)',
|
||||||
builder: (context) {
|
style: titleStyle),
|
||||||
return AlertDialog(
|
),
|
||||||
title: const Text('播放信息'),
|
ListTile(
|
||||||
content: SizedBox(
|
dense: true,
|
||||||
width: double.maxFinite,
|
onTap: () => {Get.back(), showSetVideoQa()},
|
||||||
child: ListView(
|
leading:
|
||||||
children: [
|
const Icon(Icons.play_circle_outline, size: 20),
|
||||||
ListTile(
|
title: const Text('选择画质', style: titleStyle),
|
||||||
title: const Text("Resolution"),
|
subtitle: Text(
|
||||||
subtitle: Text(
|
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
||||||
'${player.state.width}x${player.state.height}'),
|
style: subTitleStyle),
|
||||||
onTap: () {
|
),
|
||||||
Clipboard.setData(
|
if (widget.videoDetailCtr!.currentAudioQa != null)
|
||||||
ClipboardData(
|
ListTile(
|
||||||
text:
|
dense: true,
|
||||||
"Resolution\n${player.state.width}x${player.state.height}",
|
onTap: () => {Get.back(), showSetAudioQa()},
|
||||||
),
|
leading: const Icon(Icons.album_outlined, size: 20),
|
||||||
);
|
title: const Text('选择音质', style: titleStyle),
|
||||||
},
|
subtitle: Text(
|
||||||
),
|
'当前音质 ${widget.videoDetailCtr!.currentAudioQa!.description}',
|
||||||
ListTile(
|
style: subTitleStyle),
|
||||||
title: const Text("VideoParams"),
|
),
|
||||||
subtitle: Text(player.state.videoParams
|
ListTile(
|
||||||
.toString()),
|
dense: true,
|
||||||
onTap: () {
|
onTap: () => {Get.back(), showSetDecodeFormats()},
|
||||||
Clipboard.setData(
|
leading:
|
||||||
ClipboardData(
|
const Icon(Icons.av_timer_outlined, size: 20),
|
||||||
text:
|
title: const Text('解码格式', style: titleStyle),
|
||||||
"VideoParams\n${player.state.videoParams}",
|
subtitle: Text(
|
||||||
),
|
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
||||||
);
|
style: subTitleStyle),
|
||||||
},
|
),
|
||||||
),
|
ListTile(
|
||||||
ListTile(
|
dense: true,
|
||||||
title: const Text("AudioParams"),
|
onTap: () => {Get.back(), showSetRepeat()},
|
||||||
subtitle: Text(player.state.audioParams
|
leading: const Icon(Icons.repeat, size: 20),
|
||||||
.toString()),
|
title: const Text('播放顺序', style: titleStyle),
|
||||||
onTap: () {
|
subtitle: Text(
|
||||||
Clipboard.setData(
|
widget.controller!.playRepeat.description,
|
||||||
ClipboardData(
|
style: subTitleStyle),
|
||||||
text:
|
),
|
||||||
"AudioParams\n${player.state.audioParams}",
|
ListTile(
|
||||||
),
|
dense: true,
|
||||||
);
|
onTap: () => {Get.back(), showSetDanmaku()},
|
||||||
},
|
leading:
|
||||||
),
|
const Icon(Icons.subtitles_outlined, size: 20),
|
||||||
ListTile(
|
title: const Text('弹幕设置', style: titleStyle),
|
||||||
title: const Text("Media"),
|
),
|
||||||
subtitle: Text(
|
ListTile(
|
||||||
player.state.playlist.toString()),
|
dense: true,
|
||||||
onTap: () {
|
title: const Text('播放信息', style: titleStyle),
|
||||||
Clipboard.setData(
|
leading: const Icon(Icons.info_outline, size: 20),
|
||||||
ClipboardData(
|
onTap: () {
|
||||||
text:
|
Player? player =
|
||||||
"Media\n${player.state.playlist}",
|
widget.controller?.videoPlayerController;
|
||||||
),
|
if (player == null) {
|
||||||
);
|
SmartDialog.showToast('播放器未初始化');
|
||||||
},
|
return;
|
||||||
),
|
}
|
||||||
ListTile(
|
showDialog(
|
||||||
title: const Text("AudioTrack"),
|
context: context,
|
||||||
subtitle: Text(player.state.track.audio
|
builder: (context) {
|
||||||
.toString()),
|
return AlertDialog(
|
||||||
onTap: () {
|
title: const Text('播放信息'),
|
||||||
Clipboard.setData(
|
content: SizedBox(
|
||||||
ClipboardData(
|
width: double.maxFinite,
|
||||||
text:
|
child: ListView(
|
||||||
"AudioTrack\n${player.state.track.audio}",
|
children: [
|
||||||
),
|
ListTile(
|
||||||
);
|
dense: true,
|
||||||
},
|
title: const Text("Resolution"),
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title: const Text("VideoTrack"),
|
|
||||||
subtitle: Text(player.state.track.video
|
|
||||||
.toString()),
|
|
||||||
onTap: () {
|
|
||||||
Clipboard.setData(
|
|
||||||
ClipboardData(
|
|
||||||
text:
|
|
||||||
"VideoTrack\n${player.state.track.audio}",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
title: const Text("pitch"),
|
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
player.state.pitch.toString()),
|
'${player.state.width}x${player.state.height}'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Clipboard.setData(
|
Clipboard.setData(
|
||||||
ClipboardData(
|
ClipboardData(
|
||||||
text:
|
text:
|
||||||
"pitch\n${player.state.pitch}",
|
"Resolution\n${player.state.width}x${player.state.height}",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
ListTile(
|
),
|
||||||
title: const Text("rate"),
|
ListTile(
|
||||||
subtitle: Text(
|
dense: true,
|
||||||
player.state.rate.toString()),
|
title: const Text("VideoParams"),
|
||||||
|
subtitle: Text(player
|
||||||
|
.state.videoParams
|
||||||
|
.toString()),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Clipboard.setData(
|
Clipboard.setData(
|
||||||
ClipboardData(
|
ClipboardData(
|
||||||
text:
|
text:
|
||||||
"rate\n${player.state.rate}",
|
"VideoParams\n${player.state.videoParams}",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
ListTile(
|
),
|
||||||
title: const Text("AudioBitrate"),
|
ListTile(
|
||||||
subtitle: Text(player.state.audioBitrate
|
dense: true,
|
||||||
.toString()),
|
title: const Text("AudioParams"),
|
||||||
onTap: () {
|
subtitle: Text(player
|
||||||
Clipboard.setData(
|
.state.audioParams
|
||||||
ClipboardData(
|
.toString()),
|
||||||
text:
|
onTap: () {
|
||||||
"AudioBitrate\n${player.state.audioBitrate}",
|
Clipboard.setData(
|
||||||
),
|
ClipboardData(
|
||||||
);
|
text:
|
||||||
},
|
"AudioParams\n${player.state.audioParams}",
|
||||||
),
|
),
|
||||||
ListTile(
|
);
|
||||||
title: const Text("Volume"),
|
},
|
||||||
subtitle: Text(
|
),
|
||||||
player.state.volume.toString()),
|
ListTile(
|
||||||
onTap: () {
|
dense: true,
|
||||||
Clipboard.setData(
|
title: const Text("Media"),
|
||||||
ClipboardData(
|
subtitle: Text(
|
||||||
text:
|
player.state.playlist.toString()),
|
||||||
"Volume\n${player.state.volume}",
|
onTap: () {
|
||||||
),
|
Clipboard.setData(
|
||||||
);
|
ClipboardData(
|
||||||
},
|
text:
|
||||||
),
|
"Media\n${player.state.playlist}",
|
||||||
],
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
actions: [
|
),
|
||||||
TextButton(
|
ListTile(
|
||||||
onPressed: () => Get.back(),
|
dense: true,
|
||||||
child: Text(
|
title: const Text("AudioTrack"),
|
||||||
'确定',
|
subtitle: Text(player
|
||||||
style: TextStyle(
|
.state.track.audio
|
||||||
color: Theme.of(context)
|
.toString()),
|
||||||
.colorScheme
|
onTap: () {
|
||||||
.outline),
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"AudioTrack\n${player.state.track.audio}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text("VideoTrack"),
|
||||||
|
subtitle: Text(player
|
||||||
|
.state.track.video
|
||||||
|
.toString()),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"VideoTrack\n${player.state.track.audio}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text("pitch"),
|
||||||
|
subtitle: Text(
|
||||||
|
player.state.pitch.toString()),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"pitch\n${player.state.pitch}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text("rate"),
|
||||||
|
subtitle: Text(
|
||||||
|
player.state.rate.toString()),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"rate\n${player.state.rate}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text("AudioBitrate"),
|
||||||
|
subtitle: Text(player
|
||||||
|
.state.audioBitrate
|
||||||
|
.toString()),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"AudioBitrate\n${player.state.audioBitrate}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text("Volume"),
|
||||||
|
subtitle: Text(
|
||||||
|
player.state.volume.toString()),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text:
|
||||||
|
"Volume\n${player.state.volume}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
actions: [
|
||||||
);
|
TextButton(
|
||||||
},
|
onPressed: () => Get.back(),
|
||||||
);
|
child: Text(
|
||||||
})
|
'确定',
|
||||||
],
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.outline),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -524,6 +565,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
for (final int choice in scheduleTimeChoices) ...<Widget>[
|
for (final int choice in scheduleTimeChoices) ...<Widget>[
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
shutdownTimerService.scheduledExitInMinutes =
|
shutdownTimerService.scheduledExitInMinutes =
|
||||||
choice;
|
choice;
|
||||||
@@ -531,7 +573,6 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
contentPadding: const EdgeInsets.only(),
|
contentPadding: const EdgeInsets.only(),
|
||||||
dense: true,
|
|
||||||
title: Text(choice == -1 ? "禁用" : "$choice分钟后"),
|
title: Text(choice == -1 ? "禁用" : "$choice分钟后"),
|
||||||
trailing: shutdownTimerService
|
trailing: shutdownTimerService
|
||||||
.scheduledExitInMinutes ==
|
.scheduledExitInMinutes ==
|
||||||
@@ -551,12 +592,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
)),
|
)),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
shutdownTimerService.waitForPlayingCompleted =
|
shutdownTimerService.waitForPlayingCompleted =
|
||||||
!shutdownTimerService.waitForPlayingCompleted;
|
!shutdownTimerService.waitForPlayingCompleted;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
dense: true,
|
|
||||||
contentPadding: const EdgeInsets.only(),
|
contentPadding: const EdgeInsets.only(),
|
||||||
title: const Text("额外等待视频播放完毕", style: titleStyle),
|
title: const Text("额外等待视频播放完毕", style: titleStyle),
|
||||||
trailing: Switch(
|
trailing: Switch(
|
||||||
@@ -681,6 +722,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < totalQaSam; i++) ...[
|
for (int i = 0; i < totalQaSam; i++) ...[
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (currentVideoQa.code ==
|
if (currentVideoQa.code ==
|
||||||
videoFormat[i].quality) {
|
videoFormat[i].quality) {
|
||||||
@@ -701,7 +743,6 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr!.updatePlayer();
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
dense: true,
|
|
||||||
// 可能包含会员解锁画质
|
// 可能包含会员解锁画质
|
||||||
enabled: i >= totalQaSam - userfulQaSam,
|
enabled: i >= totalQaSam - userfulQaSam,
|
||||||
contentPadding:
|
contentPadding:
|
||||||
@@ -761,6 +802,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
for (final AudioItem i in audio) ...<Widget>[
|
for (final AudioItem i in audio) ...<Widget>[
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (currentAudioQa.code == i.id) {
|
if (currentAudioQa.code == i.id) {
|
||||||
return;
|
return;
|
||||||
@@ -779,7 +821,6 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr!.updatePlayer();
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
dense: true,
|
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.only(left: 20, right: 20),
|
const EdgeInsets.only(left: 20, right: 20),
|
||||||
title: Text(i.quality!),
|
title: Text(i.quality!),
|
||||||
@@ -847,6 +888,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
children: [
|
children: [
|
||||||
for (var i in list) ...[
|
for (var i in list) ...[
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (i.startsWith(currentDecodeFormats.code)) return;
|
if (i.startsWith(currentDecodeFormats.code)) return;
|
||||||
widget.videoDetailCtr!.currentDecodeFormats =
|
widget.videoDetailCtr!.currentDecodeFormats =
|
||||||
@@ -854,7 +896,6 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr!.updatePlayer();
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
dense: true,
|
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.only(left: 20, right: 20),
|
const EdgeInsets.only(left: 20, right: 20),
|
||||||
title: Text(VideoDecodeFormatsCode.fromString(i)!
|
title: Text(VideoDecodeFormatsCode.fromString(i)!
|
||||||
@@ -940,7 +981,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
left: 12,
|
left: 12,
|
||||||
top: 12,
|
top: 12,
|
||||||
right: 12,
|
right: 12,
|
||||||
bottom: widget.controller?.isFullScreen.value == true ? 70 : 12,
|
bottom:
|
||||||
|
(widget.controller?.isFullScreen.value == true ? 70 : 12) +
|
||||||
|
MediaQuery.paddingOf(context).bottom,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(left: 14, right: 14),
|
padding: const EdgeInsets.only(left: 14, right: 14),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -1427,11 +1470,11 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
for (final PlayRepeat i in PlayRepeat.values) ...[
|
for (final PlayRepeat i in PlayRepeat.values) ...[
|
||||||
ListTile(
|
ListTile(
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.controller!.setPlayRepeat(i);
|
widget.controller!.setPlayRepeat(i);
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
dense: true,
|
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.only(left: 20, right: 20),
|
const EdgeInsets.only(left: 20, right: 20),
|
||||||
title: Text(i.description),
|
title: Text(i.description),
|
||||||
@@ -1481,45 +1524,45 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
|
width: 42,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
tooltip: '返回',
|
||||||
|
icon: const Icon(
|
||||||
|
FontAwesomeIcons.arrowLeft,
|
||||||
|
size: 15,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
if (isFullScreen) {
|
||||||
|
widget.controller!.triggerFullScreen(status: false);
|
||||||
|
} else if (MediaQuery.of(context).orientation ==
|
||||||
|
Orientation.landscape &&
|
||||||
|
!horizontalScreen) {
|
||||||
|
verticalScreenForTwoSeconds();
|
||||||
|
} else {
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isFullScreen ||
|
||||||
|
MediaQuery.of(context).orientation != Orientation.portrait)
|
||||||
|
SizedBox(
|
||||||
width: 42,
|
width: 42,
|
||||||
height: 34,
|
height: 34,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
tooltip: '上一页',
|
tooltip: '返回主页',
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
FontAwesomeIcons.arrowLeft,
|
FontAwesomeIcons.house,
|
||||||
size: 15,
|
size: 15,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (isFullScreen) {
|
Get.until((route) => route.isFirst);
|
||||||
widget.controller!.triggerFullScreen(status: false);
|
|
||||||
} else if (MediaQuery.of(context).orientation ==
|
|
||||||
Orientation.landscape &&
|
|
||||||
!horizontalScreen) {
|
|
||||||
verticalScreenForTwoSeconds();
|
|
||||||
} else {
|
|
||||||
Get.back();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)),
|
),
|
||||||
if (!isFullScreen ||
|
),
|
||||||
MediaQuery.of(context).orientation != Orientation.portrait)
|
|
||||||
SizedBox(
|
|
||||||
width: 42,
|
|
||||||
height: 34,
|
|
||||||
child: IconButton(
|
|
||||||
tooltip: '返回主页',
|
|
||||||
icon: const Icon(
|
|
||||||
FontAwesomeIcons.house,
|
|
||||||
size: 15,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
// 销毁播放器实例
|
|
||||||
// await widget.controller!.dispose(type: 'all');
|
|
||||||
Get.until((route) => route.isFirst);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
if ((videoIntroController.videoDetail.value.title != null) &&
|
if ((videoIntroController.videoDetail.value.title != null) &&
|
||||||
(isFullScreen || equivalentFullScreen))
|
(isFullScreen || equivalentFullScreen))
|
||||||
Column(
|
Column(
|
||||||
@@ -1579,9 +1622,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(width: 15),
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
// ComBtn(
|
// ComBtn(
|
||||||
// icon: const Icon(
|
// icon: const Icon(
|
||||||
@@ -1780,7 +1821,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: () => showSettingSheet(),
|
onPressed: showSettingSheet,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.more_vert_outlined,
|
Icons.more_vert_outlined,
|
||||||
size: 19,
|
size: 19,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import 'widgets/play_pause_btn.dart';
|
|||||||
|
|
||||||
class PLVideoPlayer extends StatefulWidget {
|
class PLVideoPlayer extends StatefulWidget {
|
||||||
const PLVideoPlayer({
|
const PLVideoPlayer({
|
||||||
required this.controller,
|
required this.plPlayerController,
|
||||||
this.videoIntroController,
|
this.videoIntroController,
|
||||||
this.bangumiIntroController,
|
this.bangumiIntroController,
|
||||||
this.headerControl,
|
this.headerControl,
|
||||||
@@ -52,7 +52,7 @@ class PLVideoPlayer extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final PlPlayerController controller;
|
final PlPlayerController plPlayerController;
|
||||||
final VideoIntroController? videoIntroController;
|
final VideoIntroController? videoIntroController;
|
||||||
final BangumiIntroController? bangumiIntroController;
|
final BangumiIntroController? bangumiIntroController;
|
||||||
final PreferredSizeWidget? headerControl;
|
final PreferredSizeWidget? headerControl;
|
||||||
@@ -123,7 +123,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
// 双击播放、暂停
|
// 双击播放、暂停
|
||||||
void onDoubleTapCenter() {
|
void onDoubleTapCenter() {
|
||||||
final PlPlayerController plPlayerController = widget.controller;
|
|
||||||
plPlayerController.videoPlayerController!.playOrPause();
|
plPlayerController.videoPlayerController!.playOrPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,12 +151,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
super.initState();
|
super.initState();
|
||||||
animationController = AnimationController(
|
animationController = AnimationController(
|
||||||
vsync: this, duration: const Duration(milliseconds: 100));
|
vsync: this, duration: const Duration(milliseconds: 100));
|
||||||
videoController = widget.controller.videoController!;
|
videoController = plPlayerController.videoController!;
|
||||||
videoIntroController = widget.videoIntroController;
|
videoIntroController = widget.videoIntroController;
|
||||||
bangumiIntroController = widget.bangumiIntroController;
|
bangumiIntroController = widget.bangumiIntroController;
|
||||||
widget.controller.headerControl = widget.headerControl;
|
plPlayerController.headerControl = widget.headerControl;
|
||||||
widget.controller.bottomControl = widget.bottomControl;
|
plPlayerController.bottomControl = widget.bottomControl;
|
||||||
widget.controller.danmuWidget = widget.danmuWidget;
|
plPlayerController.danmuWidget = widget.danmuWidget;
|
||||||
defaultBtmProgressBehavior = setting.get(SettingBoxKey.btmProgressBehavior,
|
defaultBtmProgressBehavior = setting.get(SettingBoxKey.btmProgressBehavior,
|
||||||
defaultValue: BtmProgressBehavior.values.first.code);
|
defaultValue: BtmProgressBehavior.values.first.code);
|
||||||
enableQuickDouble =
|
enableQuickDouble =
|
||||||
@@ -218,7 +217,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
_brightnessIndicator.value = false;
|
_brightnessIndicator.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
widget.controller.brightness.value = value;
|
plPlayerController.brightness.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -230,7 +229,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
// 动态构建底部控制条
|
// 动态构建底部控制条
|
||||||
List<Widget> buildBottomControl() {
|
List<Widget> buildBottomControl() {
|
||||||
final PlPlayerController plPlayerController = widget.controller;
|
|
||||||
bool isSeason = videoIntroController?.videoDetail.value.ugcSeason != null;
|
bool isSeason = videoIntroController?.videoDetail.value.ugcSeason != null;
|
||||||
bool isPage = videoIntroController?.videoDetail.value.pages != null &&
|
bool isPage = videoIntroController?.videoDetail.value.pages != null &&
|
||||||
videoIntroController!.videoDetail.value.pages!.length > 1;
|
videoIntroController!.videoDetail.value.pages!.length > 1;
|
||||||
@@ -239,7 +237,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
Map<BottomControlType, Widget> videoProgressWidgets = {
|
Map<BottomControlType, Widget> videoProgressWidgets = {
|
||||||
/// 上一集
|
/// 上一集
|
||||||
BottomControlType.pre: Container(
|
BottomControlType.pre: Container(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: ComBtn(
|
child: ComBtn(
|
||||||
@@ -271,7 +269,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
/// 下一集
|
/// 下一集
|
||||||
BottomControlType.next: Container(
|
BottomControlType.next: Container(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: ComBtn(
|
child: ComBtn(
|
||||||
@@ -338,7 +336,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
() => plPlayerController.viewPointList.isEmpty
|
() => plPlayerController.viewPointList.isEmpty
|
||||||
? const SizedBox.shrink()
|
? const SizedBox.shrink()
|
||||||
: Container(
|
: Container(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: ComBtn(
|
child: ComBtn(
|
||||||
@@ -358,7 +356,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
/// 选集
|
/// 选集
|
||||||
BottomControlType.episode: Container(
|
BottomControlType.episode: Container(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: ComBtn(
|
child: ComBtn(
|
||||||
@@ -370,8 +368,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
),
|
),
|
||||||
fuc: () {
|
fuc: () {
|
||||||
int? index;
|
int? index;
|
||||||
int currentCid = widget.controller.cid;
|
int currentCid = plPlayerController.cid;
|
||||||
String bvid = widget.controller.bvid;
|
String bvid = plPlayerController.bvid;
|
||||||
List episodes = [];
|
List episodes = [];
|
||||||
// late Function changeFucCall;
|
// late Function changeFucCall;
|
||||||
if (isPage) {
|
if (isPage) {
|
||||||
@@ -385,7 +383,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
for (int i = 0; i < sections.length; i++) {
|
for (int i = 0; i < sections.length; i++) {
|
||||||
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
final List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
for (int j = 0; j < episodesList.length; j++) {
|
for (int j = 0; j < episodesList.length; j++) {
|
||||||
if (episodesList[j].cid == widget.controller.cid) {
|
if (episodesList[j].cid == plPlayerController.cid) {
|
||||||
index = i;
|
index = i;
|
||||||
episodes = episodesList;
|
episodes = episodesList;
|
||||||
break;
|
break;
|
||||||
@@ -413,7 +411,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
/// 画面比例
|
/// 画面比例
|
||||||
BottomControlType.fit: SizedBox(
|
BottomControlType.fit: SizedBox(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () => plPlayerController.toggleVideoFit(),
|
onPressed: () => plPlayerController.toggleVideoFit(),
|
||||||
@@ -434,7 +432,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
() => plPlayerController.vttSubtitles.isEmpty
|
() => plPlayerController.vttSubtitles.isEmpty
|
||||||
? const SizedBox.shrink()
|
? const SizedBox.shrink()
|
||||||
: SizedBox(
|
: SizedBox(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
child: PopupMenuButton<int>(
|
child: PopupMenuButton<int>(
|
||||||
onSelected: (int value) {
|
onSelected: (int value) {
|
||||||
@@ -475,9 +473,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
),
|
),
|
||||||
|
|
||||||
/// 播放速度
|
/// 播放速度
|
||||||
BottomControlType.speed: SizedBox(
|
BottomControlType.speed: Container(
|
||||||
width: 35,
|
|
||||||
height: 30,
|
height: 30,
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
alignment: Alignment.center,
|
||||||
child: PopupMenuButton<double>(
|
child: PopupMenuButton<double>(
|
||||||
onSelected: (double value) {
|
onSelected: (double value) {
|
||||||
plPlayerController.setPlaybackSpeed(value);
|
plPlayerController.setPlaybackSpeed(value);
|
||||||
@@ -498,33 +497,25 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Text("${plPlayerController.playbackSpeed}X",
|
||||||
width: 35,
|
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||||
height: 30,
|
semanticsLabel: "${plPlayerController.playbackSpeed}倍速"),
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Obx(() => Text("${plPlayerController.playbackSpeed}X",
|
|
||||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
|
||||||
semanticsLabel: "${plPlayerController.playbackSpeed}倍速")),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
/// 全屏
|
/// 全屏
|
||||||
BottomControlType.fullscreen: SizedBox(
|
BottomControlType.fullscreen: SizedBox(
|
||||||
width: 35,
|
width: isFullScreen ? 42 : 35,
|
||||||
height: 30,
|
height: 30,
|
||||||
child: Obx(() => ComBtn(
|
child: Obx(() => ComBtn(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
plPlayerController.isFullScreen.value
|
isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||||
? Icons.fullscreen_exit
|
semanticLabel: isFullScreen ? '退出全屏' : '全屏',
|
||||||
: Icons.fullscreen,
|
|
||||||
semanticLabel:
|
|
||||||
plPlayerController.isFullScreen.value ? '退出全屏' : '全屏',
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
fuc: () => plPlayerController.triggerFullScreen(
|
fuc: () =>
|
||||||
status: !plPlayerController.isFullScreen.value),
|
plPlayerController.triggerFullScreen(status: !isFullScreen),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@@ -538,7 +529,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
BottomControlType.space,
|
BottomControlType.space,
|
||||||
BottomControlType.viewPoints,
|
BottomControlType.viewPoints,
|
||||||
if (anySeason) BottomControlType.episode,
|
if (anySeason) BottomControlType.episode,
|
||||||
if (plPlayerController.isFullScreen.value) BottomControlType.fit,
|
if (isFullScreen) BottomControlType.fit,
|
||||||
BottomControlType.subtitle,
|
BottomControlType.subtitle,
|
||||||
BottomControlType.speed,
|
BottomControlType.speed,
|
||||||
BottomControlType.fullscreen,
|
BottomControlType.fullscreen,
|
||||||
@@ -558,12 +549,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlPlayerController get plPlayerController => widget.controller;
|
PlPlayerController get plPlayerController => widget.plPlayerController;
|
||||||
|
|
||||||
|
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
||||||
|
|
||||||
TextStyle get subTitleStyle => TextStyle(
|
TextStyle get subTitleStyle => TextStyle(
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
fontSize: 16 *
|
fontSize: 16 *
|
||||||
(plPlayerController.isFullScreen.value
|
(isFullScreen
|
||||||
? plPlayerController.subtitleFontScaleFS.value
|
? plPlayerController.subtitleFontScaleFS.value
|
||||||
: plPlayerController.subtitleFontScale.value),
|
: plPlayerController.subtitleFontScale.value),
|
||||||
letterSpacing: 0.1,
|
letterSpacing: 0.1,
|
||||||
@@ -585,7 +578,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (plPlayerController.isFullScreen.value) {
|
if (isFullScreen) {
|
||||||
plPlayerController.subtitleFontScaleFS.listen((value) {
|
plPlayerController.subtitleFontScaleFS.listen((value) {
|
||||||
_updateSubtitle(value);
|
_updateSubtitle(value);
|
||||||
});
|
});
|
||||||
@@ -701,15 +694,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
if (cumulativeDy > threshold) {
|
if (cumulativeDy > threshold) {
|
||||||
_gestureType = 'center_down';
|
_gestureType = 'center_down';
|
||||||
if (plPlayerController.isFullScreen.value ^
|
if (isFullScreen ^ fullScreenGestureReverse) {
|
||||||
fullScreenGestureReverse) {
|
|
||||||
fullScreenTrigger(fullScreenGestureReverse);
|
fullScreenTrigger(fullScreenGestureReverse);
|
||||||
}
|
}
|
||||||
// debugPrint('center_down:$cumulativeDy');
|
// debugPrint('center_down:$cumulativeDy');
|
||||||
} else if (cumulativeDy < -threshold) {
|
} else if (cumulativeDy < -threshold) {
|
||||||
_gestureType = 'center_up';
|
_gestureType = 'center_up';
|
||||||
if (!plPlayerController.isFullScreen.value ^
|
if (!isFullScreen ^ fullScreenGestureReverse) {
|
||||||
fullScreenGestureReverse) {
|
|
||||||
fullScreenTrigger(!fullScreenGestureReverse);
|
fullScreenTrigger(!fullScreenGestureReverse);
|
||||||
}
|
}
|
||||||
// debugPrint('center_up:$cumulativeDy');
|
// debugPrint('center_up:$cumulativeDy');
|
||||||
@@ -765,20 +756,23 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
opacity: plPlayerController.doubleSpeedStatus.value ? 1.0 : 0.0,
|
opacity: plPlayerController.doubleSpeedStatus.value ? 1.0 : 0.0,
|
||||||
duration: const Duration(milliseconds: 150),
|
duration: const Duration(milliseconds: 150),
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0x88000000),
|
color: const Color(0x88000000),
|
||||||
borderRadius: BorderRadius.circular(16.0),
|
borderRadius: BorderRadius.circular(16.0),
|
||||||
|
),
|
||||||
|
height: 32.0,
|
||||||
|
width: 70.0,
|
||||||
|
child: Center(
|
||||||
|
child: Obx(
|
||||||
|
() => Text(
|
||||||
|
'${plPlayerController.enableAutoLongPressSpeed ? plPlayerController.playbackSpeed * 2 : plPlayerController.longPressSpeed}倍速中',
|
||||||
|
style:
|
||||||
|
const TextStyle(color: Colors.white, fontSize: 13),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
height: 32.0,
|
),
|
||||||
width: 70.0,
|
),
|
||||||
child: Center(
|
|
||||||
child: Obx(() => Text(
|
|
||||||
'${plPlayerController.enableAutoLongPressSpeed ? plPlayerController.playbackSpeed * 2 : plPlayerController.longPressSpeed}倍速中',
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white, fontSize: 13),
|
|
||||||
)),
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1022,7 +1016,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
position: 'bottom',
|
position: 'bottom',
|
||||||
child: widget.bottomControl ??
|
child: widget.bottomControl ??
|
||||||
BottomControl(
|
BottomControl(
|
||||||
controller: widget.controller,
|
controller: plPlayerController,
|
||||||
buildBottomControl: buildBottomControl(),
|
buildBottomControl: buildBottomControl(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1047,11 +1041,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
}
|
}
|
||||||
if (defaultBtmProgressBehavior ==
|
if (defaultBtmProgressBehavior ==
|
||||||
BtmProgressBehavior.onlyShowFullScreen.code &&
|
BtmProgressBehavior.onlyShowFullScreen.code &&
|
||||||
!plPlayerController.isFullScreen.value) {
|
!isFullScreen) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
} else if (defaultBtmProgressBehavior ==
|
} else if (defaultBtmProgressBehavior ==
|
||||||
BtmProgressBehavior.onlyHideFullScreen.code &&
|
BtmProgressBehavior.onlyHideFullScreen.code &&
|
||||||
plPlayerController.isFullScreen.value) {
|
isFullScreen) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,28 +1143,33 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
// 锁
|
// 锁
|
||||||
Obx(
|
Obx(
|
||||||
() => Visibility(
|
() => Visibility(
|
||||||
visible: plPlayerController.videoType.value != 'live' &&
|
visible:
|
||||||
plPlayerController.isFullScreen.value,
|
plPlayerController.videoType.value != 'live' && isFullScreen,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: FractionalTranslation(
|
child: FractionalTranslation(
|
||||||
translation: const Offset(1, -0.4),
|
translation: const Offset(1, -0.4),
|
||||||
child: Visibility(
|
child: Visibility(
|
||||||
visible: plPlayerController.showControls.value &&
|
visible: plPlayerController.showControls.value &&
|
||||||
(plPlayerController.isFullScreen.value ||
|
(isFullScreen || plPlayerController.controlsLock.value),
|
||||||
plPlayerController.controlsLock.value),
|
child: DecoratedBox(
|
||||||
child: ComBtn(
|
decoration: BoxDecoration(
|
||||||
icon: Icon(
|
color: const Color(0x45000000),
|
||||||
plPlayerController.controlsLock.value
|
borderRadius: BorderRadius.circular(8),
|
||||||
? FontAwesomeIcons.lock
|
),
|
||||||
: FontAwesomeIcons.lockOpen,
|
child: ComBtn(
|
||||||
semanticLabel:
|
icon: Icon(
|
||||||
plPlayerController.controlsLock.value ? '解锁' : '锁定',
|
plPlayerController.controlsLock.value
|
||||||
size: 15,
|
? FontAwesomeIcons.lock
|
||||||
color: Colors.white,
|
: FontAwesomeIcons.lockOpen,
|
||||||
|
semanticLabel:
|
||||||
|
plPlayerController.controlsLock.value ? '解锁' : '锁定',
|
||||||
|
size: 15,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
fuc: () => plPlayerController.onLockControl(
|
||||||
|
!plPlayerController.controlsLock.value),
|
||||||
),
|
),
|
||||||
fuc: () => plPlayerController
|
|
||||||
.onLockControl(!plPlayerController.controlsLock.value),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1185,68 +1184,75 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
child: FractionalTranslation(
|
child: FractionalTranslation(
|
||||||
translation: const Offset(-1, -0.4),
|
translation: const Offset(-1, -0.4),
|
||||||
child: Visibility(
|
child: Visibility(
|
||||||
visible: plPlayerController.showControls.value &&
|
visible: plPlayerController.showControls.value && isFullScreen,
|
||||||
plPlayerController.isFullScreen.value,
|
child: DecoratedBox(
|
||||||
child: ComBtn(
|
decoration: BoxDecoration(
|
||||||
icon: const Icon(
|
color: const Color(0x45000000),
|
||||||
Icons.photo_camera,
|
borderRadius: BorderRadius.circular(8),
|
||||||
semanticLabel: '截图',
|
|
||||||
size: 20,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
),
|
||||||
fuc: () {
|
child: ComBtn(
|
||||||
SmartDialog.showToast('截图中');
|
icon: const Icon(
|
||||||
plPlayerController.videoPlayerController
|
Icons.photo_camera,
|
||||||
?.screenshot(format: 'image/png')
|
semanticLabel: '截图',
|
||||||
.then((value) {
|
size: 20,
|
||||||
if (value != null && context.mounted) {
|
color: Colors.white,
|
||||||
SmartDialog.showToast('点击弹窗保存截图');
|
),
|
||||||
showDialog(
|
fuc: () {
|
||||||
context: context,
|
SmartDialog.showToast('截图中');
|
||||||
builder: (BuildContext context) {
|
plPlayerController.videoPlayerController
|
||||||
return AlertDialog(
|
?.screenshot(format: 'image/png')
|
||||||
// title: const Text('点击保存'),
|
.then((value) {
|
||||||
titlePadding: EdgeInsets.zero,
|
if (value != null && context.mounted) {
|
||||||
contentPadding: const EdgeInsets.all(8),
|
SmartDialog.showToast('点击弹窗保存截图');
|
||||||
insetPadding:
|
showDialog(
|
||||||
EdgeInsets.only(left: context.width / 2),
|
context: context,
|
||||||
//移除圆角
|
builder: (BuildContext context) {
|
||||||
shape: const RoundedRectangleBorder(),
|
return AlertDialog(
|
||||||
content: GestureDetector(
|
// title: const Text('点击保存'),
|
||||||
onTap: () async {
|
titlePadding: EdgeInsets.zero,
|
||||||
String name = DateTime.now().toString();
|
contentPadding: const EdgeInsets.all(8),
|
||||||
final SaveResult result =
|
insetPadding:
|
||||||
await SaverGallery.saveImage(
|
EdgeInsets.only(left: context.width / 2),
|
||||||
value,
|
//移除圆角
|
||||||
fileName: name,
|
shape: const RoundedRectangleBorder(),
|
||||||
androidRelativePath: "Pictures/Screenshots",
|
content: GestureDetector(
|
||||||
skipIfExists: false,
|
onTap: () async {
|
||||||
);
|
String name = DateTime.now().toString();
|
||||||
|
final SaveResult result =
|
||||||
|
await SaverGallery.saveImage(
|
||||||
|
value,
|
||||||
|
fileName: name,
|
||||||
|
androidRelativePath:
|
||||||
|
"Pictures/Screenshots",
|
||||||
|
skipIfExists: false,
|
||||||
|
);
|
||||||
|
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
Get.back();
|
Get.back();
|
||||||
SmartDialog.showToast('$name.png已保存到相册/截图');
|
SmartDialog.showToast(
|
||||||
} else {
|
'$name.png已保存到相册/截图');
|
||||||
await SmartDialog.showToast(
|
} else {
|
||||||
'保存失败,${result.errorMessage}');
|
await SmartDialog.showToast(
|
||||||
}
|
'保存失败,${result.errorMessage}');
|
||||||
},
|
}
|
||||||
child: ConstrainedBox(
|
},
|
||||||
constraints: BoxConstraints(
|
child: ConstrainedBox(
|
||||||
maxWidth: context.width / 3,
|
constraints: BoxConstraints(
|
||||||
maxHeight: context.height / 3,
|
maxWidth: context.width / 3,
|
||||||
|
maxHeight: context.height / 3,
|
||||||
|
),
|
||||||
|
child: Image.memory(value),
|
||||||
),
|
),
|
||||||
child: Image.memory(value),
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
);
|
} else {
|
||||||
} else {
|
SmartDialog.showToast('截图失败');
|
||||||
SmartDialog.showToast('截图失败');
|
}
|
||||||
}
|
});
|
||||||
});
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1331,16 +1337,16 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
onSubmitted: (Duration value) {
|
onSubmitted: (Duration value) {
|
||||||
_hideSeekBackwardButton.value = true;
|
_hideSeekBackwardButton.value = true;
|
||||||
_mountSeekBackwardButton.value = false;
|
_mountSeekBackwardButton.value = false;
|
||||||
final Player player =
|
final Player player = widget
|
||||||
widget.controller.videoPlayerController!;
|
.plPlayerController.videoPlayerController!;
|
||||||
Duration result = player.state.position - value;
|
Duration result = player.state.position - value;
|
||||||
result = result.clamp(
|
result = result.clamp(
|
||||||
Duration.zero,
|
Duration.zero,
|
||||||
player.state.duration,
|
player.state.duration,
|
||||||
);
|
);
|
||||||
widget.controller
|
plPlayerController.seekTo(result,
|
||||||
.seekTo(result, type: 'slider');
|
type: 'slider');
|
||||||
widget.controller.play();
|
plPlayerController.play();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1377,16 +1383,16 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
onSubmitted: (Duration value) {
|
onSubmitted: (Duration value) {
|
||||||
_hideSeekForwardButton.value = true;
|
_hideSeekForwardButton.value = true;
|
||||||
_mountSeekForwardButton.value = false;
|
_mountSeekForwardButton.value = false;
|
||||||
final Player player =
|
final Player player = widget
|
||||||
widget.controller.videoPlayerController!;
|
.plPlayerController.videoPlayerController!;
|
||||||
Duration result = player.state.position + value;
|
Duration result = player.state.position + value;
|
||||||
result = result.clamp(
|
result = result.clamp(
|
||||||
Duration.zero,
|
Duration.zero,
|
||||||
player.state.duration,
|
player.state.duration,
|
||||||
);
|
);
|
||||||
widget.controller
|
plPlayerController.seekTo(result,
|
||||||
.seekTo(result, type: 'slider');
|
type: 'slider');
|
||||||
widget.controller.play();
|
plPlayerController.play();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ComBtn extends StatelessWidget {
|
|||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 34,
|
width: 34,
|
||||||
height: 34,
|
height: 34,
|
||||||
child: InkWell(
|
child: GestureDetector(
|
||||||
onTap: fuc,
|
onTap: fuc,
|
||||||
child: icon!,
|
child: icon!,
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user