Music Shake 첫 박 시각 · 카운트다운 · 옛 일시 정지 판 정리
This commit is contained in:
@@ -158,13 +158,26 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
|
||||
/// 목록 카드가 「일시 정지」로 보는 세션 — 진행완료가 아니고 Walk 가 아닌 남은 세션(앱이 꺼진
|
||||
/// inProgress 포함). 카드 단계 판정([QuestStage.paused])과 같은 규칙이다. 아니면 null.
|
||||
static QuestSession? pausedSessionOf(QuestType type, Map<String, dynamic> progress) {
|
||||
static QuestSession? pausedSessionOf(
|
||||
QuestType type,
|
||||
Map<String, dynamic> progress,
|
||||
Map<String, dynamic> quest,
|
||||
) {
|
||||
final s = sessionOf(progress);
|
||||
return s == null || type == QuestType.steps || s.state == QuestStage.completed
|
||||
return s == null ||
|
||||
type == QuestType.steps ||
|
||||
s.state == QuestStage.completed ||
|
||||
staleShake(type, quest, s)
|
||||
? null
|
||||
: s;
|
||||
}
|
||||
|
||||
/// 운영값(첫 박 · 판 길이)이 바뀌어 이어갈 수 없는 Music Shake 세션인가 — [QuestSession.fitsShake] 와 같은 기준.
|
||||
static bool staleShake(QuestType type, Map<String, dynamic> quest, QuestSession? s) =>
|
||||
type == QuestType.musicShake &&
|
||||
s != null &&
|
||||
!s.fits(Duration(milliseconds: quest.intOr('firstBeatMs')), quest.intOr('totalSegments'));
|
||||
|
||||
/// 진행 세션(`questProgress.session` — `fn-quest-progress` 만 쓴다 · 원장 C-83).
|
||||
static QuestSession? sessionOf(Map<String, dynamic> progress) {
|
||||
final raw = progress['session'];
|
||||
@@ -185,6 +198,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
total: m.intOr('total'),
|
||||
position: Duration(milliseconds: m.intOr('positionMs')),
|
||||
hits: hits is List ? [for (final h in hits) if (h is num) h.toDouble()] : const [],
|
||||
firstBeat: m['firstBeatMs'] is num ? Duration(milliseconds: m.intOr('firstBeatMs')) : null,
|
||||
judgement: judgement is Map
|
||||
? {for (final e in judgement.entries) if (e.value is num) '${e.key}': (e.value as num).round()}
|
||||
: null,
|
||||
@@ -238,13 +252,17 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
: type == QuestType.musicShake
|
||||
? quest.intOr('bpm')
|
||||
: dailyLimit;
|
||||
final session = sessionOf(progress);
|
||||
final saved = sessionOf(progress);
|
||||
// 이어갈 수 없는 옛 Music Shake 판은 세션이 없는 것으로 본다 — 「시작하기」로 보이고 시작 때 안내한다.
|
||||
final stale = staleShake(type, quest, saved);
|
||||
final session = stale ? null : saved;
|
||||
final cardGoal = authorUid.isEmpty ? goal : quest.intOr('goal', 1);
|
||||
// 걸음은 화면 밖 걸음까지 실제 값(C-62) — 오늘 걸음, 없으면 세션의 마지막 값.
|
||||
final walked = steps && session != null ? walk ?? session.progress : null;
|
||||
|
||||
return QuestCard(
|
||||
session: session,
|
||||
staleShake: stale,
|
||||
id: id,
|
||||
title: questTitle(quest),
|
||||
categoryName: type.category,
|
||||
@@ -561,6 +579,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
'total': session.total,
|
||||
'positionMs': session.position.inMilliseconds,
|
||||
if (session.hits.isNotEmpty) 'hits': session.hits,
|
||||
if (session.firstBeat != null) 'firstBeatMs': session.firstBeat!.inMilliseconds,
|
||||
'judgement': ?session.judgement,
|
||||
},
|
||||
});
|
||||
@@ -792,12 +811,18 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
if (videoId == null || bpm is! num || bpm <= 0 || segments <= 0) {
|
||||
throw BackendException('E-QST-01', appL10n.questTypeUnverifiable);
|
||||
}
|
||||
final policy = await _policy();
|
||||
final shake = policy['musicShake'];
|
||||
// 🟡 임시값 — 회신 대기(해석 확인 요청서 MusicShake 「재생 시작 위치」): 첫 박 3초 전부터 튼다.
|
||||
final leadIn = shake is Map ? shake['leadInMs'] : null;
|
||||
return MusicShakeSetup(
|
||||
videoId: videoId,
|
||||
title: link.strOr('title', questTitle(quest)),
|
||||
bpm: bpm.toDouble(),
|
||||
segments: segments,
|
||||
windows: ShakeWindows.from(await _policy()),
|
||||
firstBeat: Duration(milliseconds: quest.intOr('firstBeatMs')),
|
||||
windows: ShakeWindows.from(policy),
|
||||
leadIn: Duration(milliseconds: leadIn is num && leadIn >= 0 ? leadIn.round() : 3000),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -829,6 +854,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
'questId': card.id,
|
||||
'trackId': trackId,
|
||||
'totalSegments': segments,
|
||||
if (run != null) 'firstBeatMs': run.firstBeat.inMilliseconds,
|
||||
'judgement': judgement,
|
||||
'occurredAt': DateTime.now().toUtc().toIso8601String(),
|
||||
...await _fandomField(),
|
||||
|
||||
Reference in New Issue
Block a user