mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-30 06:10:10 +08:00
custom player/max volume
Closes #2199 Closes #2358 Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
@@ -19,6 +19,8 @@ import 'package:PiliPlus/pages/common/common_intro_controller.dart'
|
||||
show FavMixin;
|
||||
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
||||
import 'package:PiliPlus/pages/main_reply/view.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart'
|
||||
show kMaxVolume;
|
||||
import 'package:PiliPlus/pages/sponsor_block/block_mixin.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_mixin.dart';
|
||||
@@ -328,11 +330,14 @@ class AudioController extends GetxController
|
||||
_hasInit = true;
|
||||
assert(player == null, _subscriptions = null);
|
||||
player = await Player.create(
|
||||
configuration: PlatformUtils.isDesktop
|
||||
? PlayerConfiguration(
|
||||
options: {'volume': (desktopVolume.value * 100).toString()},
|
||||
)
|
||||
: const PlayerConfiguration(),
|
||||
configuration: PlayerConfiguration(
|
||||
options: {
|
||||
'volume': PlatformUtils.isDesktop
|
||||
? (desktopVolume.value * 100).toString()
|
||||
: Pref.playerVolume.toString(),
|
||||
'volume-max': kMaxVolume.toString(),
|
||||
},
|
||||
),
|
||||
);
|
||||
if (isClosed) {
|
||||
player!.dispose();
|
||||
|
||||
@@ -14,7 +14,11 @@ import 'package:PiliPlus/models/common/image_preview_type.dart';
|
||||
import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/pages/audio/controller.dart';
|
||||
import 'package:PiliPlus/pages/audio/volume_button.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart'
|
||||
show showPlayerVolumeDialog;
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
|
||||
import 'package:PiliPlus/pages/video/widgets/header_control.dart'
|
||||
show HeaderControlState;
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
|
||||
import 'package:PiliPlus/services/shutdown_timer_service.dart';
|
||||
import 'package:PiliPlus/utils/date_utils.dart';
|
||||
@@ -615,28 +619,43 @@ class _AudioPageState extends State<AudioPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
// ListTile(
|
||||
// dense: true,
|
||||
// title: const Text(
|
||||
// '定时关闭',
|
||||
// style: TextStyle(fontSize: 14),
|
||||
// ),
|
||||
// onTap: () {
|
||||
// Get.back();
|
||||
// _controller.showTimerDialog();
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'举报',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
leading: const Icon(Icons.warning_amber_rounded, size: 20),
|
||||
title: const Text('举报', style: TextStyle(fontSize: 14)),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
PageUtils.reportVideo(_controller.oid.toInt());
|
||||
},
|
||||
),
|
||||
if (_controller.player case final player?) ...[
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.info_outline, size: 20),
|
||||
title: const Text('播放信息', style: TextStyle(fontSize: 14)),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
HeaderControlState.showPlayerInfo(context, player: player);
|
||||
},
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.volume_up, size: 20),
|
||||
title: Text(
|
||||
'播放器音量: ${player.getProperty('volume').subLength(3)}%',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
showPlayerVolumeDialog(
|
||||
context,
|
||||
() {},
|
||||
onChanged: player.setVolume,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:math' as math;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/flutter/vertical_slider.dart';
|
||||
import 'package:PiliPlus/pages/audio/controller.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart' show RenderProxyBox, BoxHitTestResult;
|
||||
import 'package:get/get.dart';
|
||||
@@ -140,7 +141,7 @@ class _VolumeButtonState extends State<VolumeButton> {
|
||||
child: VerticalSlider(
|
||||
year2023: true,
|
||||
min: 0.0,
|
||||
max: 2.0,
|
||||
max: Pref.maxVolume,
|
||||
value: volume,
|
||||
showValueIndicator: .never,
|
||||
onChanged: widget.controller.setVolume,
|
||||
|
||||
@@ -123,10 +123,7 @@ class _DynMentionPanelState
|
||||
padding: EdgeInsets.only(left: 12, right: 4),
|
||||
child: Icon(Icons.search, size: 20),
|
||||
),
|
||||
prefixIconConstraints: const BoxConstraints(
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
),
|
||||
prefixIconConstraints: const .new(minHeight: 0, minWidth: 0),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 6,
|
||||
|
||||
@@ -2,12 +2,15 @@ import 'dart:io';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/marquee.dart';
|
||||
import 'package:PiliPlus/pages/live_room/controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart'
|
||||
show showPlayerVolumeDialog;
|
||||
import 'package:PiliPlus/pages/video/widgets/header_control.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart';
|
||||
import 'package:PiliPlus/services/shutdown_timer_service.dart'
|
||||
show shutdownTimerService;
|
||||
import 'package:PiliPlus/utils/android/bindings.g.dart';
|
||||
import 'package:PiliPlus/utils/extension/string_ext.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
@@ -233,19 +236,62 @@ class _LiveHeaderControlState extends State<LiveHeaderControl>
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
ComBtn(
|
||||
height: 30,
|
||||
tooltip: '播放信息',
|
||||
onTap: () => HeaderControlState.showPlayerInfo(
|
||||
context,
|
||||
plPlayerController: plPlayerController,
|
||||
),
|
||||
icon: const Icon(
|
||||
size: 18,
|
||||
Icons.info_outline,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
if (plPlayerController.videoPlayerController case final player?)
|
||||
if (PlatformUtils.isMobile)
|
||||
SizedBox.square(
|
||||
dimension: 30,
|
||||
child: PopupMenuButton(
|
||||
iconSize: 18,
|
||||
padding: .zero,
|
||||
iconColor: Colors.white,
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
height: 35,
|
||||
child: const Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Icon(Icons.info_outline, size: 16),
|
||||
Text('播放信息', style: TextStyle(fontSize: 14)),
|
||||
],
|
||||
),
|
||||
onTap: () => HeaderControlState.showPlayerInfo(
|
||||
context,
|
||||
player: player,
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
height: 35,
|
||||
child: Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
const Icon(Icons.volume_up, size: 16),
|
||||
Text(
|
||||
'播放器音量: ${player.getProperty('volume').subLength(3)}%',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => showPlayerVolumeDialog(
|
||||
context,
|
||||
() {},
|
||||
onChanged: player.setVolume,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
ComBtn(
|
||||
height: 30,
|
||||
tooltip: '播放信息',
|
||||
onTap: () =>
|
||||
HeaderControlState.showPlayerInfo(context, player: player),
|
||||
icon: const Icon(
|
||||
size: 18,
|
||||
Icons.info_outline,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -940,7 +940,7 @@ Future<void> _showRefreshDragDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: '刷新滑动距离',
|
||||
title: const Text('刷新滑动距离'),
|
||||
min: 0.1,
|
||||
max: 0.5,
|
||||
divisions: 8,
|
||||
@@ -963,7 +963,7 @@ Future<void> _showRefreshDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: '刷新指示器高度',
|
||||
title: const Text('刷新指示器高度'),
|
||||
min: 10.0,
|
||||
max: 100.0,
|
||||
divisions: 9,
|
||||
@@ -1063,7 +1063,7 @@ Future<void> _showReplyCountDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: '连接重试次数',
|
||||
title: const Text('连接重试次数'),
|
||||
min: 0,
|
||||
max: 8,
|
||||
divisions: 8,
|
||||
@@ -1085,7 +1085,7 @@ Future<void> _showReplyDelayDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: '连接重试间隔',
|
||||
title: const Text('连接重试间隔'),
|
||||
min: 0,
|
||||
max: 1000,
|
||||
divisions: 10,
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/fullscreen_mode.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
|
||||
import 'package:PiliPlus/services/service_locator.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
@@ -101,6 +102,20 @@ List<SettingsModel> get playSettings => [
|
||||
setKey: SettingBoxKey.enableSlideFS,
|
||||
defaultVal: true,
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
NormalModel(
|
||||
title: '播放器音量',
|
||||
leading: const Icon(Icons.volume_up),
|
||||
getSubtitle: () => '当前:「${Pref.playerVolume.toStringAsFixed(0)}%」',
|
||||
onTap: showPlayerVolumeDialog,
|
||||
)
|
||||
else
|
||||
NormalModel(
|
||||
title: '最高音量',
|
||||
leading: const Icon(Icons.volume_up),
|
||||
getSubtitle: () => '当前:「${(Pref.maxVolume * 100).toStringAsFixed(0)}%」',
|
||||
onTap: _showMaxVolumeDialog,
|
||||
),
|
||||
getVideoFilterSelectModel(
|
||||
title: '双击快进/快退时长',
|
||||
suffix: 's',
|
||||
@@ -362,7 +377,7 @@ Future<void> _showAngleDegreesDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: '倾斜角度阈值',
|
||||
title: const Text('倾斜角度阈值'),
|
||||
min: 10.0,
|
||||
max: 90.0,
|
||||
divisions: 90,
|
||||
@@ -376,3 +391,67 @@ Future<void> _showAngleDegreesDialog(
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showPlayerVolumeDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState, {
|
||||
ValueChanged<double>? onChanged,
|
||||
}) {
|
||||
return showVolumeDialog(
|
||||
context,
|
||||
title: const Text('播放器音量'),
|
||||
value: Pref.playerVolume,
|
||||
onChanged: (value) => GStorage.setting
|
||||
.put(SettingBoxKey.playerVolume, value)
|
||||
.whenComplete(() {
|
||||
setState();
|
||||
onChanged?.call(value);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showMaxVolumeDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState,
|
||||
) {
|
||||
return showVolumeDialog(
|
||||
context,
|
||||
title: const Text('最高音量'),
|
||||
value: Pref.maxVolume * 100,
|
||||
onChanged: (rawValue) {
|
||||
final maxVolume = (rawValue / 100).toPrecision(2);
|
||||
if (Pref.desktopVolume > maxVolume) {
|
||||
GStorage.setting.put(SettingBoxKey.desktopVolume, maxVolume);
|
||||
}
|
||||
GStorage.setting
|
||||
.put(SettingBoxKey.maxVolume, maxVolume)
|
||||
.whenComplete(setState);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const kMinVolume = 100.0;
|
||||
const kMaxVolume = 300.0;
|
||||
|
||||
Future<void> showVolumeDialog(
|
||||
BuildContext context, {
|
||||
required Widget title,
|
||||
required double value,
|
||||
required ValueChanged<double> onChanged,
|
||||
}) async {
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: title,
|
||||
min: kMinVolume,
|
||||
max: kMaxVolume,
|
||||
divisions: 40,
|
||||
precise: 0,
|
||||
value: value,
|
||||
suffix: '%',
|
||||
),
|
||||
);
|
||||
if (res != null) {
|
||||
onChanged(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ List<SettingsModel> get styleSettings => [
|
||||
NormalModel(
|
||||
onTap: (context, setState) => _showQualityDialog(
|
||||
context: context,
|
||||
title: '图片质量',
|
||||
title: const Text('图片质量'),
|
||||
initValue: Pref.picQuality,
|
||||
onChanged: (picQuality) async {
|
||||
GlobalData().imgQuality = picQuality;
|
||||
@@ -239,7 +239,7 @@ List<SettingsModel> get styleSettings => [
|
||||
NormalModel(
|
||||
onTap: (context, setState) => _showQualityDialog(
|
||||
context: context,
|
||||
title: '查看大图质量',
|
||||
title: const Text('查看大图质量'),
|
||||
initValue: Pref.previewQ,
|
||||
onChanged: (picQuality) async {
|
||||
await GStorage.setting.put(SettingBoxKey.previewQuality, picQuality);
|
||||
@@ -381,7 +381,7 @@ List<SettingsModel> get styleSettings => [
|
||||
|
||||
void _showQualityDialog({
|
||||
required BuildContext context,
|
||||
required String title,
|
||||
required Widget title,
|
||||
required int initValue,
|
||||
required ValueChanged<int> onChanged,
|
||||
}) {
|
||||
@@ -637,7 +637,7 @@ Future<void> _showFontWeightDialog(BuildContext context) async {
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: 'App字体字重',
|
||||
title: const Text('App字体字重'),
|
||||
value: Pref.appFontWeight.toDouble() + 1,
|
||||
min: 1,
|
||||
max: FontWeight.values.length.toDouble(),
|
||||
@@ -676,11 +676,11 @@ Future<void> _showCardWidthDialog(
|
||||
final res = await showDialog<(double, double)>(
|
||||
context: context,
|
||||
builder: (context) => DualSliderDialog(
|
||||
title: '列表最大列宽度(默认240dp)',
|
||||
title: const Text('列表最大列宽度(默认240dp)'),
|
||||
value1: Pref.recommendCardWidth,
|
||||
value2: Pref.smallCardWidth,
|
||||
description1: '主页推荐流',
|
||||
description2: '其他',
|
||||
description1: const Text('主页推荐流'),
|
||||
description2: const Text('其他'),
|
||||
min: 150.0,
|
||||
max: 500.0,
|
||||
divisions: 35,
|
||||
@@ -853,7 +853,7 @@ Future<void> _showToastDialog(
|
||||
final res = await showDialog<double>(
|
||||
context: context,
|
||||
builder: (context) => SliderDialog(
|
||||
title: 'Toast不透明度',
|
||||
title: const Text('Toast不透明度'),
|
||||
value: CustomToast.toastOpacity,
|
||||
min: 0.0,
|
||||
max: 1.0,
|
||||
|
||||
@@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
|
||||
class DualSliderDialog extends StatefulWidget {
|
||||
final double value1;
|
||||
final double value2;
|
||||
final String title;
|
||||
final String description1;
|
||||
final String description2;
|
||||
final Widget title;
|
||||
final Widget description1;
|
||||
final Widget description2;
|
||||
final double min;
|
||||
final double max;
|
||||
final int? divisions;
|
||||
@@ -45,7 +45,7 @@ class _DualSliderDialogState extends State<DualSliderDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.title),
|
||||
title: widget.title,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 8,
|
||||
@@ -55,7 +55,7 @@ class _DualSliderDialogState extends State<DualSliderDialog> {
|
||||
content: Column(
|
||||
mainAxisSize: .min,
|
||||
children: [
|
||||
Text(widget.description1),
|
||||
widget.description1,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return Slider(
|
||||
@@ -72,7 +72,7 @@ class _DualSliderDialogState extends State<DualSliderDialog> {
|
||||
);
|
||||
},
|
||||
),
|
||||
Text(widget.description2),
|
||||
widget.description2,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return Slider(
|
||||
|
||||
@@ -35,7 +35,7 @@ class SelectDialog<T> extends StatelessWidget {
|
||||
clipBehavior: Clip.hardEdge,
|
||||
title: Text(title),
|
||||
constraints: subtitleBuilder != null
|
||||
? const BoxConstraints(maxWidth: 320, minWidth: 320)
|
||||
? const BoxConstraints.tightFor(width: 320)
|
||||
: null,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
content: Material(
|
||||
|
||||
@@ -2,14 +2,6 @@ import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SliderDialog extends StatefulWidget {
|
||||
final double value;
|
||||
final String title;
|
||||
final double min;
|
||||
final double max;
|
||||
final int? divisions;
|
||||
final String suffix;
|
||||
final int precise;
|
||||
|
||||
const SliderDialog({
|
||||
super.key,
|
||||
required this.value,
|
||||
@@ -21,6 +13,14 @@ class SliderDialog extends StatefulWidget {
|
||||
this.precise = 1,
|
||||
});
|
||||
|
||||
final double value;
|
||||
final Widget title;
|
||||
final double min;
|
||||
final double max;
|
||||
final int? divisions;
|
||||
final String suffix;
|
||||
final int precise;
|
||||
|
||||
@override
|
||||
State<SliderDialog> createState() => _SliderDialogState();
|
||||
}
|
||||
@@ -37,13 +37,8 @@ class _SliderDialogState extends State<SliderDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.title),
|
||||
contentPadding: const EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 8,
|
||||
right: 8,
|
||||
bottom: 8,
|
||||
),
|
||||
title: widget.title,
|
||||
contentPadding: const .only(top: 20, left: 8, right: 8, bottom: 8),
|
||||
content: SizedBox(
|
||||
height: 40,
|
||||
child: Slider(
|
||||
|
||||
@@ -23,6 +23,8 @@ import 'package:PiliPlus/models/video/play/url.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_play_info/subtitle.dart';
|
||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||
import 'package:PiliPlus/pages/danmaku/danmaku_model.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart'
|
||||
show showPlayerVolumeDialog;
|
||||
import 'package:PiliPlus/pages/setting/widgets/popup_item.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
@@ -66,6 +68,7 @@ import 'package:get/get.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:intl/intl.dart' show DateFormat;
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:media_kit/media_kit.dart' show NativePlayer;
|
||||
|
||||
mixin TimeBatteryMixin<T extends StatefulWidget> on State<T> {
|
||||
PlPlayerController get plPlayerController;
|
||||
@@ -476,6 +479,24 @@ class HeaderControlState extends State<HeaderControl>
|
||||
descFontSize: 12,
|
||||
descPosType: .subtitle,
|
||||
),
|
||||
if (PlatformUtils.isMobile)
|
||||
if (plPlayerController.videoPlayerController
|
||||
case final player?)
|
||||
Builder(
|
||||
builder: (context) => ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.volume_up, size: 20),
|
||||
title: const Text('播放器音量'),
|
||||
subtitle: Text(
|
||||
'当前: ${Pref.playerVolume.toStringAsFixed(0)}%',
|
||||
),
|
||||
onTap: () => showPlayerVolumeDialog(
|
||||
context,
|
||||
() => (context as Element).markNeedsBuild(),
|
||||
onChanged: player.setVolume,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!isFileSource)
|
||||
ListTile(
|
||||
dense: true,
|
||||
@@ -729,15 +750,13 @@ class HeaderControlState extends State<HeaderControl>
|
||||
leading: const Icon(Icons.download_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: () => showPlayerInfo(
|
||||
context,
|
||||
plPlayerController: plPlayerController,
|
||||
if (plPlayerController.videoPlayerController case final player?)
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text('播放信息', style: titleStyle),
|
||||
leading: const Icon(Icons.info_outline, size: 20),
|
||||
onTap: () => showPlayerInfo(context, player: player),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
onTap: () {
|
||||
@@ -761,14 +780,10 @@ class HeaderControlState extends State<HeaderControl>
|
||||
|
||||
static void showPlayerInfo(
|
||||
BuildContext context, {
|
||||
required PlPlayerController plPlayerController,
|
||||
required NativePlayer player,
|
||||
}) {
|
||||
final player = plPlayerController.videoPlayerController;
|
||||
if (player == null) {
|
||||
SmartDialog.showToast('播放器未初始化');
|
||||
return;
|
||||
}
|
||||
final hwdec = player.getProperty('hwdec-current');
|
||||
final volume = player.getProperty('volume').subLength(3);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
@@ -789,9 +804,7 @@ class HeaderControlState extends State<HeaderControl>
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("Resolution"),
|
||||
subtitle: Text(
|
||||
'${state.width}x${state.height}',
|
||||
),
|
||||
subtitle: Text('${state.width}x${state.height}'),
|
||||
onTap: () => Utils.copyText(
|
||||
'Resolution\n${state.width}x${state.height}',
|
||||
),
|
||||
@@ -799,60 +812,42 @@ class HeaderControlState extends State<HeaderControl>
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("VideoParams"),
|
||||
subtitle: Text(
|
||||
state.videoParams.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'VideoParams\n${state.videoParams}',
|
||||
),
|
||||
subtitle: Text(state.videoParams.toString()),
|
||||
onTap: () =>
|
||||
Utils.copyText('VideoParams\n${state.videoParams}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("AudioParams"),
|
||||
subtitle: Text(
|
||||
state.audioParams.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'AudioParams\n${state.audioParams}',
|
||||
),
|
||||
subtitle: Text(state.audioParams.toString()),
|
||||
onTap: () =>
|
||||
Utils.copyText('AudioParams\n${state.audioParams}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("Media"),
|
||||
subtitle: Text(
|
||||
state.playlist.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'Media\n${state.playlist}',
|
||||
),
|
||||
subtitle: Text(state.playlist.toString()),
|
||||
onTap: () => Utils.copyText('Media\n${state.playlist}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("AudioTrack"),
|
||||
subtitle: Text(
|
||||
state.track.audio.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'AudioTrack\n${state.track.audio}',
|
||||
),
|
||||
subtitle: Text(state.track.audio.toString()),
|
||||
onTap: () =>
|
||||
Utils.copyText('AudioTrack\n${state.track.audio}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("VideoTrack"),
|
||||
subtitle: Text(
|
||||
state.track.video.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'VideoTrack\n${state.track.audio}',
|
||||
),
|
||||
subtitle: Text(state.track.video.toString()),
|
||||
onTap: () =>
|
||||
Utils.copyText('VideoTrack\n${state.track.audio}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("pitch"),
|
||||
subtitle: Text(state.pitch.toString()),
|
||||
onTap: () => Utils.copyText(
|
||||
'pitch\n${state.pitch}',
|
||||
),
|
||||
onTap: () => Utils.copyText('pitch\n${state.pitch}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
@@ -863,12 +858,8 @@ class HeaderControlState extends State<HeaderControl>
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("Volume"),
|
||||
subtitle: Text(
|
||||
state.volume.toString(),
|
||||
),
|
||||
onTap: () => Utils.copyText(
|
||||
'Volume\n${state.volume}',
|
||||
),
|
||||
subtitle: Text(volume.toString()),
|
||||
onTap: () => Utils.copyText('Volume\n$volume'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
|
||||
@@ -63,7 +63,7 @@ class PlayerFocus extends StatelessWidget {
|
||||
void _setVolume({required bool isIncrease}) {
|
||||
final volume = isIncrease
|
||||
? math.min(
|
||||
PlPlayerController.maxVolume,
|
||||
plPlayerController.maxVolume,
|
||||
plPlayerController.volume.value + 0.1,
|
||||
)
|
||||
: math.max(0.0, plPlayerController.volume.value - 0.1);
|
||||
|
||||
Reference in New Issue
Block a user