@Tags(['design']) library; import 'package:fancake/core/data/repositories.dart'; import 'package:fancake/core/router/app_router.dart'; import 'package:fancake/core/theme/app_theme.dart'; import 'package:fancake/features/auth/auth_repository.dart'; import 'package:fancake/features/eclipse/eclipse_data.dart'; import 'package:fancake/features/galaxy/galaxy_search_screen.dart'; import 'package:fancake/features/planet/fpi_ranking_screen.dart'; import 'package:fancake/features/planet/lounge_post_screens.dart'; import 'package:fancake/features/planet/moderation.dart'; import 'package:fancake/features/planet/planet_data.dart'; import 'package:fancake/features/planet/planet_detail_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../eclipse_stubs.dart'; import 'design_match_test.dart' as base; /// 디자인 일치 2단계 **그룹 B**(F2 갤럭시 · F3 행성/성운 상세) 렌더. /// /// 공유 하네스([base.main])를 그대로 돌리되 shots 만 이 그룹 것으로 바꾼다. /// 표본은 Figma 사본 문구와 같게 여기서 만든다(공유 표본 저장소는 건드리지 않는다). /// /// 실행: `DESIGN_MATCH_OUT=<폴더> fvm flutter test --tags design test/design_match/b_test.dart` void main() { base.shots ..clear() ..addAll(_shots); base.main(); } Future _settle(WidgetTester t) async { for (var i = 0; i < 6; i++) { await t.pump(const Duration(milliseconds: 300)); } } Future _tap(WidgetTester t, Finder f) async { await t.tap(f.first, warnIfMissed: false); await _settle(t); } Future _overlay( WidgetTester t, void Function(BuildContext c) open, ) async { open(t.element(find.byType(Scaffold).last)); await _settle(t); } final _now = DateTime.now(); const _photo = 'assets/figma/lounge-post-sample.png'; LoungePost _post( String author, Duration ago, String text, { int likes = 8, int comments = 24, List images = const [], String? photo, Duration? video, }) => LoungePost( id: author, authorName: author, createdAt: _now.subtract(ago), title: '', body: text, likes: likes, comments: comments, images: images, authorPhoto: photo, videoDuration: video, ); /// F3-05 `244:22509` — 첫 댓글 전 글. final _hongPost = _post( 'BTS_Hong', Duration.zero, '안녕하세요! BTS 팬이에요!', likes: 0, comments: 0, images: const [_photo], photo: 'assets/figma/avatar-hong.png', video: const Duration(seconds: 36), ); /// F3-07 `252:163306` — 사진 세 장 글. final _ilaPost = _post( 'ILA_WITH', const Duration(days: 3), '여러분 지금 미국 컴백 무대 보셨나요?\n사진 공유해드릴게요 모두 온라인 직관하세요', likes: 8, comments: 5, images: const [_photo, _photo, _photo], ); FpiScore _score(FpiMetric m, int v, int rank, int trend) => FpiScore(metric: m, value: v, rank: rank, trend: trend, myTopPercent: 1); /// 시안 수치 그대로의 행성 · 성운 상세. class _FigmaPlanet extends SamplePlanetRepository { const _FigmaPlanet(); @override Future load({required bool nebula}) async => nebula ? PlanetDetail( fandomId: 'bts-rm', name: 'BTS_RM', isNebula: true, stage: 0, totalFpi: 0, members: 1, ownerName: 'BTS_Hong', ownerPhoto: 'assets/figma/avatar-hong.png', scores: const [], posts: const [], ) : PlanetDetail( fandomId: 'bts', name: 'BTS', isNebula: false, totalFpi: 1220, members: 850, ownerName: 'BTS_Maker', ownerPhoto: 'assets/figma/avatar-maker.png', scores: [ _score(FpiMetric.bpm, 34200, 2, 1), _score(FpiMetric.health, 1180000, 4, -1), _score(FpiMetric.referral, 34200, 3, 0), _score(FpiMetric.contribution, 450100, 2, 2), _score(FpiMetric.community, 1000, 4, -2), ], posts: [ _post( 'arrrmy_', const Duration(minutes: 3), 'I love BTS sooooo much 😭😭😭', ), _post( 'AR_NNJO', const Duration(hours: 3), 'NAMJOON so handsome isn’t it???', images: const [_photo], ), _ilaPost, ], ); @override Future> morePosts({ required int offset, int limit = 5, }) async => const []; @override Future planetRanking({ required FpiMetric metric, int limit = 30, }) async => FpiRanking( mine: const FpiRankRow( rank: 24, id: 'bts', name: 'BTS', value: 34200, change: 12, isMine: true, ), rows: _rows(const [ (1, 'Bigbnag', 782200, 1), (2, 'NewJeans', 703200, 0), (3, 'Blackpink', 689700, 1), (5, 'Twice', 531100, -1), (6, 'ITZY', 527800, 2), (7, 'Aespa', 422400, 3), (8, 'Seventeen', 329600, 8), (9, 'Eighteen', 311200, -1), (10, 'Nineteen', 134500, 1), ]), ); @override Future userRanking({ required FpiMetric metric, required String fandomId, int limit = 30, }) async => FpiRanking( mine: const FpiRankRow( rank: 82, id: 'me', name: 'BTS_Hong', value: 3, change: 1, ), rows: _rows(const [ (1, 'GLAS_SMILE', 3000, 0), (2, 'Suyom_mo', 2600, 0), (3, 'Bool_huuu', 1400, 0), (4, 'Wachooo', 1200, 1), (5, 'Jeans_Bewn', 1200, 0), (6, 'pinkyy', 1100, 1), (7, 'T_T', 1000, -1), (8, 'Yogi_ITZY', 98, 2), ]), ); } List _rows(List<(int, String, int, int)> t) => [ for (final (rank, name, value, change) in t) FpiRankRow(rank: rank, id: name, name: name, value: value, change: change), ]; Widget _detail({bool nebula = false}) => PlanetDetailScreen( nebula: nebula, repository: const _FigmaPlanet(), eclipse: const NoEclipseRepository(), ); const _report = ModerationTarget( authorName: 'BTS_Hong', title: '공방 신청 꿀팁 공유합니다.', ); /// 이클립스가 없는 표본 저장소. 탭 화면은 공유 하네스가 저장소를 직접 만들어서 /// 바꿀 수 없으므로, 탭 셸을 통째로 한 번 더 띄운다(하단 탭까지 그려진다). class _NoEclipseRepos extends Repositories { _NoEclipseRepos() : super(live: false); @override EclipseRepository get eclipse => const NoEclipseRepository(); } Widget _tab(String path) { final router = buildRouter( AuthRepository()..signInWithMockSession(), repositories: _NoEclipseRepos(), )..go(path); return MaterialApp.router( theme: buildAppTheme(), debugShowCheckedModeBanner: false, routerConfig: router, ); } final _shots = [ // F2 갤럭시 base.Shot('F2-01', build: (_) async => _tab('/galaxy')), base.Shot( 'F2-02', build: (r) async => GalaxySearchScreen(repository: r.galaxy), ), // F3 행성/성운 상세 base.Shot('F3-01', h: 1042, build: (_) async => _detail(nebula: true)), base.Shot( 'F3-02', build: (_) async => const ReportScreen( target: ModerationTarget(authorName: 'BTS_Hong', title: 'BTS_RM'), ), ), base.Shot( 'F3-03', build: (_) async => _detail(nebula: true), after: (t) => _overlay( t, (c) => confirmBlock(c, 'BTS_Hong', message: '이 성운을 차단할까요?'), ), ), base.Shot('F3-04', h: 1243, build: (_) async => _detail()), base.Shot('F3-05', build: (_) async => LoungePostScreen(post: _hongPost)), base.Shot('F3-06', build: (_) async => const ReportScreen(target: _report)), base.Shot( 'F3-07', build: (_) async => LoungePostScreen(post: _ilaPost), after: (t) => _overlay(t, (c) => confirmBlock(c, 'ILA_WITH')), ), base.Shot('F3-09', build: (_) async => const LoungeComposeScreen()), base.Shot( 'F3-10', build: (_) async => const FpiRankingScreen( metric: FpiMetric.bpm, repository: _FigmaPlanet(), ), ), base.Shot( 'F3-11', build: (_) async => const FpiUserRankingScreen( metric: FpiMetric.bpm, fandomId: 'bts', planetName: 'BTS', repository: _FigmaPlanet(), ), ), base.Shot( 'F3-12', build: (_) async => _detail(), after: (t) async { await _tap(t, find.text('팬덤 라운지')); await _tap( t, find.image(const AssetImage('assets/figma/icon-post-more.png')), ); }, ), base.Shot('F3-13', build: (_) async => const ReportScreen(target: _report)), ];