import 'package:flutter/material.dart'; import '../../core/theme/tokens.dart'; import '../home/home_screen.dart' show formatPop; import '../planet/planet_data.dart' show PlanetRepositoryFactory; import '../planet/planet_history_screen.dart'; import 'my_data.dart'; import 'widgets/my_cards.dart'; import '../../core/i18n/app_locale.dart'; /// 티어 정보 — 화면 대조 원장 F6 · Figma `373:633256`. /// /// 명세 `549:22185` — *티어별 이미지 · 티어명 · 기준치 · **티어가 낮은 순으로 소팅*** /// /// C-18 — 기준치는 **레벨 구간**이다. 누적 기여 POP 문턱과 칭호별 권한·보상은 적지 /// 않는다. Passport Tier(B-65)는 별개 체계라 따로 늘어놓는다. class TierInfoScreen extends StatelessWidget { const TierInfoScreen({super.key}); @override Widget build(BuildContext context) { // 시안 `373:633256` 한 줄 — 새싹 80 · 간격 17 · 이름 20/500 · 기준 12/400 #84868e · // 위아래 12 · 밑줄 #1b1c1c. Widget row(String label, String note, {bool sprout = true}) => Container( margin: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.symmetric(vertical: 12), decoration: const BoxDecoration( border: Border(bottom: BorderSide(color: Color(0xFF1B1C1C))), ), child: Row( children: [ SizedBox( width: 80, height: 80, child: sprout ? Image.asset('assets/figma/icon-tier-sprout.png') : null, ), const SizedBox(width: 17), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: myText(20, FontWeight.w500)), if (note.isNotEmpty) Text( note, style: myText( 12, FontWeight.w400, color: const Color(0xFF84868E), ), ), ], ), ), ], ), ); return Scaffold( appBar: AppBar(title: Text(context.l10n.tierInfoTitle)), body: ListView( padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), children: [ Text.rich( TextSpan( style: myText(18, FontWeight.w500), children: [ TextSpan(text: context.l10n.tierPromptPrefix), TextSpan( text: context.l10n.tierPromptRank, style: TextStyle(color: AppColors.cosmicAccent), ), TextSpan(text: context.l10n.tierPromptSuffix), ], ), ), const SizedBox(height: 20), // 낮은 순으로. LevelTitle 선언 순서가 곧 낮은 순이다. 기준치는 레벨 구간(C-18). for (final title in LevelTitle.values) row('${title.label} TIER', title.rangeLabel), // Passport Tier 는 레벨과 별개 체계다(B-65 · FR-MY-01). 시안에 없는 구획이다. Text('PASSPORT', style: myText(16, FontWeight.w600)), const SizedBox(height: 4), Text( context.l10n.tierPassportNote, style: myText(12, FontWeight.w400, color: const Color(0xFF84868E)), ), const SizedBox(height: 8), for (final tier in PassportTier.values) row(tier.label, '', sprout: false), ], ), ); } } /// 티어 상세 — 화면 대조 원장 F6 · Figma `494:16177`. /// /// 명세 `549:22206` — *갤럭시에서 선택된 기본 행성의 티어를 메인으로 상단에 위치 ·* /// *나머지 행성 티어는 티어 높은순으로 소팅* /// /// 칭호는 개인 레벨에서만 나오므로(C-18) 행성별로는 **그 팬덤 Passport Tier 와 기여 실적**을 보인다 /// (10/3 #10 사용자 × 팬덤). 탈퇴한 팬덤도 기록을 지우지 않고 아래에 둔다(9/21 5절 · FX §7.1 ARCHIVED). /// 아래 BADGE 는 별첨 1 ②-5 「배지 부여·프로필 표시」 — 앱 Figma 에 Badge 화면이 없어 이 화면 끝에 둔다. class TierDetailScreen extends StatelessWidget { const TierDetailScreen({ super.key, required this.tiers, this.badges = const [], this.planetRepository, }); final List tiers; final List badges; /// 행성 카드를 누르면 그 팬덤의 Passport History(팬덤 역사 · 내 기록)를 연다. null 이면 열지 않는다. final PlanetRepositoryFactory? planetRepository; /// 기본 행성이 맨 앞, 나머지는 가입 중 → 탈퇴 순, 같은 구분 안에서는 Tier · 기여 POP 높은 순. List get ordered { final primary = tiers.where((p) => p.isPrimary).toList(); final rest = tiers.where((p) => !p.isPrimary).toList() ..sort((a, b) { if (a.joined != b.joined) return a.joined ? -1 : 1; final byTier = b.passportTier.index.compareTo(a.passportTier.index); return byTier != 0 ? byTier : b.contributedPop.compareTo(a.contributedPop); }); return [...primary, ...rest]; } @override Widget build(BuildContext context) { final list = ordered; final top = list.fold( 0, (m, p) => p.contributedPop > m ? p.contributedPop : m, ); // 시안 `494:16177` — 기본 행성 카드(#19191c · 분홍 획) · 구분선 #2c2c2c · 나머지 카드. // 행성별 칭호는 두지 않는다(C-18) — 시안의 「GLOW TIER」 줄은 비우고 기여 실적만 그린다. return Scaffold( appBar: AppBar(title: const Text('TIER')), body: ListView( padding: const EdgeInsets.all(16), children: [ for (final (i, planet) in list.indexed) ...[ if (i > 0) const SizedBox(height: 16), InkWell( onTap: planetRepository == null || planet.fandomId.isEmpty ? null : () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => PlanetHistoryScreen( repository: planetRepository!(planet.fandomId), fandomName: planet.fandomName, ), ), ), child: _PlanetCard( planet: planet, progress: top == 0 ? 0 : planet.contributedPop / top, ), ), if (i == 0 && planet.isPrimary && list.length > 1) ...[ const SizedBox(height: 16), const SizedBox( height: 1, child: ColoredBox(color: MyColors.divider), ), ], ], if (badges.isNotEmpty) ...[ const SizedBox(height: 24), Text('BADGE', style: myText(16, FontWeight.w600)), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: [ for (final badge in badges) Chip(label: Text(badge.label, style: myText(12, FontWeight.w500))), ], ), ], ], ), ); } } /// 행성 한 장 — 행성 60 + 이름 12/600 · 진행 바 · 「누적 기여 / N POP」. class _PlanetCard extends StatelessWidget { const _PlanetCard({required this.planet, required this.progress}); final PlanetTier planet; final double progress; @override Widget build(BuildContext context) => Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: planet.isPrimary ? BoxDecoration( color: MyColors.card, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: AppColors.cosmicAccent), ) : null, child: Row( children: [ SizedBox( width: 60, child: Column( children: [ Image.asset( 'assets/figma/my-planet-1.png', width: 60, height: 60, ), Text( planet.fandomName, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontFamily: AppFonts.body, fontSize: 12, fontWeight: FontWeight.w600, height: 1, color: AppColors.onCosmic, ), ), ], ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'PASSPORT ${planet.passportTier.label}', style: myText( 14, FontWeight.w500, color: planet.joined ? AppColors.onCosmic : const Color(0xFF84868E), ), ), const SizedBox(height: 4), MyProgressBar(value: progress), const SizedBox(height: 8), Row( children: [ Text( context.l10n.tierTotalContribution, style: myText( 12, FontWeight.w500, color: AppColors.cosmicAccent, ), ), const Spacer(), Text( '${formatPop(planet.contributedPop)} POP', style: myText( 12, FontWeight.w500, color: AppColors.cosmicAccent, ), ), ], ), ], ), ), ], ), ); }