Initial commit
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/features/player/widgets/android/android_bottom_transport_controls.dart';
|
||||
|
||||
import '../../../../helpers/fake_player_engine.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('renders prev play next order', (tester) async {
|
||||
final player = FakePlayerEngine(playing: true);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: Center(
|
||||
child: AndroidBottomTransportControls(
|
||||
player: player,
|
||||
hasPrev: true,
|
||||
hasNext: true,
|
||||
onPrevItem: () {},
|
||||
onNextItem: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.skip_previous), findsOneWidget);
|
||||
expect(find.byIcon(Icons.pause), findsOneWidget);
|
||||
expect(find.byIcon(Icons.skip_next), findsOneWidget);
|
||||
|
||||
final prevCenter = tester.getCenter(find.byIcon(Icons.skip_previous));
|
||||
final playCenter = tester.getCenter(find.byIcon(Icons.pause));
|
||||
final nextCenter = tester.getCenter(find.byIcon(Icons.skip_next));
|
||||
|
||||
expect(prevCenter.dx < playCenter.dx, isTrue);
|
||||
expect(playCenter.dx < nextCenter.dx, isTrue);
|
||||
|
||||
await player.dispose();
|
||||
});
|
||||
|
||||
testWidgets('invokes prev/next callbacks and toggles playback', (
|
||||
tester,
|
||||
) async {
|
||||
final player = FakePlayerEngine(playing: true);
|
||||
var prevTaps = 0;
|
||||
var nextTaps = 0;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AndroidBottomTransportControls(
|
||||
player: player,
|
||||
hasPrev: true,
|
||||
hasNext: true,
|
||||
onPrevItem: () => prevTaps++,
|
||||
onNextItem: () => nextTaps++,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byIcon(Icons.skip_previous));
|
||||
await tester.tap(find.byIcon(Icons.skip_next));
|
||||
await tester.tap(find.byIcon(Icons.pause));
|
||||
await tester.pump();
|
||||
|
||||
expect(prevTaps, 1);
|
||||
expect(nextTaps, 1);
|
||||
expect(player.pauseCalls, 1);
|
||||
expect(player.playCalls, 0);
|
||||
|
||||
await player.dispose();
|
||||
});
|
||||
|
||||
testWidgets('disables prev/next when unavailable', (tester) async {
|
||||
final player = FakePlayerEngine(playing: true);
|
||||
var prevTaps = 0;
|
||||
var nextTaps = 0;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: AndroidBottomTransportControls(
|
||||
player: player,
|
||||
hasPrev: false,
|
||||
hasNext: false,
|
||||
onPrevItem: () => prevTaps++,
|
||||
onNextItem: () => nextTaps++,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final prevBtn = tester.widget<IconButton>(
|
||||
find.widgetWithIcon(IconButton, Icons.skip_previous),
|
||||
);
|
||||
final nextBtn = tester.widget<IconButton>(
|
||||
find.widgetWithIcon(IconButton, Icons.skip_next),
|
||||
);
|
||||
|
||||
expect(prevBtn.onPressed, isNull);
|
||||
expect(nextBtn.onPressed, isNull);
|
||||
|
||||
await player.dispose();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/features/player/widgets/android/android_gesture_feedback.dart';
|
||||
|
||||
void main() {
|
||||
Widget buildSubject({required bool seekIsForward}) {
|
||||
return MaterialApp(
|
||||
home: SizedBox(
|
||||
width: 360,
|
||||
height: 240,
|
||||
child: AndroidGestureFeedback(
|
||||
data: GestureFeedbackData(
|
||||
kind: GestureFeedbackKind.seek,
|
||||
seekTarget: const Duration(minutes: 1),
|
||||
totalDuration: const Duration(minutes: 10),
|
||||
seekIsForward: seekIsForward,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('seek preview shows rewind icon for backward seek', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(buildSubject(seekIsForward: false));
|
||||
|
||||
expect(find.byIcon(Icons.fast_rewind), findsOneWidget);
|
||||
expect(find.byIcon(Icons.fast_forward), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('seek preview shows forward icon for forward seek', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(buildSubject(seekIsForward: true));
|
||||
|
||||
expect(find.byIcon(Icons.fast_forward), findsOneWidget);
|
||||
expect(find.byIcon(Icons.fast_rewind), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('long press speed uses light background', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: SizedBox(
|
||||
width: 360,
|
||||
height: 240,
|
||||
child: AndroidGestureFeedback(
|
||||
data: GestureFeedbackData(
|
||||
kind: GestureFeedbackKind.longPressSpeed,
|
||||
speedRate: 3,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final container = tester.widget<Container>(
|
||||
find.descendant(
|
||||
of: find.byType(AndroidGestureFeedback),
|
||||
matching: find.byType(Container),
|
||||
),
|
||||
);
|
||||
final decoration = container.decoration as BoxDecoration;
|
||||
|
||||
expect(decoration.color, const Color(0x45181818));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/features/player/widgets/player_hold_speed_prompt.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('hold speed prompt uses light background', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Stack(
|
||||
children: [HoldSpeedPrompt(visible: true, isLeft: false, rate: 3)],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final container = tester.widget<Container>(
|
||||
find.descendant(
|
||||
of: find.byType(HoldSpeedPrompt),
|
||||
matching: find.byType(Container),
|
||||
),
|
||||
);
|
||||
final decoration = container.decoration as BoxDecoration;
|
||||
|
||||
expect(decoration.color, const Color(0x45181818));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/features/player/widgets/player_hold_speed_prompt.dart';
|
||||
import 'package:smplayer/features/player/widgets/player_video_widget.dart';
|
||||
|
||||
import '../../../helpers/fake_player_engine.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('keyboard hold speed prompt hides immediately on release', (
|
||||
tester,
|
||||
) async {
|
||||
final player = FakePlayerEngine(playing: true);
|
||||
final fit = ValueNotifier<BoxFit>(BoxFit.contain);
|
||||
final rates = <double>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: SizedBox(
|
||||
width: 800,
|
||||
height: 450,
|
||||
child: PlayerVideoWidget(
|
||||
player: player,
|
||||
fit: fit,
|
||||
topBar: const [],
|
||||
bottomBar: const SizedBox.shrink(),
|
||||
overlays: const [],
|
||||
onControlsAreaTap: null,
|
||||
isFullscreen: false,
|
||||
onToggleFullscreen: () async {},
|
||||
isPip: false,
|
||||
keyboardEnabled: true,
|
||||
currentRate: 1,
|
||||
onSetRate: rates.add,
|
||||
suppressControlsChrome: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
expect(_promptOpacity(tester), 1);
|
||||
expect(rates.last, 3);
|
||||
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.pump();
|
||||
|
||||
expect(_promptOpacity(tester), 0);
|
||||
expect(rates.last, 1);
|
||||
|
||||
fit.dispose();
|
||||
await player.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
double _promptOpacity(WidgetTester tester) {
|
||||
return tester
|
||||
.widget<AnimatedOpacity>(
|
||||
find.descendant(
|
||||
of: find.byType(HoldSpeedPrompt),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
),
|
||||
)
|
||||
.opacity;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/core/infra/player_engine/player_engine.dart';
|
||||
import 'package:smplayer/features/player/widgets/track_selector_button.dart';
|
||||
|
||||
import '../../../helpers/fake_player_engine.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('音轨按钮由初始 tracks 决定显隐', (tester) async {
|
||||
final player = FakePlayerEngine(
|
||||
playing: true,
|
||||
tracks: const PlayerTracks(
|
||||
audio: [
|
||||
AudioTrack(id: '1'),
|
||||
AudioTrack(id: '2'),
|
||||
],
|
||||
),
|
||||
);
|
||||
addTearDown(player.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: AudioTracksButton(
|
||||
player: player,
|
||||
isPanelOpen: false,
|
||||
onTogglePanel: () {},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byTooltip('音轨'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('字幕按钮响应 tracks stream 更新', (tester) async {
|
||||
final player = FakePlayerEngine(playing: true);
|
||||
addTearDown(player.dispose);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: SubtitleTracksButton(
|
||||
player: player,
|
||||
embySubtitles: const [],
|
||||
isPanelOpen: false,
|
||||
onTogglePanel: () {},
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(find.byTooltip('字幕'), findsNothing);
|
||||
|
||||
player.addTracks(
|
||||
const PlayerTracks(subtitle: [SubtitleTrack(id: 'embedded')]),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byTooltip('字幕'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user