feat(settings): expose music quality preset

This commit is contained in:
edde746
2026-07-12 08:42:22 +02:00
parent 2ebc1e250d
commit 242cc8616c
6 changed files with 86 additions and 3 deletions
+1
View File
@@ -158,6 +158,7 @@
"bufferSizeWarning": "${heap}MB memory available. A ${size}MB buffer may affect playback.",
"defaultQualityTitle": "Default Quality",
"defaultQualityDescription": "Used when starting playback. Lower values reduce bandwidth.",
"musicQualityTitle": "Music Quality",
"subtitleStyling": "Subtitle Styling",
"subtitleStylingDescription": "Customize subtitle appearance",
"smallSkipDuration": "Small Skip Duration",
+1 -1
View File
@@ -4,7 +4,7 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 16
/// Strings: 22706 (1419 per locale)
/// Strings: 22707 (1419 per locale)
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+6 -2
View File
@@ -588,6 +588,9 @@ class TranslationsSettingsEn {
/// en: 'Used when starting playback. Lower values reduce bandwidth.'
String get defaultQualityDescription => 'Used when starting playback. Lower values reduce bandwidth.';
/// en: 'Music Quality'
String get musicQualityTitle => 'Music Quality';
/// en: 'Subtitle Styling'
String get subtitleStyling => 'Subtitle Styling';
@@ -5111,6 +5114,7 @@ extension on Translations {
'settings.bufferSizeWarning' => ({required Object heap, required Object size}) => '${heap}MB memory available. A ${size}MB buffer may affect playback.',
'settings.defaultQualityTitle' => 'Default Quality',
'settings.defaultQualityDescription' => 'Used when starting playback. Lower values reduce bandwidth.',
'settings.musicQualityTitle' => 'Music Quality',
'settings.subtitleStyling' => 'Subtitle Styling',
'settings.subtitleStylingDescription' => 'Customize subtitle appearance',
'settings.smallSkipDuration' => 'Small Skip Duration',
@@ -5474,9 +5478,9 @@ extension on Translations {
'messages.removedFromContinueWatching' => 'Removed from Continue Watching',
'messages.errorLoading' => ({required Object error}) => 'Error: ${error}',
'messages.streamInterrupted' => 'The stream was interrupted. Press play or seek to retry.',
'messages.fileInfoNotAvailable' => 'File information not available',
_ => null,
} ?? switch (path) {
'messages.fileInfoNotAvailable' => 'File information not available',
'messages.errorLoadingFileInfo' => ({required Object error}) => 'Error loading file info: ${error}',
'messages.errorLoadingSeries' => 'Error loading series',
'messages.musicNotSupported' => 'Music playback is not yet supported',
@@ -5988,9 +5992,9 @@ extension on Translations {
'downloads.manage' => 'Manage',
'downloads.tvShows' => 'TV Shows',
'downloads.movies' => 'Movies',
'downloads.music' => 'Music',
_ => null,
} ?? switch (path) {
'downloads.music' => 'Music',
'downloads.tracksQueued' => ({required Object count}) => '${count} tracks queued for download',
'downloads.noDownloads' => 'No downloads yet',
'downloads.noDownloadsDescription' => 'Downloaded content will appear here for offline viewing',
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import '../../i18n/strings.g.dart';
import '../../models/audio_quality_preset.dart';
import '../../models/transcode_quality_preset.dart';
import '../../mpv/player/platform/player_android.dart';
import '../../utils/quality_preset_labels.dart';
@@ -91,6 +92,7 @@ class _PlaybackSettingsScreenState extends State<PlaybackSettingsScreen> {
if (exoActive) _dvConversionModeTile(),
_bufferSizeTile(),
_defaultQualityTile(),
_musicQualityTile(),
],
),
@@ -443,6 +445,19 @@ class _PlaybackSettingsScreenState extends State<PlaybackSettingsScreen> {
encode: (p) => p,
);
Widget _musicQualityTile() => SettingSelectionTile<AudioQualityPreset, AudioQualityPreset>(
pref: SettingsService.musicQualityPreset,
icon: Symbols.music_note_rounded,
title: t.settings.musicQualityTitle,
subtitleBuilder: _musicQualityLabel,
options: AudioQualityPreset.values.map((p) => DialogOption(value: p, title: _musicQualityLabel(p))).toList(),
decode: (p) => p,
encode: (p) => p,
);
String _musicQualityLabel(AudioQualityPreset preset) =>
preset.isOriginal ? t.videoControls.qualityOriginal : '${preset.bitrateKbps} kbps';
Widget _mpvConfigTile() => SettingNavigationTile(
icon: Symbols.tune_rounded,
title: t.mpvConfig.title,
@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/models/audio_quality_preset.dart';
import 'package:plezy/screens/settings/playback_settings_screen.dart';
import 'package:plezy/services/settings_service.dart';
import 'package:plezy/theme/mono_theme.dart';
import '../../test_helpers/prefs.dart';
void main() {
setUp(() async {
resetSharedPreferencesForTest(initialAsync: {'music_quality_preset': 'medium'});
SettingsService.resetForTesting();
await SettingsService.getInstance();
LocaleSettings.setLocaleSync(AppLocale.en);
});
testWidgets('shows and changes the persisted music quality', (tester) async {
tester.view.devicePixelRatio = 1;
tester.view.physicalSize = const Size(1000, 1400);
addTearDown(tester.view.resetDevicePixelRatio);
addTearDown(tester.view.resetPhysicalSize);
await tester.pumpWidget(MaterialApp(theme: monoTheme(dark: true), home: const PlaybackSettingsScreen()));
await tester.pumpAndSettle();
final title = find.text('Music Quality');
await tester.scrollUntilVisible(title, 500, scrollable: find.byType(Scrollable).first);
final tile = find.widgetWithText(ListTile, 'Music Quality');
expect(find.descendant(of: tile, matching: find.text('192 kbps')), findsOneWidget);
await tester.tap(title);
await tester.pumpAndSettle();
await tester.tap(find.text('128 kbps'));
await tester.pumpAndSettle();
final settings = SettingsService.instance;
expect(settings.read(SettingsService.musicQualityPreset), AudioQualityPreset.low);
expect(settings.prefs.getString(SettingsService.musicQualityPreset.key), 'low');
expect(find.descendant(of: tile, matching: find.text('128 kbps')), findsOneWidget);
});
}
+19
View File
@@ -1,6 +1,8 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/models/audio_quality_preset.dart';
import 'package:plezy/models/hotkey_model.dart';
import 'package:plezy/services/base_shared_preferences_service.dart';
import 'package:plezy/services/settings_service.dart';
import 'package:plezy/services/trackers/tracker_constants.dart';
import 'package:plezy/utils/platform_detector.dart';
@@ -145,6 +147,23 @@ void main() {
});
});
group('SettingsService music quality', () {
test('defaults to original and persists changes by enum name', () async {
var settings = await SettingsService.getInstance();
expect(settings.read(SettingsService.musicQualityPreset), AudioQualityPreset.original);
await settings.write(SettingsService.musicQualityPreset, AudioQualityPreset.medium);
expect(settings.prefs.getString(SettingsService.musicQualityPreset.key), 'medium');
BaseSharedPreferencesService.resetForTesting();
SettingsService.resetForTesting();
settings = await SettingsService.getInstance();
expect(settings.read(SettingsService.musicQualityPreset), AudioQualityPreset.medium);
});
});
group('SettingsService platform gates', () {
test('audio passthrough stays available on desktop and Apple TV', () {
expect(PlatformDetector.supportsAudioPassthrough(), isTrue);