Files
plezy/test/widgets/volume_control_test.dart
T
Ryan Ernest c86d40f8dd fix(player): preserve volume when toggling mute (#1532)
* fix(player): preserve volume when toggling mute

Muting now keeps the last volume level memorized. Unmuting restores that level, including amplified values allowed by the configured maximum.

* fix(player): preserve volume for companion remote mute

Route the companion remote through the shared mute transition so it no longer overwrites the persisted volume or restores to 100%. Also correct the Dartdoc formatting for the transition record fields.
2026-07-11 12:46:58 +02:00

86 lines
2.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/mpv/mpv.dart';
import 'package:plezy/services/settings_service.dart';
import 'package:plezy/widgets/video_controls/widgets/volume_control.dart';
import '../test_helpers/prefs.dart';
void main() {
setUp(() async {
resetSharedPreferencesForTest();
SettingsService.resetForTesting();
await SettingsService.getInstance();
LocaleSettings.setLocaleSync(AppLocale.en);
});
testWidgets('mute button keeps and restores the exact non-zero volume', (tester) async {
final settings = SettingsService.instance;
await settings.write(SettingsService.volume, 37.0);
final player = _VolumePlayer(37);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(body: VolumeControl(player: player)),
),
);
await tester.tap(find.byType(IconButton));
await tester.pumpAndSettle();
expect(player.volume, 0);
expect(settings.read(SettingsService.volume), 37);
await tester.tap(find.byType(IconButton));
await tester.pumpAndSettle();
expect(player.volume, 37);
expect(settings.read(SettingsService.volume), 37);
expect(player.volumeChanges, [0, 37]);
});
}
class _VolumePlayer implements Player {
_VolumePlayer(this.volume)
: _streams = PlayerStreams(
playing: const Stream<bool>.empty(),
completed: const Stream<bool>.empty(),
buffering: const Stream<bool>.empty(),
position: const Stream<Duration>.empty(),
duration: const Stream<Duration>.empty(),
seekable: const Stream<bool>.empty(),
buffer: const Stream<Duration>.empty(),
volume: const Stream<double>.empty(),
rate: const Stream<double>.empty(),
tracks: const Stream<Tracks>.empty(),
track: const Stream<TrackSelection>.empty(),
log: const Stream<PlayerLog>.empty(),
error: const Stream<PlayerError>.empty(),
audioDevice: const Stream<AudioDevice>.empty(),
audioDevices: const Stream<List<AudioDevice>>.empty(),
bufferRanges: const Stream<List<BufferRange>>.empty(),
playbackRestart: const Stream<void>.empty(),
backendSwitched: const Stream<void>.empty(),
);
double volume;
final List<double> volumeChanges = [];
final PlayerStreams _streams;
@override
PlayerState get state => PlayerState(volume: volume);
@override
PlayerStreams get streams => _streams;
@override
Future<void> setVolume(double volume) async {
this.volume = volume;
volumeChanges.add(volume);
}
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}