Passport Tier 팬덤 단위 · 활동 Badge · 진화 Emblem · Eclipse 참여 기록

This commit is contained in:
Sn-Kinos
2026-10-05 22:09:10 +09:00
parent 71ec17dc3c
commit cc0f2fb292
36 changed files with 877 additions and 81 deletions
+58 -7
View File
@@ -2,6 +2,8 @@ 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';
@@ -98,17 +100,32 @@ class TierInfoScreen extends StatelessWidget {
/// 명세 `549:22206` — *갤럭시에서 선택된 기본 행성의 티어를 메인으로 상단에 위치 ·*
/// *나머지 행성 티어는 티어 높은순으로 소팅*
///
/// 칭호는 개인 레벨에서만 나오므로(C-18) 행성별로는 **기여 실적(POP)만** 보인다.
/// 칭호는 개인 레벨에서만 나오므로(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});
const TierDetailScreen({
super.key,
required this.tiers,
this.badges = const [],
this.planetRepository,
});
final List<PlanetTier> tiers;
final List<MyBadge> badges;
/// 기본 행성이 맨 앞, 나머지는 기여 POP 높은 순.
/// 행성 카드를 누르면 그 팬덤의 Passport History(팬덤 역사 · 내 기록)를 연다. null 이면 열지 않는다.
final PlanetRepositoryFactory? planetRepository;
/// 기본 행성이 맨 앞, 나머지는 가입 중 → 탈퇴 순, 같은 구분 안에서는 Tier · 기여 POP 높은 순.
List<PlanetTier> get ordered {
final primary = tiers.where((p) => p.isPrimary).toList();
final rest = tiers.where((p) => !p.isPrimary).toList()
..sort((a, b) => b.contributedPop.compareTo(a.contributedPop));
..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];
}
@@ -128,9 +145,21 @@ class TierDetailScreen extends StatelessWidget {
children: [
for (final (i, planet) in list.indexed) ...[
if (i > 0) const SizedBox(height: 16),
_PlanetCard(
planet: planet,
progress: top == 0 ? 0 : planet.contributedPop / top,
InkWell(
onTap: planetRepository == null || planet.fandomId.isEmpty
? null
: () => Navigator.of(context).push(
MaterialPageRoute<void>(
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),
@@ -140,6 +169,19 @@ class TierDetailScreen extends StatelessWidget {
),
],
],
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))),
],
),
],
],
),
);
@@ -194,6 +236,15 @@ class _PlanetCard extends StatelessWidget {
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(