feat(player): 未就绪改由进度条展示加载态

This commit is contained in:
Zhou Weidong committed 2026-10-21 10:07:34 +08:00
1 parent 76cc52ad66
commit cf4b07aa69
12 files changed
+359 -167

No files matched your search

+2
View File
@@ -150,6 +150,8 @@ void main() {
tester.widget<Text>(find.byKey(const Key('rail-comments-count'))).data,
'12',
);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byKey(const Key('home-feed-progress-thumb')), findsNothing);
});
testWidgets('should_seek_and_open_player_from_feed_actions', (tester) async {
+93 -37
View File
@@ -16,55 +16,111 @@ void main() {
expect(seekPositionForFraction(1, duration), lessThan(duration));
});
testWidgets('should_preview_while_dragging_and_seek_on_release_when_slider_is_horizontal', (
testWidgets('should_show_loading_track_when_controller_is_missing', (
tester,
) async {
final video = ValueNotifier<VideoPlayerValue>(
const VideoPlayerValue(
duration: Duration(seconds: 12),
position: Duration(seconds: 3),
isInitialized: true,
),
);
addTearDown(video.dispose);
var started = 0;
Duration? target;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
width: 300,
child: SeekProgressBar(
valueListenable: video,
semanticsLabel: 'Seek video',
onScrubStart: () => started++,
onSeek: (position) async {
target = position;
},
),
),
body: SeekProgressBar(
valueListenable: null,
semanticsLabel: 'Seek video',
),
),
),
);
final gesture = await tester.startGesture(
tester.getCenter(find.byType(Slider)),
);
await gesture.moveBy(const Offset(120, 0));
await tester.pump();
expect(started, 1);
expect(target, isNull);
expect(find.textContaining('/ 00:12'), findsOneWidget);
await gesture.up();
await tester.pumpAndSettle();
expect(target, isNotNull);
expect(target!, greaterThan(const Duration(seconds: 3)));
expect(target!, lessThan(const Duration(seconds: 12)));
expect(find.textContaining('/ 00:12'), findsNothing);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
});
testWidgets('should_switch_between_loading_track_and_slider', (tester) async {
final video = ValueNotifier<VideoPlayerValue>(
const VideoPlayerValue(
duration: Duration(seconds: 12),
position: Duration(seconds: 3),
isInitialized: true,
isBuffering: true,
),
);
addTearDown(video.dispose);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: SeekProgressBar(
valueListenable: video,
semanticsLabel: 'Seek video',
onSeek: (_) async {},
),
),
),
);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
expect(find.textContaining('00:12'), findsNothing);
video.value = const VideoPlayerValue(
duration: Duration(seconds: 12),
position: Duration(seconds: 3),
isInitialized: true,
);
await tester.pump();
expect(find.byKey(const Key('progress-loading')), findsNothing);
expect(find.byType(Slider), findsOneWidget);
});
testWidgets(
'should_preview_while_dragging_and_seek_on_release_when_slider_is_horizontal',
(tester) async {
final video = ValueNotifier<VideoPlayerValue>(
const VideoPlayerValue(
duration: Duration(seconds: 12),
position: Duration(seconds: 3),
isInitialized: true,
),
);
addTearDown(video.dispose);
var started = 0;
Duration? target;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
width: 300,
child: SeekProgressBar(
valueListenable: video,
semanticsLabel: 'Seek video',
onScrubStart: () => started++,
onSeek: (position) async {
target = position;
},
),
),
),
),
),
);
final gesture = await tester.startGesture(
tester.getCenter(find.byType(Slider)),
);
await gesture.moveBy(const Offset(120, 0));
await tester.pump();
expect(started, 1);
expect(target, isNull);
expect(find.textContaining('/ 00:12'), findsOneWidget);
await gesture.up();
await tester.pumpAndSettle();
expect(target, isNotNull);
expect(target!, greaterThan(const Duration(seconds: 3)));
expect(target!, lessThan(const Duration(seconds: 12)));
expect(find.textContaining('/ 00:12'), findsNothing);
},
);
testWidgets('should_show_time_only_while_dragging_when_seek_bar_is_compact', (
tester,
) async {
@@ -0,0 +1,53 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/theme/app_colors.dart';
import 'package:fruitshorts/pages/player/widgets/loading_progress_track.dart';
void main() {
testWidgets('should_move_highlight_while_loading', (tester) async {
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
addTearDown(
() => tester.binding.handleAppLifecycleStateChanged(
AppLifecycleState.paused,
),
);
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(width: 240, child: LoadingProgressTrack(height: 4)),
),
),
),
);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(
tester
.widget<ColoredBox>(find.byKey(const Key('progress-loading-track')))
.color,
Colors.white24,
);
expect(
tester
.widget<ColoredBox>(
find.byKey(const Key('progress-loading-highlight')),
)
.color,
AppColors.blue,
);
final initialLeft = tester
.getTopLeft(find.byKey(const Key('progress-loading-highlight')))
.dx;
await tester.pump(const Duration(milliseconds: 300));
final movedLeft = tester
.getTopLeft(find.byKey(const Key('progress-loading-highlight')))
.dx;
expect(movedLeft, greaterThan(initialLeft));
expect(tester.getSize(find.byKey(const Key('progress-loading'))).height, 4);
});
}
+12 -42
View File
@@ -18,7 +18,6 @@ import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart';
import 'package:fruitshorts/core/data/services/playback_session.dart';
import 'package:fruitshorts/core/theme/app_colors.dart';
import 'package:fruitshorts/core/widgets/remote_image.dart';
import 'package:fruitshorts/pages/auth/auth_view.dart';
import 'package:fruitshorts/pages/player/widgets/player_center_toggle.dart';
import 'package:fruitshorts/pages/player/widgets/seek_progress_bar.dart';
@@ -132,15 +131,9 @@ void main() {
expect(player.playing, isTrue);
});
testWidgets('should_fall_back_to_black_when_poster_is_empty', (tester) async {
await _pumpApp(
tester,
catalog: FakeCatalogRepository(dramas: const [_noCoverDrama]),
);
await _openSeriesPlayer(
tester,
cardKey: const Key('home-drama-card-no-cover-demo'),
);
testWidgets('should_keep_video_surface_background_black', (tester) async {
await _pumpApp(tester);
await _openSeriesPlayer(tester);
expect(
tester
@@ -150,6 +143,8 @@ void main() {
.color,
Colors.black,
);
expect(find.byKey(const Key('player-fallback-cover')), findsNothing);
expect(find.byKey(const Key('player-fallback-scrim')), findsNothing);
});
testWidgets('should_gate_comments_before_opening_sheet_when_signed_out', (
@@ -415,19 +410,9 @@ void main() {
expect(find.byKey(const Key('player-background')), findsNothing);
final fallback = find.byKey(const Key('player-fallback-background'));
expect(fallback, findsOneWidget);
expect(find.byKey(const Key('player-fallback-cover')), findsOneWidget);
expect(
tester
.widget<RemoteImage>(find.byKey(const Key('player-fallback-cover')))
.fallbackColor,
Colors.black,
);
expect(
tester
.widget<ColoredBox>(find.byKey(const Key('player-fallback-scrim')))
.color,
const Color(0x4D000000),
);
expect(tester.widget<ColoredBox>(fallback).color, Colors.black);
expect(find.byKey(const Key('player-fallback-cover')), findsNothing);
expect(find.byKey(const Key('player-fallback-scrim')), findsNothing);
expect(
tester
.widget<Scaffold>(find.byKey(const Key('player-scaffold')))
@@ -476,7 +461,8 @@ void main() {
tester.getSize(find.byKey(const Key('player-bottom-clear-screen'))),
const Size(40, 40),
);
expect(tester.widget<Slider>(find.byType(Slider)).padding, EdgeInsets.zero);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
expect(bottom.height, lessThanOrEqualTo(200));
expect(bottom.top, greaterThanOrEqualTo(screenHeight * 0.78));
@@ -1092,7 +1078,8 @@ void _expectFullscreenOverlay(WidgetTester tester) {
expect(find.byKey(const Key('player-pip')), findsNothing);
expect(find.byKey(const Key('player-rail-comments')), findsOneWidget);
expect(find.byKey(const Key('player-fullscreen-toggle')), findsNothing);
expect(find.byType(Slider), findsOneWidget);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
expect(find.byKey(const Key('player-title')), findsNothing);
expect(find.byKey(const Key('player-subtitle')), findsNothing);
expect(find.byKey(const Key('player-genre-chip')), findsNothing);
@@ -1211,20 +1198,3 @@ const _lockedDrama = Drama(
),
],
);
const _noCoverDrama = Drama(
id: 'no-cover-demo',
title: 'No Cover Demo',
synopsis: 'No cover synopsis',
posterUrl: '',
detailLoaded: true,
episodes: [
Episode(
id: 'no-cover-demo-1',
number: 1,
title: 'No Cover Episode',
isFree: true,
videoUrl: 'https://example.test/no-cover-demo-1.mp4',
),
],
);
+13 -5
View File
@@ -12,8 +12,9 @@ void main() {
) async {
await _pumpSurface(tester);
expect(find.byKey(const Key('player-fallback-background')), findsOneWidget);
expect(find.byKey(const Key('player-fallback-cover')), findsOneWidget);
expect(_fallbackColor(tester), Colors.black);
expect(find.byKey(const Key('player-fallback-cover')), findsNothing);
expect(find.byKey(const Key('player-fallback-scrim')), findsNothing);
expect(_opacity(tester), 0);
expect(find.byKey(const Key('player-debug-video')), findsNothing);
});
@@ -48,7 +49,8 @@ void main() {
expect(halfway, lessThan(1));
await tester.pump(const Duration(milliseconds: 100));
expect(_fadeValue(tester), 1);
expect(find.byKey(const Key('player-fallback-background')), findsOneWidget);
expect(_fallbackColor(tester), Colors.black);
expect(find.byKey(const Key('player-fallback-cover')), findsNothing);
expect(find.byKey(const Key('player-debug-video')), findsNothing);
});
@@ -62,7 +64,8 @@ void main() {
expect(find.byKey(const Key('player-video-error')), findsOneWidget);
expect(find.text('No route to host'), findsOneWidget);
expect(find.byKey(const Key('player-fallback-background')), findsOneWidget);
expect(_fallbackColor(tester), Colors.black);
expect(find.byKey(const Key('player-fallback-cover')), findsNothing);
expect(_opacity(tester), 0);
expect(find.byKey(const Key('player-debug-video')), findsNothing);
});
@@ -82,7 +85,6 @@ Future<VideoPlayerController> _pumpSurface(
home: Scaffold(
body: PlayerVideoSurface(
controller: controller,
posterUrl: '/files/poster.jpg',
videoUrl: controller.dataSource,
theater: false,
onTap: () {},
@@ -94,6 +96,12 @@ Future<VideoPlayerController> _pumpSurface(
return controller;
}
Color _fallbackColor(WidgetTester tester) {
return tester
.widget<ColoredBox>(find.byKey(const Key('player-fallback-background')))
.color;
}
double _opacity(WidgetTester tester) {
return tester
.widget<AnimatedOpacity>(find.byKey(const Key('player-video-opacity')))
+2 -1
View File
@@ -185,7 +185,8 @@ void main() {
await tester.pumpAndSettle();
await _openTheaterPlayer(tester);
expect(find.byType(Slider), findsOneWidget);
expect(find.byKey(const Key('progress-loading')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
await tester.drag(find.byType(PageView), const Offset(0, -500));
await tester.pumpAndSettle();
expect(