생성 때 고른 행성 형태·색 표시 · HOME 주간 정보
This commit is contained in:
@@ -333,8 +333,12 @@ class HomeSnapshot {
|
||||
required this.insides,
|
||||
this.items = const [],
|
||||
this.nebulas = const [],
|
||||
this.weekly,
|
||||
});
|
||||
|
||||
/// HOME 주간 정보(A-37 · HOME 정보위계 v1.0 §2 · §3). 소속 행성이 없으면 null.
|
||||
final HomeWeekly? weekly;
|
||||
|
||||
/// 활동 POP 잔액. 정책 설계서 §P-02 — 활동/지원 원장은 분리되어 있고
|
||||
/// 홈 상단에는 활동 POP 을 띄운다.
|
||||
final int popBalance;
|
||||
@@ -364,6 +368,87 @@ class HomeSnapshot {
|
||||
final List<ItemProduct> items;
|
||||
}
|
||||
|
||||
/// HOME 주간 정보 — 발주사 9/9 검토회신 2항 「행성의 주간 순위 · 이번 주 성장 정도 · 이번 주
|
||||
/// 기여량 및 기여 비율 · 보유 POP」(HOME 정보위계 v1.0 §2 의 2 · 3 · 6 · 7번). 값의 뜻은 §3(별첨 B):
|
||||
///
|
||||
/// - 순위는 **주간 공식 Snapshot**(`rankingSnapshots`, B-20)의 순위다 — 실시간 순위가 아니다.
|
||||
/// 변동은 직전 Snapshot 대비(C-43 「순위 동향 · 변동값」). 양수 = 올라감.
|
||||
/// - 이번 주 성장은 **두 축(Growth POP · sFPI)** 각각의 증분 — 단일 백분율로 합치지 않는다.
|
||||
/// - 기여 비율은 **행성 주간 성장 총량 대비 본인 비중**.
|
||||
/// - 보유 POP 은 **일반 POP / 기여 POP** 분리 표기.
|
||||
///
|
||||
/// 「이번 주」의 시작은 마지막 주간 Snapshot 시각(KST 월요일 00:10, Q-A11 임시값)이다. 그 시각의
|
||||
/// 행성 누계가 기준선이라 Snapshot 이 없거나 기준선 필드가 없는 옛 Snapshot 이면 그 값은 null.
|
||||
class HomeWeekly {
|
||||
const HomeWeekly({
|
||||
this.rank,
|
||||
this.rankChange,
|
||||
this.weekGrowthPop,
|
||||
this.weekSfpi,
|
||||
this.myWeekPop,
|
||||
this.myShare,
|
||||
required this.generalPop,
|
||||
required this.supportPop,
|
||||
});
|
||||
|
||||
final int? rank;
|
||||
final int? rankChange;
|
||||
final num? weekGrowthPop;
|
||||
final num? weekSfpi;
|
||||
/// 이번 주 내가 이 행성 성장에 보탠 Growth POP(`users/{uid}/growthEvents` 합). 못 읽으면 null.
|
||||
final num? myWeekPop;
|
||||
|
||||
/// 0~1. 행성 주간 성장이 0 이거나 모르면 null.
|
||||
final double? myShare;
|
||||
final int generalPop;
|
||||
final int supportPop;
|
||||
|
||||
/// Snapshot 두 개(최신 · 직전)의 `planets` 와 현재 행성 누계 · 내 이번 주 성장 기여로 만든다.
|
||||
factory HomeWeekly.from({
|
||||
required String fandomId,
|
||||
required List<Map<String, dynamic>> snapshots,
|
||||
required Map<String, dynamic> fandom,
|
||||
required num? myWeekPop,
|
||||
required Map<String, dynamic> wallet,
|
||||
}) {
|
||||
Map<String, dynamic>? entryOf(Map<String, dynamic>? snap) {
|
||||
final planets = snap?['planets'];
|
||||
if (planets is! List) return null;
|
||||
for (final p in planets) {
|
||||
if (p is Map && p['fandomId'] == fandomId) return p.cast<String, dynamic>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final latest = entryOf(snapshots.firstOrNull);
|
||||
final previous = entryOf(snapshots.length > 1 ? snapshots[1] : null);
|
||||
int? rankOf(Map<String, dynamic>? e) =>
|
||||
e?['rank'] is int ? e!['rank'] as int : null;
|
||||
num? delta(String key) {
|
||||
final now = fandom[key];
|
||||
final base = latest?[key];
|
||||
return now is num && base is num ? now - base : null;
|
||||
}
|
||||
|
||||
final rank = rankOf(latest);
|
||||
final prev = rankOf(previous);
|
||||
final weekGrowth = delta('growthPop');
|
||||
int intOf(dynamic v) => v is num ? v.toInt() : 0;
|
||||
return HomeWeekly(
|
||||
rank: rank,
|
||||
rankChange: rank != null && prev != null ? prev - rank : null,
|
||||
weekGrowthPop: weekGrowth,
|
||||
weekSfpi: delta('sfpi'),
|
||||
myWeekPop: myWeekPop,
|
||||
myShare: weekGrowth != null && weekGrowth > 0 && myWeekPop != null
|
||||
? (myWeekPop / weekGrowth).clamp(0.0, 1.0).toDouble()
|
||||
: null,
|
||||
generalPop: intOf(wallet['activityBalance']),
|
||||
supportPop: intOf(wallet['supportBalance']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 아이템(Hero Gift) 상품 한 줄 — 사본 `아이템 구입`(`252:160233`) 카드.
|
||||
///
|
||||
/// 구매하면 구매자에게 기여 POP, 팬덤 Drop Pool 에 같은 수량의 일반 POP 이 생긴다
|
||||
|
||||
Reference in New Issue
Block a user