퀘스트 제목 다국어 · HOME 다시 읽기 · 내 퀘스트 검토 중·반려됨 구분

This commit is contained in:
Sn-Kinos
2026-10-06 01:22:28 +09:00
parent cf3dd06774
commit 83d9c1e8d4
10 changed files with 139 additions and 26 deletions
@@ -178,7 +178,7 @@ class FirestoreQuestRepository implements QuestRepository {
return QuestCard(
id: id,
title: _title(quest),
title: questTitle(quest),
categoryName: type.label,
type: type,
author: authorUid.isEmpty ? QuestAuthor.admin : QuestAuthor.user,
@@ -203,22 +203,11 @@ class FirestoreQuestRepository implements QuestRepository {
ugcAdPop: policy.intOr('adRewardPop', 10),
// 열린 TIME ATTACK 회차의 마감. 있으면 카드 · 상세가 남은 시간을 세고 참여는 회차로 간다.
endsAt: openTimeAttack(quest)?.endsAt,
publishState: authorUid == uid ? quest.strOr('status') : '',
);
}
/// 다국어 제목 — 설계서 §2.8 은 `title`(다국어)이라고만 적었다.
/// 문자열과 지도(map) 둘 다 들어올 수 있어 둘 다 받는다.
String _title(Map<String, dynamic> quest) {
final raw = quest['title'];
if (raw is String) return raw;
if (raw is Map) {
final map = Map<String, dynamic>.from(raw);
return map.strOr('ko', map.strOr('en'));
}
return '';
}
Future<Map<String, dynamic>> _policy() async {
final snap = await _backend.db.doc('config/policy').get();
return snap.data() ?? const <String, dynamic>{};
@@ -635,7 +624,7 @@ class FirestoreQuestRepository implements QuestRepository {
}
return MusicShakeSetup(
videoId: videoId,
title: link.strOr('title', _title(quest)),
title: link.strOr('title', questTitle(quest)),
bpm: bpm.toDouble(),
segments: segments,
windows: ShakeWindows.from(await _policy()),
@@ -792,7 +781,14 @@ List<int> _stepTiers(Map<String, dynamic> policy) {
/// 열린 TIME ATTACK 회차 — 원 Quest 문서의 `timeAttack`(10/3 통합회신: 별도 유형이 아니라
/// 기존 Quest 에 붙는 제한시간 모드). 창(`activeFrom` ~ `activeTo`, 서버 시각) 밖이면 null.
/// 화면 표시용이다 — 참여 수락은 서버(`fn-quest-timeattack`)가 서버 시각으로 다시 판정한다.
({String roundId, DateTime endsAt, int rewardPop})? openTimeAttack(
/// 카드 · 상세에 보일 Quest 제목. 열린 TIME ATTACK 회차면 회차 제목(`timeAttack.title`)이 먼저다.
/// 운영 Quest 제목은 언어별 지도라 [SnapshotReader.textOr] 로 읽는다(설계서 §2.8 `title` 다국어).
String questTitle(Map<String, dynamic> quest) {
final round = openTimeAttack(quest)?.title ?? '';
return round.isNotEmpty ? round : quest.textOr('title');
}
({String roundId, DateTime endsAt, int rewardPop, String title})? openTimeAttack(
Map<String, dynamic> quest,
) {
final raw = quest['timeAttack'];
@@ -807,5 +803,6 @@ List<int> _stepTiers(Map<String, dynamic> policy) {
roundId: round.strOr('roundId'),
endsAt: to.toDate(),
rewardPop: round.intOr('rewardPop'),
title: round.textOr('title'),
);
}