feat(player): 新增卡片式播放器

This commit is contained in:
Zhou Weidong committed 2026-10-19 15:16:40 +08:00
1 parent ec163f905d
commit 689063a694
6 files changed
+1229 -4

No files matched your search

+169
View File
@@ -0,0 +1,169 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
import 'package:fruitshorts/app.dart';
import 'package:fruitshorts/core/data/models/comment.dart';
import 'package:fruitshorts/core/data/repositories/comment_repository.dart';
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart';
import 'package:fruitshorts/core/theme/app_colors.dart';
import '../support/fake_catalog.dart';
import '../support/fake_category.dart';
import '../support/fake_haptics.dart';
import '../support/fake_interaction_repositories.dart';
import '../support/fake_notice_repository.dart';
import '../support/widget_player.dart';
void main() {
setUp(() {
SharedPreferencesAsyncPlatform.instance =
InMemorySharedPreferencesAsync.empty();
});
testWidgets('should_render_card_player_progress_and_three_action_buttons', (
tester,
) async {
await _pumpApp(tester);
await _openCityLights(tester);
final frame = tester.widget<AspectRatio>(
find.byKey(const Key('card-player-video-frame')),
);
expect(frame.aspectRatio, closeTo(9 / 10, 0.001));
expect(find.byKey(const Key('player-back')), findsOneWidget);
expect(find.byKey(const Key('player-title')), findsOneWidget);
expect(find.byKey(const Key('player-more')), findsOneWidget);
expect(find.byKey(const Key('card-player-progress')), findsOneWidget);
expect(find.byKey(const Key('card-player-episodes')), findsOneWidget);
expect(find.byKey(const Key('card-player-comments')), findsOneWidget);
expect(find.byKey(const Key('card-player-next')), findsOneWidget);
final theme = tester.widget<SliderTheme>(
find.ancestor(
of: find.byKey(const Key('card-player-progress')),
matching: find.byType(SliderTheme),
),
);
expect(theme.data.trackHeight, 1.5);
expect(theme.data.activeTrackColor, AppColors.blue);
expect(theme.data.thumbColor, Colors.white);
expect(theme.data.inactiveTrackColor, Colors.white.withValues(alpha: 0.15));
final next = tester.widget<FilledButton>(
find.byKey(const Key('card-player-next')),
);
expect(next.onPressed, isNotNull);
await tester.tap(find.byKey(const Key('card-player-next')));
await tester.pumpAndSettle();
expect(
tester.widget<Text>(find.byKey(const Key('player-title'))).data,
contains('Episode 2'),
);
expect(tester.takeException(), isNull);
});
testWidgets('should_disable_next_episode_on_the_last_episode', (
tester,
) async {
await _pumpApp(tester);
await _openCityLights(tester);
for (var index = 0; index < 6; index++) {
await tester.tap(find.byKey(const Key('card-player-next')));
await tester.pumpAndSettle();
}
expect(
tester.widget<Text>(find.byKey(const Key('player-title'))).data,
contains('Episode 7'),
);
final next = tester.widget<FilledButton>(
find.byKey(const Key('card-player-next')),
);
expect(next.onPressed, isNull);
expect(tester.takeException(), isNull);
});
testWidgets('should_show_featured_comment_when_comments_exist', (
tester,
) async {
await _pumpApp(
tester,
comments: FakeCommentRepository(
pages: const [
CommentPage(
comments: [
DramaComment(
id: 'c1',
dramaId: 'city-lights-demo',
episodeId: '0',
parentId: '0',
rootId: '0',
userId: '9',
uid: 'U9',
nickname: 'Lina',
avatarUrl: '',
content: 'The banquet scene gave me chills.',
status: 'approved',
auditReason: '',
likeCount: 428,
replyCount: 0,
reportCount: 0,
createdAt: null,
mine: false,
liked: false,
),
],
),
],
),
);
await _openCityLights(tester);
expect(find.byKey(const Key('player-featured-comment')), findsOneWidget);
expect(find.text('Lina'), findsOneWidget);
expect(find.text('428'), findsOneWidget);
expect(find.byKey(const Key('player-comments-view-all')), findsOneWidget);
await tester.tap(find.byKey(const Key('player-comments-view-all')));
await tester.pumpAndSettle();
expect(find.text('The banquet scene gave me chills.'), findsWidgets);
});
}
Future<void> _openCityLights(WidgetTester tester) async {
await tester.tap(find.byKey(const Key('tab-discover')));
await tester.pumpAndSettle();
await tester.tap(find.text('City Lights & Velvet Nights'));
await tester.pumpAndSettle();
}
Future<void> _pumpApp(
WidgetTester tester, {
CommentRepository? comments,
}) async {
tester.view.physicalSize = const Size(390, 844);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final catalog = FakeCatalogRepository();
await tester.pumpWidget(
LumaDramaApp(
playerFactory: createWidgetPlayer,
catalogRepository: catalog,
categoryRepository: FakeCategoryRepository(catalog: catalog),
watchHistoryRepository: InMemoryWatchHistoryRepository(),
favoriteRepository: InMemoryFavoriteRepository(cards: catalog.dramas),
playbackRepository: FakePlaybackRepository(),
commentRepository: comments ?? FakeCommentRepository(),
interactionRepository: FakeInteractionRepository(),
noticeRepository: FakeNoticeRepository(),
haptics: FakeHaptics(),
),
);
await tester.pumpAndSettle();
}