fix(player): reduce sync offset dpad step

This commit is contained in:
edde746
2026-05-31 06:38:25 +02:00
parent 5671f6e5d1
commit 8413e1e5a7
2 changed files with 106 additions and 32 deletions
@@ -61,7 +61,7 @@ class _SyncOffsetControlState extends State<SyncOffsetControl> {
static const double _absoluteMax = 60000;
static const double _tapStep = 100; // 100ms per tap
static const double _longPressStep = 1000; // 1s per long-press tick
static const int _sliderDivisions = 240; // 500ms steps for ±60s range
static const int _sliderDivisions = 1200; // 100ms steps for ±60s range
late double _currentOffset;
Timer? _longPressTimer;
@@ -243,22 +243,25 @@ class _SyncOffsetControlState extends State<SyncOffsetControl> {
return KeyEventResult.ignored;
},
canRequestFocus: false,
child: Slider(
focusNode: widget.sliderFocusNode,
value: sliderValue,
min: _sliderMin,
max: _sliderMax,
divisions: _sliderDivisions,
activeColor: Theme.of(context).colorScheme.primary,
inactiveColor: Theme.of(context).colorScheme.outlineVariant,
onChanged: (value) {
setState(() {
_currentOffset = value;
});
},
onChangeEnd: (value) {
_applyOffset(value);
},
child: SliderTheme(
data: SliderTheme.of(context).copyWith(tickMarkShape: SliderTickMarkShape.noTickMark),
child: Slider(
focusNode: widget.sliderFocusNode,
value: sliderValue,
min: _sliderMin,
max: _sliderMax,
divisions: _sliderDivisions,
activeColor: Theme.of(context).colorScheme.primary,
inactiveColor: Theme.of(context).colorScheme.outlineVariant,
onChanged: (value) {
setState(() {
_currentOffset = value;
});
},
onChangeEnd: (value) {
_applyOffset(value);
},
),
),
),
),
@@ -333,21 +336,24 @@ class _SyncOffsetControlState extends State<SyncOffsetControl> {
style: TextStyle(color: tokens(context).textMuted),
),
Expanded(
child: Slider(
value: sliderValue,
min: _sliderMin,
max: _sliderMax,
divisions: _sliderDivisions,
activeColor: Theme.of(context).colorScheme.primary,
inactiveColor: Theme.of(context).colorScheme.outlineVariant,
onChanged: (value) {
setState(() {
_currentOffset = value;
});
},
onChangeEnd: (value) {
_applyOffset(value);
},
child: SliderTheme(
data: SliderTheme.of(context).copyWith(tickMarkShape: SliderTickMarkShape.noTickMark),
child: Slider(
value: sliderValue,
min: _sliderMin,
max: _sliderMax,
divisions: _sliderDivisions,
activeColor: Theme.of(context).colorScheme.primary,
inactiveColor: Theme.of(context).colorScheme.outlineVariant,
onChanged: (value) {
setState(() {
_currentOffset = value;
});
},
onChangeEnd: (value) {
_applyOffset(value);
},
),
),
),
Text(
+68
View File
@@ -1,15 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/media/media_source_info.dart';
import 'package:plezy/media/media_version.dart';
import 'package:plezy/models/shader_preset.dart';
import 'package:plezy/mpv/mpv.dart';
import 'package:plezy/theme/mono_tokens.dart';
import 'package:plezy/widgets/video_controls/video_controls.dart';
import 'package:plezy/widgets/video_controls/painters/buffer_range_painter.dart';
import 'package:plezy/widgets/video_controls/widgets/mobile_skip_zones.dart';
import 'package:plezy/widgets/video_controls/widgets/sync_offset_control.dart';
import 'package:plezy/widgets/video_controls/widgets/timeline_slider.dart';
const _testTokens = MonoTokens(
radiusSm: 8,
radiusMd: 12,
space: 8,
fast: Duration(milliseconds: 1),
normal: Duration(milliseconds: 1),
slow: Duration(milliseconds: 1),
bg: Colors.black,
surface: Colors.black,
outline: Colors.white24,
text: Colors.white,
textMuted: Colors.white70,
splashFactory: NoSplash.splashFactory,
);
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('resolveShaderTogglePreset', () {
test('turns shaders off when a shader is currently active', () {
final result = resolveShaderTogglePreset(
@@ -234,4 +255,51 @@ void main() {
expect(slider.max, 0.0);
});
});
group('SyncOffsetControl', () {
testWidgets('uses 100ms slider steps without rendering tick marks', (tester) async {
LocaleSettings.setLocaleSync(AppLocale.en);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(extensions: const [_testTokens]),
home: Scaffold(
body: SizedBox(
width: 700,
child: SyncOffsetControl(
player: _FakeSyncPlayer(),
propertyName: 'sub-delay',
initialOffset: 0,
labelText: 'Subtitles',
onOffsetChanged: (_) async {},
compact: true,
),
),
),
),
);
final slider = tester.widget<Slider>(find.byType(Slider));
final sliderTheme = tester.widget<SliderTheme>(
find.ancestor(of: find.byType(Slider), matching: find.byType(SliderTheme)).first,
);
expect(slider.min, -60000);
expect(slider.max, 60000);
expect(slider.divisions, 1200);
expect((slider.max - slider.min) / slider.divisions!, 100);
expect(sliderTheme.data.tickMarkShape, same(SliderTickMarkShape.noTickMark));
});
});
}
class _FakeSyncPlayer implements Player {
@override
PlayerState get state => PlayerState();
@override
Future<void> setProperty(String name, String value) async {}
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}