feat(flutter): 首页改为两列全部剧目网格
This commit is contained in:
1 parent
99f64ab870
commit
cf03178cc5
11 files changed
+498
-230
No files matched your search
@@ -0,0 +1,245 @@
|
||||
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/content_category.dart';
|
||||
import 'package:fruitshorts/core/data/models/drama.dart';
|
||||
import 'package:fruitshorts/core/data/models/home_feed.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/category_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/widgets/remote_image.dart';
|
||||
|
||||
import '../support/fake_catalog.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_show_all_dramas_in_two_column_sliver_grid_without_continue_watching',
|
||||
(tester) async {
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await _pumpApp(tester, categoryRepository: _GridCategoryRepository());
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Continue Watching'), findsNothing);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
|
||||
final grid = tester.widget<SliverGrid>(
|
||||
find.byKey(const Key('home-all-dramas-grid')),
|
||||
);
|
||||
final delegate =
|
||||
grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
|
||||
expect(delegate.crossAxisCount, 2);
|
||||
expect(delegate.crossAxisSpacing, 12);
|
||||
expect(delegate.mainAxisSpacing, 16);
|
||||
expect(delegate.childAspectRatio, closeTo(2 / 3, 0.001));
|
||||
expect(
|
||||
tester
|
||||
.widget<SliverPadding>(
|
||||
find.byKey(const Key('home-all-dramas-section')),
|
||||
)
|
||||
.padding,
|
||||
const EdgeInsets.symmetric(horizontal: 16),
|
||||
);
|
||||
expect(find.byType(GridView), findsNothing);
|
||||
expect(find.byType(CustomScrollView), findsOneWidget);
|
||||
expect(find.byType(RemoteImage), findsWidgets);
|
||||
|
||||
final cover = tester.widget<AspectRatio>(
|
||||
find.byKey(const Key('home-drama-cover-city-lights-demo')),
|
||||
);
|
||||
expect(cover.aspectRatio, closeTo(2 / 3, 0.001));
|
||||
expect(
|
||||
tester
|
||||
.widget<Text>(
|
||||
find.byKey(const Key('home-drama-title-city-lights-demo')),
|
||||
)
|
||||
.maxLines,
|
||||
2,
|
||||
);
|
||||
expect(
|
||||
tester
|
||||
.widget<Text>(
|
||||
find.byKey(const Key('home-drama-genre-city-lights-demo')),
|
||||
)
|
||||
.maxLines,
|
||||
1,
|
||||
);
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('should_update_grid_when_category_is_selected', (tester) async {
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await _pumpApp(tester, categoryRepository: _GridCategoryRepository());
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('The Signal'), findsOneWidget);
|
||||
expect(find.text('City Lights & Velvet Nights'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Romance'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('The Signal'), findsNothing);
|
||||
expect(find.text('City Lights & Velvet Nights'), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('home-drama-card-the-signal-demo')),
|
||||
findsNothing,
|
||||
);
|
||||
expect(
|
||||
find.byKey(const Key('home-drama-card-city-lights-demo')),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('should_keep_empty_messages_when_feed_has_no_dramas', (
|
||||
tester,
|
||||
) async {
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await _pumpApp(
|
||||
tester,
|
||||
categoryRepository: _GridCategoryRepository(
|
||||
discoverFeed: const HomeFeed(),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.text('No matching dramas.'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Romance'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('No dramas in this category yet.'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('should_show_retry_when_category_feed_fails', (tester) async {
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await _pumpApp(tester, categoryRepository: _FailingCategoryRepository());
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.text('Categories could not be loaded.'), findsOneWidget);
|
||||
expect(find.text('Retry'), findsOneWidget);
|
||||
expect(find.byKey(const Key('home-all-dramas-grid')), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('should_fit_two_column_grid_on_compact_screen', (tester) async {
|
||||
tester.view.physicalSize = const Size(320, 568);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await _pumpApp(tester, categoryRepository: _GridCategoryRepository());
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.scrollUntilVisible(
|
||||
find.byKey(const Key('home-drama-card-city-lights-demo')),
|
||||
180,
|
||||
scrollable: find.byType(Scrollable).last,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.text('City Lights & Velvet Nights'), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _pumpApp(
|
||||
WidgetTester tester, {
|
||||
required CategoryRepository categoryRepository,
|
||||
}) async {
|
||||
final catalog = FakeCatalogRepository();
|
||||
await tester.pumpWidget(
|
||||
LumaDramaApp(
|
||||
playerFactory: createWidgetPlayer,
|
||||
catalogRepository: catalog,
|
||||
categoryRepository: categoryRepository,
|
||||
watchHistoryRepository: InMemoryWatchHistoryRepository(),
|
||||
favoriteRepository: InMemoryFavoriteRepository(),
|
||||
playbackRepository: FakePlaybackRepository(),
|
||||
commentRepository: FakeCommentRepository(),
|
||||
interactionRepository: FakeInteractionRepository(),
|
||||
noticeRepository: FakeNoticeRepository(),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
class _GridCategoryRepository implements CategoryRepository {
|
||||
_GridCategoryRepository({HomeFeed? discoverFeed})
|
||||
: discoverFeed = discoverFeed ?? _defaultDiscoverFeed;
|
||||
|
||||
final HomeFeed discoverFeed;
|
||||
|
||||
@override
|
||||
Future<List<ContentCategory>> fetchCategories() async => const [
|
||||
ContentCategory(id: '7', name: 'Romance'),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<HomeFeed> fetchDiscoverFeed() async => discoverFeed;
|
||||
}
|
||||
|
||||
class _FailingCategoryRepository implements CategoryRepository {
|
||||
@override
|
||||
Future<List<ContentCategory>> fetchCategories() async => const [
|
||||
ContentCategory(id: '7', name: 'Romance'),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<HomeFeed> fetchDiscoverFeed() async {
|
||||
throw StateError('discover feed unavailable');
|
||||
}
|
||||
}
|
||||
|
||||
final _defaultDiscoverFeed = HomeFeed(
|
||||
sections: [
|
||||
FeedSection(code: 'hot', title: 'Hot', dramas: demoDramas),
|
||||
FeedSection(
|
||||
code: 'category-7',
|
||||
title: 'Romance',
|
||||
dramas: [
|
||||
Drama(
|
||||
id: 'city-lights-demo',
|
||||
title: 'City Lights & Velvet Nights',
|
||||
synopsis: 'City Lights & Velvet Nights synopsis',
|
||||
posterUrl: '/files/city-lights-demo.png',
|
||||
genre: 'Urban Romance',
|
||||
detailLoaded: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
+11
-11
@@ -155,7 +155,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(appUnderTest());
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
@@ -186,15 +186,15 @@ void main() {
|
||||
.active,
|
||||
isFalse,
|
||||
);
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byKey(const Key('drawer-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(
|
||||
Navigator.of(tester.element(find.text('Continue Watching'))).canPop(),
|
||||
Navigator.of(tester.element(find.text('All Dramas'))).canPop(),
|
||||
isFalse,
|
||||
);
|
||||
},
|
||||
@@ -313,7 +313,7 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('For You'), findsOneWidget);
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.text('Rewards'), findsOneWidget);
|
||||
expect(find.text(r'$ 0'), findsOneWidget);
|
||||
expect(find.text('Urban Romance', skipOffstage: false), findsOneWidget);
|
||||
@@ -345,10 +345,10 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Home'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.byTooltip('Search'), findsNothing);
|
||||
expect(
|
||||
Navigator.of(tester.element(find.text('Continue Watching'))).canPop(),
|
||||
Navigator.of(tester.element(find.text('All Dramas'))).canPop(),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
@@ -365,10 +365,10 @@ void main() {
|
||||
|
||||
await tester.tap(find.byKey(const Key('tab-discover')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(find.byTooltip('Search'), findsNothing);
|
||||
expect(
|
||||
Navigator.of(tester.element(find.text('Continue Watching'))).canPop(),
|
||||
Navigator.of(tester.element(find.text('All Dramas'))).canPop(),
|
||||
isFalse,
|
||||
);
|
||||
await tester.tap(find.byKey(const Key('tab-my-list')));
|
||||
@@ -564,7 +564,7 @@ void main() {
|
||||
await tester.pumpWidget(appUnderTest());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Quick access'), findsOneWidget);
|
||||
@@ -572,7 +572,7 @@ void main() {
|
||||
await tester.binding.handlePopRoute();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Quick access'), findsNothing);
|
||||
expect(find.text('Continue Watching'), findsOneWidget);
|
||||
expect(find.text('All Dramas'), findsOneWidget);
|
||||
expect(
|
||||
Navigator.of(
|
||||
tester.element(find.byKey(const Key('home-tabs-bar'))),
|
||||
|
||||
Reference in new issue
Block a user