Figma 설명 프레임 반영 — 로그인·온보딩·스플래시 · HOME · GALAXY · 퀘스트·이클립스·알림

This commit is contained in:
Sn-Kinos
2026-10-06 03:03:20 +09:00
parent 64825e72b0
commit ecf5998725
77 changed files with 2703 additions and 640 deletions
@@ -133,7 +133,12 @@ class FirestoreQuestRepository implements QuestRepository {
} on Exception {
progress = const {};
}
cards.add(_card(doc.id, quest, progress, uid, policy, await _submission(doc.id, quest)));
final card = _card(doc.id, quest, progress, uid, policy, await _submission(doc.id, quest));
// 명세 `523:18176` 퀘스트 종료 시점 1 — *참여 인원 충족 시 퀘스트 종료*. 서버는 정원이 차면
// 참여를 거부하므로(미배정 Pool 0), 아직 참여하지 않은 사람에게는 열린 퀘스트로 보이지 않게 한다.
// 이미 참여한 사람(진행중 · 완료 탭)과 생성자(내 퀘스트)에게는 그대로 남긴다.
if (questFull(card) && card.stage == QuestStage.notStarted) continue;
cards.add(card);
}
return cards;
}
@@ -198,7 +203,7 @@ class FirestoreQuestRepository implements QuestRepository {
return QuestCard(
id: id,
title: questTitle(quest),
categoryName: type.label,
categoryName: type.category,
type: type,
author: authorUid.isEmpty ? QuestAuthor.admin : QuestAuthor.user,
stage: authorUid == uid
@@ -223,6 +228,7 @@ class FirestoreQuestRepository implements QuestRepository {
// 열린 TIME ATTACK 회차의 마감. 있으면 카드 · 상세가 남은 시간을 세고 참여는 회차로 간다.
endsAt: openTimeAttack(quest)?.endsAt,
publishState: authorUid == uid ? quest.strOr('status') : '',
authorName: quest.strOr('authorName'),
);
}
@@ -513,6 +519,29 @@ class FirestoreQuestRepository implements QuestRepository {
return wallet.data()?.intOr('activityBalance');
}
@override
Future<bool> adAvailable() async {
try {
final db = _backend.db;
final ad = (await db.doc('users/${_backend.requireUid}/questProgress/ad').get()).data();
// 서버 `progress(uid, 'ad', dayKey(now))` 와 같은 규약 — KST 날짜가 다르면 오늘 0회.
final today = ServerClock.now().toUtc().add(const Duration(hours: 9)).toIso8601String().substring(0, 10);
if (ad == null || ad['dayKey'] != today) return true;
final limit = (await _policy()).intOr('adDailyLimit', 5);
return ad.intOr('count') < limit;
} on Exception {
return true;
}
}
@override
Future<int?> spendableBalance() async {
final wallet = await _backend.db.doc('users/${_backend.requireUid}/wallet/main').get();
final data = wallet.data();
if (data == null) return null;
return data.intOr('activityBalance') + data.intOr('supportBalance');
}
@override
Stream<int> progressStream(QuestCard card) {
if (card.type != QuestType.steps) return const Stream<int>.empty();