광고 추가 보상 서버 시청 검증 · 사용자 퀘스트 승인 후 공개 · TIME ATTACK 모드 · 만보기 퀘스트 · 위치 퀘스트 지도 선택 · 운영 퀘스트 보상 재원

This commit is contained in:
Sn-Kinos
2026-10-05 22:48:09 +09:00
parent 4bb92c2ee7
commit fbf9a2c3d7
39 changed files with 1871 additions and 477 deletions
@@ -8,7 +8,7 @@ import 'package:flutter/painting.dart' show Color;
import 'home_data.dart';
import '../inside/inside_repository_firestore.dart' show insideQuestionFrom;
import '../quest/quest_data.dart' show QuestType;
import '../quest/quest_repository_firestore.dart' show questToday;
import '../quest/quest_repository_firestore.dart' show openTimeAttack, questToday;
import '../../core/i18n/app_locale.dart';
/// 홈의 실 서버 구현 — 화면 대조 원장 F1.
@@ -124,10 +124,9 @@ class FirestoreHomeRepository implements HomeRepository {
? null
: db
.collection('quests')
.where('type', isEqualTo: 'timeattack')
.where('fandomId', isEqualTo: fandomId)
.where('timeAttack.fandomId', isEqualTo: fandomId)
.where(
'activeTo',
'timeAttack.activeTo',
isGreaterThan: Timestamp.fromDate(
DateTime.now().subtract(const Duration(hours: 1)),
),
@@ -194,16 +193,17 @@ class FirestoreHomeRepository implements HomeRepository {
if (doc.data()['active'] != false) doc,
];
if (timeAttacks.isNotEmpty) await ServerClock.ensure(_backend);
final serverNow = ServerClock.now();
final open = [
for (final d in timeAttacks)
if (openTimeAttack(d.data()) != null) d,
];
final openIds = {for (final d in open) d.id};
final quests = [
...timeAttacks.where((d) {
final to = d.data()['activeTo'];
return to is Timestamp && to.toDate().isAfter(serverNow);
}),
// 타임어택은 위에서 창이 열린 것만 받았다. 여기서 다시 받으면 마감된 것이 남는다.
...open,
// 회차가 열린 Quest 는 위에서 맨 앞에 넣었다. 두 번 넣지 않는다.
...adminQuestsLatest([
for (final d in (await questsF).docs)
if (d.data()['type'] != 'timeattack') d,
if (!openIds.contains(d.id)) d,
], (d) => d.data()),
].take(3).toList();
final progress = (await progressF).docs;
@@ -374,7 +374,8 @@ class FirestoreHomeRepository implements HomeRepository {
title: quest.strOr('title'),
type: QuestType.parse(quest.strOr('type')),
category: QuestType.parse(quest.strOr('type')).label,
rewardPop: QuestType.parse(quest.strOr('type')).rewardFrom(quest, policy),
rewardPop: openTimeAttack(quest)?.rewardPop ??
QuestType.parse(quest.strOr('type')).rewardFrom(quest, policy),
state: done
? QuestState.done
: started
@@ -384,9 +385,7 @@ class FirestoreHomeRepository implements HomeRepository {
? null
: quest.strOr('progressLabel'),
id: id,
endsAt: quest['type'] == 'timeattack' && quest['activeTo'] is Timestamp
? (quest['activeTo'] as Timestamp).toDate()
: null,
endsAt: openTimeAttack(quest)?.endsAt,
);
}