feat(detail): 重做详情页视觉结构
This commit is contained in:
1 parent
4553606ec2
commit
ec163f905d
9 files changed
+1153
-239
No files matched your search
@@ -0,0 +1,151 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:fruitshorts/core/data/models/drama.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/data/services/catalog_controller.dart';
|
||||
import 'package:fruitshorts/core/data/services/favorite_controller.dart';
|
||||
import 'package:fruitshorts/core/data/services/interaction_controller.dart';
|
||||
import 'package:fruitshorts/core/platform/haptics.dart';
|
||||
import 'package:fruitshorts/core/theme/app_theme.dart';
|
||||
import 'package:fruitshorts/l10n/app_localizations.dart';
|
||||
import 'package:fruitshorts/pages/drama_detail/drama_detail_view.dart';
|
||||
|
||||
import '../support/fake_catalog.dart';
|
||||
import '../support/fake_haptics.dart';
|
||||
import '../support/fake_interaction_repositories.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('should_render_hero_cta_synopsis_and_two_column_episode_grid', (
|
||||
tester,
|
||||
) async {
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await tester.pumpWidget(_host(_detailDrama()));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final hero = tester.widget<AspectRatio>(
|
||||
find.byKey(const Key('detail-hero')),
|
||||
);
|
||||
expect(hero.aspectRatio, closeTo(16 / 9, 0.001));
|
||||
expect(find.byKey(const Key('detail-cta')), findsOneWidget);
|
||||
expect(find.byKey(const Key('detail-favorite')), findsOneWidget);
|
||||
expect(find.byKey(const Key('detail-download')), findsOneWidget);
|
||||
expect(find.byKey(const Key('detail-episodes-range')), findsOneWidget);
|
||||
expect(find.byKey(const Key('detail-episode-chip-1')), findsOneWidget);
|
||||
expect(
|
||||
tester.getSize(find.byKey(const Key('detail-episode-chip-1'))),
|
||||
const Size(46, 44),
|
||||
);
|
||||
|
||||
final synopsis = tester.widget<Text>(
|
||||
find.byKey(const Key('detail-synopsis')),
|
||||
);
|
||||
expect(synopsis.maxLines, 2);
|
||||
await tester.tap(find.byKey(const Key('detail-synopsis-toggle')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
tester.widget<Text>(find.byKey(const Key('detail-synopsis'))).maxLines,
|
||||
100,
|
||||
);
|
||||
|
||||
final grid = tester.widget<SliverGrid>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('detail-episode-grid')),
|
||||
matching: find.byType(SliverGrid),
|
||||
),
|
||||
);
|
||||
final delegate =
|
||||
grid.gridDelegate as SliverGridDelegateWithFixedCrossAxisCount;
|
||||
expect(delegate.crossAxisCount, 2);
|
||||
expect(find.byKey(const Key('detail-episode-card-1')), findsOneWidget);
|
||||
expect(
|
||||
tester.getSize(find.byKey(const Key('detail-episode-thumb-1'))),
|
||||
const Size(96, 64),
|
||||
);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
testWidgets('should_fit_compact_viewport_when_detail_scrolls', (
|
||||
tester,
|
||||
) async {
|
||||
tester.view.physicalSize = const Size(320, 568);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
await tester.pumpWidget(_host(_detailDrama()));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.drag(
|
||||
find.byKey(const Key('detail-scroll')),
|
||||
const Offset(0, -520),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('detail-episode-card-3')), findsOneWidget);
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _host(Drama drama) {
|
||||
final catalog = FakeCatalogRepository(dramas: [drama]);
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
Provider<WatchHistoryRepository>.value(
|
||||
value: InMemoryWatchHistoryRepository(),
|
||||
),
|
||||
Provider<PlaybackRepository>.value(value: FakePlaybackRepository()),
|
||||
Provider<Haptics>.value(value: FakeHaptics()),
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => FavoriteController(InMemoryFavoriteRepository()),
|
||||
),
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => InteractionController(FakeInteractionRepository()),
|
||||
),
|
||||
ChangeNotifierProvider(create: (_) => CatalogController(catalog)..load()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
theme: AppTheme.dark(),
|
||||
locale: const Locale('en'),
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
home: DramaDetailPage(drama: drama),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Drama _detailDrama() {
|
||||
return Drama(
|
||||
id: 'detail-k25',
|
||||
title: 'Detail K25',
|
||||
synopsis:
|
||||
'She agreed to marry a mysterious stranger to save her family, '
|
||||
'until she discovered his secret identity and the city he controls.',
|
||||
posterUrl: '/files/detail-k25.png',
|
||||
genre: 'Urban Romance',
|
||||
category: 'Romance',
|
||||
totalEpisodes: 8,
|
||||
viewCount: 4800000,
|
||||
detailLoaded: true,
|
||||
episodes: [
|
||||
for (var number = 1; number <= 8; number++)
|
||||
Episode(
|
||||
id: 'detail-k25-$number',
|
||||
number: number,
|
||||
title: 'Episode $number',
|
||||
isFree: number == 1,
|
||||
durationSec: 135,
|
||||
locked: number > 1,
|
||||
videoUrl: number == 1 ? '/files/detail-k25-1.mp4' : '',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user