mod: video sheet

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-21 18:04:31 +08:00
parent 4190c17cdc
commit 516eed76b7

View File

@@ -113,480 +113,444 @@ class _HeaderControlState extends State<HeaderControl> {
right: 12, right: 12,
bottom: 12 + MediaQuery.paddingOf(context).bottom, bottom: 12 + MediaQuery.paddingOf(context).bottom,
), ),
child: Column( child: Material(
children: [ color: Colors.transparent,
SizedBox( child: MediaQuery.removePadding(
height: 35, context: context,
child: Center( removeBottom: true,
child: Container( child: ListView(
width: 32, children: [
height: 3, const SizedBox(height: 14),
decoration: BoxDecoration( // ListTile(
color: Theme.of(context) // onTap: () {},
.colorScheme // dense: true,
.onSecondaryContainer // enabled: false,
.withOpacity(0.5), // leading:
borderRadius: const BorderRadius.all(Radius.circular(3))), // const Icon(Icons.network_cell_outlined, size: 20),
// title: Text('省流模式', style: titleStyle),
// subtitle: Text('低画质 减少视频缓存', style: subTitleStyle),
// trailing: Transform.scale(
// scale: 0.75,
// child: Switch(
// thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
// (Set<WidgetState> states) {
// if (states.isNotEmpty &&
// states.first == WidgetState.selected) {
// return const Icon(Icons.done);
// }
// return null; // All other states will use the default thumbIcon.
// }),
// value: false,
// onChanged: (value) => {},
// ),
// ),
// ),
// if (widget.videoDetailCtr.userInfo != null)
ListTile(
dense: true,
onTap: () async {
Get.back();
final res = await UserHttp.toViewLater(
bvid: widget.videoDetailCtr.bvid);
SmartDialog.showToast(res['msg']);
},
leading: const Icon(Icons.watch_later_outlined, size: 20),
title: const Text('添加至「稍后再看」', style: titleStyle),
), ),
), ListTile(
), dense: true,
Expanded( onTap: () => {Get.back(), scheduleExit()},
child: Material( leading: const Icon(Icons.hourglass_top_outlined, size: 20),
color: Colors.transparent, title: const Text('定时关闭', style: titleStyle),
child: MediaQuery.removePadding( ),
context: context, ListTile(
removeBottom: true, dense: true,
child: ListView( onTap: () => {
Get.back(),
widget.videoDetailCtr.queryVideoUrl(
widget.videoDetailCtr.playedTime,
)
},
leading: const Icon(Icons.refresh_outlined, size: 20),
title: const Text('重载视频', style: titleStyle),
),
ListTile(
dense: true,
leading: const Icon(Icons.stay_current_landscape_outlined,
size: 20),
title: Row(
children: [ children: [
// ListTile( const Text(
// onTap: () {}, '超分辨率',
// dense: true, strutStyle: StrutStyle(leading: 0, height: 1),
// enabled: false, style: TextStyle(
// leading: height: 1,
// const Icon(Icons.network_cell_outlined, size: 20), fontSize: 14,
// title: Text('省流模式', style: titleStyle), ),
// subtitle: Text('低画质 减少视频缓存', style: subTitleStyle),
// trailing: Transform.scale(
// scale: 0.75,
// child: Switch(
// thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
// (Set<WidgetState> states) {
// if (states.isNotEmpty &&
// states.first == WidgetState.selected) {
// return const Icon(Icons.done);
// }
// return null; // All other states will use the default thumbIcon.
// }),
// value: false,
// onChanged: (value) => {},
// ),
// ),
// ),
// if (widget.videoDetailCtr.userInfo != null)
ListTile(
dense: true,
onTap: () async {
Get.back();
final res = await UserHttp.toViewLater(
bvid: widget.videoDetailCtr.bvid);
SmartDialog.showToast(res['msg']);
},
leading:
const Icon(Icons.watch_later_outlined, size: 20),
title: const Text('添加至「稍后再看」', style: titleStyle),
), ),
ListTile( const SizedBox(width: 10),
dense: true, Builder(
onTap: () => {Get.back(), scheduleExit()}, builder: (context) => PopupMenuButton(
leading: initialValue: SuperResolutionType
const Icon(Icons.hourglass_top_outlined, size: 20), .values[widget.controller.superResolutionType],
title: const Text('定时关闭', style: titleStyle), child: Padding(
), padding: const EdgeInsets.all(4),
ListTile( child: Row(
dense: true, mainAxisSize: MainAxisSize.min,
onTap: () => { children: [
Get.back(), Text(
widget.videoDetailCtr.queryVideoUrl( SuperResolutionType
widget.videoDetailCtr.playedTime, .values[
) widget.controller.superResolutionType]
}, .title,
leading: const Icon(Icons.refresh_outlined, size: 20), strutStyle: StrutStyle(leading: 0, height: 1),
title: const Text('重载视频', style: titleStyle), style: TextStyle(
), height: 1,
ListTile( fontSize: 14,
dense: true, color:
leading: const Icon( Theme.of(context).colorScheme.secondary,
Icons.stay_current_landscape_outlined, ),
size: 20), ),
title: Row( Icon(
children: [ MdiIcons.unfoldMoreHorizontal,
const Text( size: MediaQuery.textScalerOf(context)
'超分辨率', .scale(14),
strutStyle: StrutStyle(leading: 0, height: 1), color:
style: TextStyle( Theme.of(context).colorScheme.secondary,
height: 1, )
fontSize: 14, ],
),
), ),
const SizedBox(width: 10), ),
Builder( onSelected: (value) {
builder: (context) => PopupMenuButton( widget.controller.setShader(value.index);
initialValue: SuperResolutionType.values[ if (context.mounted) {
widget.controller.superResolutionType], (context as Element).markNeedsBuild();
child: Padding( }
padding: const EdgeInsets.all(4), },
child: Row( itemBuilder: (context) => SuperResolutionType.values
mainAxisSize: MainAxisSize.min, .map((item) => PopupMenuItem(
children: [ value: item,
Text( child: Text(item.title),
SuperResolutionType ))
.values[widget .toList(),
.controller.superResolutionType]
.title,
strutStyle:
StrutStyle(leading: 0, height: 1),
style: TextStyle(
height: 1,
fontSize: 14,
color: Theme.of(context)
.colorScheme
.secondary,
),
),
Icon(
MdiIcons.unfoldMoreHorizontal,
size: MediaQuery.textScalerOf(context)
.scale(14),
color: Theme.of(context)
.colorScheme
.secondary,
)
],
),
),
onSelected: (value) {
widget.controller.setShader(value.index);
if (context.mounted) {
(context as Element).markNeedsBuild();
}
},
itemBuilder: (context) =>
SuperResolutionType.values
.map((item) => PopupMenuItem(
value: item,
child: Text(item.title),
))
.toList(),
),
),
],
), ),
), ),
ListTile(
dense: true,
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());
},
);
if (result != null) {
defaultCDNService = result;
setting.put(SettingBoxKey.CDNService, result);
SmartDialog.showToast(
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
setState(() {});
widget.videoDetailCtr.queryVideoUrl(
widget.videoDetailCtr.playedTime,
);
}
},
),
SelfSizedHorizontalList(
itemCount: 4,
gapSize: 10,
padding: const EdgeInsets.symmetric(horizontal: 16),
childBuilder: (index) {
return switch (index) {
0 => Obx(
() => ActionRowLineItem(
iconData: Icons.flip,
onTap: () {
widget.controller.flipX.value =
!widget.controller.flipX.value;
},
text: " 左右翻转 ",
selectStatus: widget.controller.flipX.value,
),
),
1 => Obx(
() => ActionRowLineItem(
icon: Transform.rotate(
angle: pi / 2,
child: Icon(
Icons.flip,
size: 13,
color: widget.controller.flipY.value
? Theme.of(context)
.colorScheme
.onSecondaryContainer
: Theme.of(context)
.colorScheme
.outline,
),
),
onTap: () {
widget.controller.flipY.value =
!widget.controller.flipY.value;
},
text: " 上下翻转 ",
selectStatus: widget.controller.flipY.value,
),
),
2 => Obx(
() => ActionRowLineItem(
iconData: Icons.headphones,
onTap: widget.controller.setOnlyPlayAudio,
text: " 听视频 ",
selectStatus:
widget.controller.onlyPlayAudio.value,
),
),
3 => Obx(
() => ActionRowLineItem(
iconData: Icons.play_circle_outline,
onTap: widget
.controller.setContinuePlayInBackground,
text: " 后台播放 ",
selectStatus: widget.controller
.continuePlayInBackground.value,
),
),
int() => throw UnimplementedError(),
};
},
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetVideoQa()},
leading:
const Icon(Icons.play_circle_outline, size: 20),
title: const Text('选择画质', style: titleStyle),
subtitle: Text(
'当前画质 ${widget.videoDetailCtr.currentVideoQa.description}',
style: subTitleStyle),
),
if (widget.videoDetailCtr.currentAudioQa != null)
ListTile(
dense: true,
onTap: () => {Get.back(), showSetAudioQa()},
leading: const Icon(Icons.album_outlined, size: 20),
title: const Text('选择音质', style: titleStyle),
subtitle: Text(
'当前音质 ${widget.videoDetailCtr.currentAudioQa!.description}',
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetDecodeFormats()},
leading: const Icon(Icons.av_timer_outlined, size: 20),
title: const Text('解码格式', style: titleStyle),
subtitle: Text(
'当前解码格式 ${widget.videoDetailCtr.currentDecodeFormats.description}',
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetRepeat()},
leading: const Icon(Icons.repeat, size: 20),
title: const Text('播放顺序', style: titleStyle),
subtitle: Text(widget.controller.playRepeat.description,
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetDanmaku()},
leading: const Icon(Icons.subtitles_outlined, size: 20),
title: const Text('弹幕/字幕设置', style: titleStyle),
),
ListTile(
dense: true,
title: const Text('播放信息', style: titleStyle),
leading: const Icon(Icons.info_outline, size: 20),
onTap: () {
Player? player =
widget.controller.videoPlayerController;
if (player == null) {
SmartDialog.showToast('播放器未初始化');
return;
}
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('播放信息'),
content: SizedBox(
width: double.maxFinite,
child: ListView(
children: [
ListTile(
dense: true,
title: const Text("Resolution"),
subtitle: Text(
'${player.state.width}x${player.state.height}'),
onTap: () {
Utils.copyText(
'Resolution\n${player.state.width}x${player.state.height}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("VideoParams"),
subtitle: Text(player.state.videoParams
.toString()),
onTap: () {
Utils.copyText(
'VideoParams\n${player.state.videoParams}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("AudioParams"),
subtitle: Text(player.state.audioParams
.toString()),
onTap: () {
Utils.copyText(
'AudioParams\n${player.state.audioParams}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("Media"),
subtitle: Text(
player.state.playlist.toString()),
onTap: () {
Utils.copyText(
'Media\n${player.state.playlist}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("AudioTrack"),
subtitle: Text(player.state.track.audio
.toString()),
onTap: () {
Utils.copyText(
'AudioTrack\n${player.state.track.audio}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("VideoTrack"),
subtitle: Text(player.state.track.video
.toString()),
onTap: () {
Utils.copyText(
'VideoTrack\n${player.state.track.audio}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("pitch"),
subtitle: Text(
player.state.pitch.toString()),
onTap: () {
Utils.copyText(
'pitch\n${player.state.pitch}',
needToast: false,
);
}),
ListTile(
dense: true,
title: const Text("rate"),
subtitle: Text(
player.state.rate.toString()),
onTap: () {
Utils.copyText(
'rate\n${player.state.rate}',
needToast: false,
);
}),
ListTile(
dense: true,
title: const Text("AudioBitrate"),
subtitle: Text(player.state.audioBitrate
.toString()),
onTap: () {
Utils.copyText(
'AudioBitrate\n${player.state.audioBitrate}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("Volume"),
subtitle: Text(
player.state.volume.toString()),
onTap: () {
Utils.copyText(
'Volume\n${player.state.volume}',
needToast: false,
);
},
),
],
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'确定',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.outline),
),
),
],
);
},
);
},
),
ListTile(
dense: true,
onTap: () {
if (widget.videoDetailCtr.userInfo == null) {
SmartDialog.showToast('账号未登录');
return;
}
Get.back();
Get.toNamed('/webview', parameters: {
'url':
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr.bvid)}&bvid=${widget.videoDetailCtr.bvid}'
});
},
leading: const Icon(Icons.error_outline, size: 20),
title: const Text('举报', style: titleStyle),
),
const SizedBox(height: 14),
], ],
), ),
), ),
), ListTile(
dense: true,
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());
},
);
if (result != null) {
defaultCDNService = result;
setting.put(SettingBoxKey.CDNService, result);
SmartDialog.showToast(
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
setState(() {});
widget.videoDetailCtr.queryVideoUrl(
widget.videoDetailCtr.playedTime,
);
}
},
),
SelfSizedHorizontalList(
itemCount: 4,
gapSize: 10,
padding: const EdgeInsets.symmetric(horizontal: 16),
childBuilder: (index) {
return switch (index) {
0 => Obx(
() => ActionRowLineItem(
iconData: Icons.flip,
onTap: () {
widget.controller.flipX.value =
!widget.controller.flipX.value;
},
text: " 左右翻转 ",
selectStatus: widget.controller.flipX.value,
),
),
1 => Obx(
() => ActionRowLineItem(
icon: Transform.rotate(
angle: pi / 2,
child: Icon(
Icons.flip,
size: 13,
color: widget.controller.flipY.value
? Theme.of(context)
.colorScheme
.onSecondaryContainer
: Theme.of(context).colorScheme.outline,
),
),
onTap: () {
widget.controller.flipY.value =
!widget.controller.flipY.value;
},
text: " 上下翻转 ",
selectStatus: widget.controller.flipY.value,
),
),
2 => Obx(
() => ActionRowLineItem(
iconData: Icons.headphones,
onTap: widget.controller.setOnlyPlayAudio,
text: " 听视频 ",
selectStatus: widget.controller.onlyPlayAudio.value,
),
),
3 => Obx(
() => ActionRowLineItem(
iconData: Icons.play_circle_outline,
onTap:
widget.controller.setContinuePlayInBackground,
text: " 后台播放 ",
selectStatus: widget
.controller.continuePlayInBackground.value,
),
),
int() => throw UnimplementedError(),
};
},
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetVideoQa()},
leading: const Icon(Icons.play_circle_outline, size: 20),
title: const Text('选择画质', style: titleStyle),
subtitle: Text(
'当前画质 ${widget.videoDetailCtr.currentVideoQa.description}',
style: subTitleStyle),
),
if (widget.videoDetailCtr.currentAudioQa != null)
ListTile(
dense: true,
onTap: () => {Get.back(), showSetAudioQa()},
leading: const Icon(Icons.album_outlined, size: 20),
title: const Text('选择音质', style: titleStyle),
subtitle: Text(
'当前音质 ${widget.videoDetailCtr.currentAudioQa!.description}',
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetDecodeFormats()},
leading: const Icon(Icons.av_timer_outlined, size: 20),
title: const Text('解码格式', style: titleStyle),
subtitle: Text(
'当前解码格式 ${widget.videoDetailCtr.currentDecodeFormats.description}',
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetRepeat()},
leading: const Icon(Icons.repeat, size: 20),
title: const Text('播放顺序', style: titleStyle),
subtitle: Text(widget.controller.playRepeat.description,
style: subTitleStyle),
),
ListTile(
dense: true,
onTap: () => {Get.back(), showSetDanmaku()},
leading: const Icon(Icons.subtitles_outlined, size: 20),
title: const Text('弹幕/字幕设置', style: titleStyle),
),
ListTile(
dense: true,
title: const Text('播放信息', style: titleStyle),
leading: const Icon(Icons.info_outline, size: 20),
onTap: () {
Player? player = widget.controller.videoPlayerController;
if (player == null) {
SmartDialog.showToast('播放器未初始化');
return;
}
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('播放信息'),
content: SizedBox(
width: double.maxFinite,
child: ListView(
children: [
ListTile(
dense: true,
title: const Text("Resolution"),
subtitle: Text(
'${player.state.width}x${player.state.height}'),
onTap: () {
Utils.copyText(
'Resolution\n${player.state.width}x${player.state.height}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("VideoParams"),
subtitle:
Text(player.state.videoParams.toString()),
onTap: () {
Utils.copyText(
'VideoParams\n${player.state.videoParams}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("AudioParams"),
subtitle:
Text(player.state.audioParams.toString()),
onTap: () {
Utils.copyText(
'AudioParams\n${player.state.audioParams}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("Media"),
subtitle:
Text(player.state.playlist.toString()),
onTap: () {
Utils.copyText(
'Media\n${player.state.playlist}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("AudioTrack"),
subtitle:
Text(player.state.track.audio.toString()),
onTap: () {
Utils.copyText(
'AudioTrack\n${player.state.track.audio}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("VideoTrack"),
subtitle:
Text(player.state.track.video.toString()),
onTap: () {
Utils.copyText(
'VideoTrack\n${player.state.track.audio}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("pitch"),
subtitle:
Text(player.state.pitch.toString()),
onTap: () {
Utils.copyText(
'pitch\n${player.state.pitch}',
needToast: false,
);
}),
ListTile(
dense: true,
title: const Text("rate"),
subtitle:
Text(player.state.rate.toString()),
onTap: () {
Utils.copyText(
'rate\n${player.state.rate}',
needToast: false,
);
}),
ListTile(
dense: true,
title: const Text("AudioBitrate"),
subtitle: Text(
player.state.audioBitrate.toString()),
onTap: () {
Utils.copyText(
'AudioBitrate\n${player.state.audioBitrate}',
needToast: false,
);
},
),
ListTile(
dense: true,
title: const Text("Volume"),
subtitle:
Text(player.state.volume.toString()),
onTap: () {
Utils.copyText(
'Volume\n${player.state.volume}',
needToast: false,
);
},
),
],
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'确定',
style: TextStyle(
color:
Theme.of(context).colorScheme.outline),
),
),
],
);
},
);
},
),
ListTile(
dense: true,
onTap: () {
if (widget.videoDetailCtr.userInfo == null) {
SmartDialog.showToast('账号未登录');
return;
}
Get.back();
Get.toNamed('/webview', parameters: {
'url':
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr.bvid)}&bvid=${widget.videoDetailCtr.bvid}'
});
},
leading: const Icon(Icons.error_outline, size: 20),
title: const Text('举报', style: titleStyle),
),
const SizedBox(height: 14),
],
), ),
], ),
), ),
), ),
); );
@@ -619,7 +583,7 @@ class _HeaderControlState extends State<HeaderControl> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 30), const SizedBox(height: 10),
const Center(child: Text('定时关闭', style: titleStyle)), const Center(child: Text('定时关闭', style: titleStyle)),
const SizedBox(height: 10), const SizedBox(height: 10),
...[ ...[
@@ -1149,8 +1113,7 @@ class _HeaderControlState extends State<HeaderControl> {
Get.toNamed('/danmakuBlock', Get.toNamed('/danmakuBlock',
arguments: widget.controller) arguments: widget.controller)
}, },
child: Text( child: Text("屏蔽管理(${widget.controller.filterCount})")),
"屏蔽管理(${widget.controller.filterCount})")),
], ],
), ),
Padding( Padding(