@@ -4,6 +4,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/mpv/mpv.dart';
|
||||
import 'package:plezy/services/keyboard_shortcuts_service.dart';
|
||||
import 'package:plezy/services/settings_service.dart';
|
||||
import 'package:plezy/services/video_filter_manager.dart';
|
||||
|
||||
import '../test_helpers/prefs.dart';
|
||||
|
||||
@@ -13,7 +14,7 @@ void main() {
|
||||
SettingsService.resetForTesting();
|
||||
});
|
||||
|
||||
testWidgets('Ctrl+S takes a screenshot and shows feedback', (tester) async {
|
||||
testWidgets('Ctrl+S takes a screenshot once while held', (tester) async {
|
||||
final service = await KeyboardShortcutsService.getInstance();
|
||||
addTearDown(service.dispose);
|
||||
final player = _FakePlayer();
|
||||
@@ -35,15 +36,197 @@ void main() {
|
||||
null,
|
||||
onScreenshot: () => feedbackCount++,
|
||||
);
|
||||
final repeatResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyRepeatEvent(
|
||||
physicalKey: PhysicalKeyboardKey.keyS,
|
||||
logicalKey: LogicalKeyboardKey.keyS,
|
||||
timeStamp: Duration(milliseconds: 30),
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onScreenshot: () => feedbackCount++,
|
||||
);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft);
|
||||
await tester.pump();
|
||||
|
||||
expect(result, KeyEventResult.handled);
|
||||
expect(repeatResult, KeyEventResult.handled);
|
||||
expect(player.commands, [
|
||||
['screenshot', 'subtitles'],
|
||||
]);
|
||||
expect(feedbackCount, 1);
|
||||
});
|
||||
|
||||
testWidgets('Alt+Plus triggers zoom in callback', (tester) async {
|
||||
final service = await KeyboardShortcutsService.getInstance();
|
||||
addTearDown(service.dispose);
|
||||
final player = _FakePlayer();
|
||||
var zoomInCount = 0;
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
|
||||
final result = service.handleVideoPlayerKeyEvent(
|
||||
const KeyDownEvent(
|
||||
physicalKey: PhysicalKeyboardKey.equal,
|
||||
logicalKey: LogicalKeyboardKey.equal,
|
||||
timeStamp: Duration.zero,
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomIn: () => zoomInCount++,
|
||||
);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
|
||||
|
||||
expect(result, KeyEventResult.handled);
|
||||
expect(zoomInCount, 1);
|
||||
});
|
||||
|
||||
testWidgets('Alt+Plus repeats zoom in callback while held', (tester) async {
|
||||
final service = await KeyboardShortcutsService.getInstance();
|
||||
addTearDown(service.dispose);
|
||||
final player = _FakePlayer();
|
||||
var zoomInCount = 0;
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
|
||||
final downResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyDownEvent(
|
||||
physicalKey: PhysicalKeyboardKey.equal,
|
||||
logicalKey: LogicalKeyboardKey.equal,
|
||||
timeStamp: Duration.zero,
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomIn: () => zoomInCount++,
|
||||
);
|
||||
final repeatResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyRepeatEvent(
|
||||
physicalKey: PhysicalKeyboardKey.equal,
|
||||
logicalKey: LogicalKeyboardKey.equal,
|
||||
timeStamp: Duration(milliseconds: 30),
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomIn: () => zoomInCount++,
|
||||
);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
|
||||
|
||||
expect(downResult, KeyEventResult.handled);
|
||||
expect(repeatResult, KeyEventResult.handled);
|
||||
expect(zoomInCount, 2);
|
||||
});
|
||||
|
||||
testWidgets('Alt+Minus repeats zoom out callback while held', (tester) async {
|
||||
final service = await KeyboardShortcutsService.getInstance();
|
||||
addTearDown(service.dispose);
|
||||
final player = _FakePlayer();
|
||||
var zoomOutCount = 0;
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
|
||||
final downResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyDownEvent(
|
||||
physicalKey: PhysicalKeyboardKey.minus,
|
||||
logicalKey: LogicalKeyboardKey.minus,
|
||||
timeStamp: Duration.zero,
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomOut: () => zoomOutCount++,
|
||||
);
|
||||
final repeatResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyRepeatEvent(
|
||||
physicalKey: PhysicalKeyboardKey.minus,
|
||||
logicalKey: LogicalKeyboardKey.minus,
|
||||
timeStamp: Duration(milliseconds: 30),
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomOut: () => zoomOutCount++,
|
||||
);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
|
||||
|
||||
expect(downResult, KeyEventResult.handled);
|
||||
expect(repeatResult, KeyEventResult.handled);
|
||||
expect(zoomOutCount, 2);
|
||||
});
|
||||
|
||||
testWidgets('Alt+Backspace reset does not repeat while held', (tester) async {
|
||||
final service = await KeyboardShortcutsService.getInstance();
|
||||
addTearDown(service.dispose);
|
||||
final player = _FakePlayer();
|
||||
var resetCount = 0;
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
|
||||
final downResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyDownEvent(
|
||||
physicalKey: PhysicalKeyboardKey.backspace,
|
||||
logicalKey: LogicalKeyboardKey.backspace,
|
||||
timeStamp: Duration.zero,
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomReset: () => resetCount++,
|
||||
);
|
||||
final repeatResult = service.handleVideoPlayerKeyEvent(
|
||||
const KeyRepeatEvent(
|
||||
physicalKey: PhysicalKeyboardKey.backspace,
|
||||
logicalKey: LogicalKeyboardKey.backspace,
|
||||
timeStamp: Duration(milliseconds: 30),
|
||||
),
|
||||
player,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
onZoomReset: () => resetCount++,
|
||||
);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
|
||||
|
||||
expect(downResult, KeyEventResult.handled);
|
||||
expect(repeatResult, KeyEventResult.handled);
|
||||
expect(resetCount, 1);
|
||||
});
|
||||
|
||||
test('video zoom scale maps to mpv logarithmic property', () {
|
||||
expect(VideoFilterManager.videoZoomPropertyForScale(1.0), closeTo(0.0, 0.0001));
|
||||
expect(VideoFilterManager.videoZoomPropertyForScale(2.0), closeTo(1.0, 0.0001));
|
||||
expect(VideoFilterManager.videoZoomPropertyForScale(0.5), closeTo(-1.0, 0.0001));
|
||||
});
|
||||
}
|
||||
|
||||
class _FakePlayer implements Player {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/widgets/video_controls/helpers/two_finger_double_tap_tracker.dart';
|
||||
|
||||
void main() {
|
||||
late DateTime now;
|
||||
late TwoFingerDoubleTapTracker tracker;
|
||||
|
||||
void advance(Duration duration) {
|
||||
now = now.add(duration);
|
||||
}
|
||||
|
||||
setUp(() {
|
||||
now = DateTime(2026);
|
||||
tracker = TwoFingerDoubleTapTracker(now: () => now);
|
||||
});
|
||||
|
||||
test('detects two two-finger taps as double tap', () {
|
||||
tracker.pointerDown(1, const Offset(100, 100));
|
||||
tracker.pointerDown(2, const Offset(140, 100));
|
||||
expect(tracker.pointerUp(1, const Offset(100, 100)), isFalse);
|
||||
expect(tracker.pointerUp(2, const Offset(140, 100)), isFalse);
|
||||
|
||||
advance(const Duration(milliseconds: 120));
|
||||
|
||||
tracker.pointerDown(3, const Offset(102, 102));
|
||||
tracker.pointerDown(4, const Offset(142, 102));
|
||||
expect(tracker.pointerUp(3, const Offset(102, 102)), isFalse);
|
||||
expect(tracker.pointerUp(4, const Offset(142, 102)), isTrue);
|
||||
});
|
||||
|
||||
test('does not detect one-finger double tap', () {
|
||||
tracker.pointerDown(1, const Offset(100, 100));
|
||||
expect(tracker.pointerUp(1, const Offset(100, 100)), isFalse);
|
||||
|
||||
advance(const Duration(milliseconds: 120));
|
||||
|
||||
tracker.pointerDown(2, const Offset(100, 100));
|
||||
expect(tracker.pointerUp(2, const Offset(100, 100)), isFalse);
|
||||
});
|
||||
|
||||
test('movement invalidates a candidate two-finger tap', () {
|
||||
tracker.pointerDown(1, const Offset(100, 100));
|
||||
tracker.pointerDown(2, const Offset(140, 100));
|
||||
tracker.pointerMove(1, const Offset(140, 140));
|
||||
expect(tracker.pointerUp(1, const Offset(140, 140)), isFalse);
|
||||
expect(tracker.pointerUp(2, const Offset(140, 100)), isFalse);
|
||||
|
||||
advance(const Duration(milliseconds: 120));
|
||||
|
||||
tracker.pointerDown(3, const Offset(100, 100));
|
||||
tracker.pointerDown(4, const Offset(140, 100));
|
||||
expect(tracker.pointerUp(3, const Offset(100, 100)), isFalse);
|
||||
expect(tracker.pointerUp(4, const Offset(140, 100)), isFalse);
|
||||
});
|
||||
|
||||
test('third finger invalidates a candidate two-finger tap', () {
|
||||
tracker.pointerDown(1, const Offset(100, 100));
|
||||
tracker.pointerDown(2, const Offset(140, 100));
|
||||
tracker.pointerDown(3, const Offset(180, 100));
|
||||
expect(tracker.pointerUp(1, const Offset(100, 100)), isFalse);
|
||||
expect(tracker.pointerUp(2, const Offset(140, 100)), isFalse);
|
||||
expect(tracker.pointerUp(3, const Offset(180, 100)), isFalse);
|
||||
|
||||
advance(const Duration(milliseconds: 120));
|
||||
|
||||
tracker.pointerDown(4, const Offset(100, 100));
|
||||
tracker.pointerDown(5, const Offset(140, 100));
|
||||
expect(tracker.pointerUp(4, const Offset(100, 100)), isFalse);
|
||||
expect(tracker.pointerUp(5, const Offset(140, 100)), isFalse);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user