custom player/max volume

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-06-08 17:28:32 +08:00
parent e7efba6843
commit 7725b15f0b
20 changed files with 291 additions and 145 deletions

View File

@@ -267,7 +267,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,
@@ -290,7 +290,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,
@@ -369,7 +369,7 @@ Future<void> _showReplyCountDialog(
final res = await showDialog<double>(
context: context,
builder: (context) => SliderDialog(
title: '连接重试次数',
title: const Text('连接重试次数'),
min: 0,
max: 8,
divisions: 8,
@@ -391,7 +391,7 @@ Future<void> _showReplyDelayDialog(
final res = await showDialog<double>(
context: context,
builder: (context) => SliderDialog(
title: '连接重试间隔',
title: const Text('连接重试间隔'),
min: 0,
max: 1000,
divisions: 10,

View File

@@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/pages/setting/models/model.dart';
import 'package:PiliPlus/pages/setting/widgets/slider_dialog.dart';
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.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';
@@ -39,6 +40,20 @@ List<SettingsModel> get playSettings => [
setKey: SettingBoxKey.showBatteryLevel,
defaultVal: PlatformUtils.isMobile,
),
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',
@@ -95,7 +110,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: 80,
@@ -109,3 +124,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);
}
}

View File

@@ -98,7 +98,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;
@@ -117,7 +117,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);
@@ -164,7 +164,7 @@ List<SettingsModel> get styleSettings => [
void _showQualityDialog({
required BuildContext context,
required String title,
required Widget title,
required int initValue,
required ValueChanged<int> onChanged,
}) {
@@ -341,11 +341,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,

View File

@@ -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(

View File

@@ -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(

View File

@@ -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(