UX·FX v1.5 — 햅틱 단계 · 라이브 띠 · HERO 전광판 · Push 우선순위 · Shield · 이클립스 성공·실패 연출

This commit is contained in:
Sn-Kinos
2026-10-06 20:12:44 +09:00
parent a04626b003
commit 62b9637db9
30 changed files with 851 additions and 118 deletions
+19 -3
View File
@@ -156,6 +156,8 @@ class Repositories {
Stream<PlanetVisualState> _openPlanet(String fandomId) => Stream.multi((out) {
PlanetVisualState? planet;
var isEclipsed = false;
var eclipseFailed = false;
String? eclipseSuccessId;
var isHeroTime = false;
Set<String>? heroEventIds;
Timer? heroExpiry;
@@ -174,6 +176,8 @@ class Repositories {
level: current.level,
evolutionImminent: current.evolutionImminent,
isEclipsed: isEclipsed,
eclipseFailed: eclipseFailed,
eclipseSuccessId: eclipseSuccessId,
isHeroTime: isHeroTime,
heroEventIds: heroEventIds,
heroEndsAt: heroEndsAt,
@@ -191,9 +195,9 @@ class Repositories {
planet = PlanetVisualState.fromDocument(s.data() ?? const {});
emit();
}, onError: out.addError);
final danger = eclipse.watch(fandomId: fandomId).listen((state) {
isEclipsed =
state != null && !state.defended && !state.isExpired(DateTime.now());
// 판정 결과까지 받는다 — 활성 회차만 보면 마감 순간 null 이 되어 성공 · 실패를 가를 수 없다.
final danger = eclipse.watch(fandomId: fandomId, includeResults: true).listen((state) {
(isEclipsed, eclipseFailed, eclipseSuccessId) = eclipseLook(state, DateTime.now());
emit();
}, onError: out.addError);
// 기존 선물 이벤트만 읽는다. 구매 시도/로컬 캐시는 축제 확정이 아니다.
@@ -264,3 +268,15 @@ class Repositories {
// 눌러도 같은 상세가 열린다.
: SamplePlanetRepository(fandomId: fandomId);
}
/// 최근 이클립스 회차 → 행성 표현 (진행 중 감소 · 실패 감소 · 성공 회차 ID).
/// 판정 대기(마감 후 결과 전)는 셋 다 아니다 — 오류를 실패처럼 보이지 않는다(v1.5 §5 집계 오류).
(bool, bool, String?) eclipseLook(EclipseState? state, DateTime now) {
if (state == null) return (false, false, null);
final won = state.defended || state.result == EclipseResult.success;
return (
state.result == null && !won && !state.isExpired(now),
state.result == EclipseResult.failure,
won ? state.eclipseId : null,
);
}