코드 주석을 이 저장소 기준으로 정리
This commit is contained in:
@@ -23,7 +23,7 @@ typedef ShakePlayerEvent = ({bool playing, Duration position, bool ended});
|
||||
/// 재생되는 동안의 흔들기를 **영상 시각**으로 찍어 박마다 Perfect · Good · Miss · Combo 를
|
||||
/// 띄운다. 판정 창은 운영값(🟡 임시값 — 회신 대기). 마지막 박의 창이 닫히거나 영상이 끝나면
|
||||
/// 판정표를 돌려준다. 중간에 나가면 null 이다 — 호출자는 넘긴 [judge] 의 판정 · 영상 시각을
|
||||
/// 일시 정지 세션으로 남기고, 「이어하기」 때 그 판정표를 다시 넘겨 멈춘 자리부터 잇는다(원장 C-83).
|
||||
/// 일시 정지 세션으로 남기고, 「이어하기」 때 그 판정표를 다시 넘겨 멈춘 자리부터 잇는다(정책 원장 C-83).
|
||||
///
|
||||
/// Figma 에 이 진행 화면은 없다(상세 `480:14506` 은 「진행중」 버튼까지). 공통 기준 5항 —
|
||||
/// 기존 범위 기능의 정상 구현에 필요한 화면이다. 상세의 시각 문법(#141414 · #1a1a1c r24)을 따른다.
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
import '../../core/i18n/app_locale.dart';
|
||||
import '../../core/theme/tokens.dart';
|
||||
|
||||
/// 위치 Quest QR 인증 — 현장에 붙은 QR 을 스캔해 그 값을 돌려준다(원장 C-03 · PRD-05 「QR 인증」).
|
||||
/// 위치 Quest QR 인증 — 현장에 붙은 QR 을 스캔해 그 값을 돌려준다(정책 원장 C-03 · PRD-05 「QR 인증」).
|
||||
///
|
||||
/// 판정은 서버가 한다(생성 때 발급한 코드와 대조). 이 화면은 첫 번째로 읽힌 값으로 닫힐 뿐이다.
|
||||
/// 🟡 Figma 에 스캔 화면이 없어 카메라 전체 화면 + 닫기 버튼만 둔다(해석 확인 요청 영역B Q-B-10).
|
||||
|
||||
@@ -97,7 +97,7 @@ class _AdBonusDialog extends StatelessWidget {
|
||||
child: Text(
|
||||
bonusPop == null
|
||||
? context.l10n.adBonusPlaceholder
|
||||
// 원장 C-116 — 운영값 기반 「+N 기여 POP」(증분은 기여 POP · C-122).
|
||||
// 정책 원장 C-116 — 운영값 기반 「+N 기여 POP」(증분은 기여 POP · C-122).
|
||||
: '+${formatPop(bonusPop!)} ${context.l10n.popKindContribution}',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
@@ -166,7 +166,7 @@ class _AdBonusDialog extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Focus(광고 제거 구독 · 원장 B-04) 구입 버튼. 가격은 스토어가 준 현지 가격이다 —
|
||||
/// Focus(광고 제거 구독 · 정책 원장 B-04) 구입 버튼. 가격은 스토어가 준 현지 가격이다 —
|
||||
/// 시안의 「₩3,900/월」은 확정가(US$1.99)와 달라 쓰지 않는다(공통 기준 2항).
|
||||
/// 스토어에 상품이 없으면 「스토어 상품 준비 중」으로 멈춘다.
|
||||
class _FocusOffer extends StatefulWidget {
|
||||
|
||||
@@ -319,7 +319,7 @@ class _QuestCreateScreenState extends State<QuestCreateScreen> {
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: _pickPlace,
|
||||
),
|
||||
// 추가 인증 수단(원장 C-03 「Location 의 추가 인증 수단」 · PRD-05 「GPS · 사진 · QR 인증」).
|
||||
// 추가 인증 수단(정책 원장 C-03 「Location 의 추가 인증 수단」 · PRD-05 「GPS · 사진 · QR 인증」).
|
||||
// GPS 는 항상 들어간다. 🟡 Figma 생성 화면에 이 줄이 없어 배치는 임시다(해석 확인 요청 영역B Q-B-10).
|
||||
Text(context.l10n.questExtraVerify, style: Theme.of(context).textTheme.bodySmall),
|
||||
const SizedBox(height: AppSpace.s2),
|
||||
|
||||
@@ -20,7 +20,7 @@ import 'quest_evidence.dart' show ShakeJudge, ShakeWindows;
|
||||
/// 진행 상태 — 명세가 **다섯 가지**를 못박았다.
|
||||
///
|
||||
/// 명세 주석은 *「자세히」 · 「시작하기」 · 「진행중」 · 「보상받기」 · 「보상완료」* 이지만,
|
||||
/// 버튼 문구는 시각 기준(원장 C-44)인 Figma 화면을 따른다 — 「퀘스트 시작하기」 ·
|
||||
/// 버튼 문구는 시각 기준(정책 원장 C-44)인 Figma 화면을 따른다 — 「퀘스트 시작하기」 ·
|
||||
/// 「보상받기」 · 「보상 완료」(`264:46867` · `373:433420`). 상세 `272:245274` 는 「보상 받기」로
|
||||
/// 띄어 썼지만 홈 · 목록 사본 표기로 통일한다.
|
||||
///
|
||||
@@ -32,7 +32,7 @@ enum QuestStage {
|
||||
notStarted,
|
||||
inProgress,
|
||||
|
||||
/// 화면 안에서 진행하는 Quest(Music Shake)를 진행 화면 밖으로 나와 멈춘 상태 — 원장 C-83(10/3 통합회신
|
||||
/// 화면 안에서 진행하는 Quest(Music Shake)를 진행 화면 밖으로 나와 멈춘 상태 — 정책 원장 C-83(10/3 통합회신
|
||||
/// Q-OB-01 A): 진행 상태 값 「일시 정지」 · 버튼 「이어하기」. Walk · 출석은 이 상태가 되지 않는다.
|
||||
paused,
|
||||
completed,
|
||||
@@ -72,11 +72,11 @@ enum QuestType {
|
||||
/// 안에서만 참여를 받는다. 판정 시각은 서버 시각이다(`fn-quest-timeattack`).
|
||||
timeAttack,
|
||||
|
||||
/// 스밍·YouTube — 무보상 기본 참여(원장 C-04 · B-25, 9/16 확정). POP 지급 없이 참여 기록과
|
||||
/// 스밍·YouTube — 무보상 기본 참여(정책 원장 C-04 · B-25, 9/16 확정). POP 지급 없이 참여 기록과
|
||||
/// FPI 원천만 남는다(`fn-quest-stream-participate`).
|
||||
streaming,
|
||||
|
||||
/// 사용자 생성 Vote · SNS — 인증 자료 제출 → 생성자 · 운영자 검토(원장 C-08 · C-10).
|
||||
/// 사용자 생성 Vote · SNS — 인증 자료 제출 → 생성자 · 운영자 검토(정책 원장 C-08 · C-10).
|
||||
vote,
|
||||
sns,
|
||||
|
||||
@@ -134,7 +134,7 @@ enum QuestType {
|
||||
/// `quests.rewardPop` 을 보지 않는다. 그래서 출석만 운영값을 읽는다. 운영값이
|
||||
/// 없으면 null — 숫자를 지어내지 않고 화면이 중립 문구를 쓴다.
|
||||
///
|
||||
/// 운영 걸음 Quest 는 `fn-quest-steps` 가 `config/policy.stepTiers` 구간표(원장 B-26 —
|
||||
/// 운영 걸음 Quest 는 `fn-quest-steps` 가 `config/policy.stepTiers` 구간표(정책 원장 B-26 —
|
||||
/// 1 천/5 천/1 만/1.5 만보 = 5/6/7/8)대로 지급하고 `quests.rewardPop` 을 보지 않는다. 카드의
|
||||
/// 목표 칸이 오늘 다음 구간(`[cleared]` 번째)이므로 보상 칸도 **그 구간의 지급액**이다.
|
||||
int? rewardFrom(
|
||||
@@ -152,7 +152,7 @@ enum QuestType {
|
||||
]..sort((a, b) => a.steps.compareTo(b.steps));
|
||||
if (tiers.isNotEmpty) return tiers[cleared.clamp(0, tiers.length - 1)].pop;
|
||||
}
|
||||
// Music Shake 는 BPM 판정 성공 시 일반 POP(원장 B-24 · 보상액 운영값). 서버
|
||||
// Music Shake 는 BPM 판정 성공 시 일반 POP(정책 원장 B-24 · 보상액 운영값). 서버
|
||||
// (`fn-quest-verify-music-shake`)가 퀘스트의 `rewardPop` 을, 없으면
|
||||
// `config/policy.musicShake.pop` 을 기본액으로 쓴다. 운영값이 둘 다 없을 때만 중립 문구.
|
||||
final shake = policy['musicShake'];
|
||||
@@ -210,7 +210,7 @@ enum QuestAuthor {
|
||||
user,
|
||||
}
|
||||
|
||||
/// 퀘스트 분류 — `config/questCatalog.categories`(원장 C-01). 순서 · 노출은 Admin 운영값이다.
|
||||
/// 퀘스트 분류 — `config/questCatalog.categories`(정책 원장 C-01). 순서 · 노출은 Admin 운영값이다.
|
||||
class QuestCategory {
|
||||
const QuestCategory({
|
||||
required this.id,
|
||||
@@ -359,7 +359,7 @@ bool questFull(QuestCard card) =>
|
||||
card.capacity! > 0 &&
|
||||
card.participants >= card.capacity!;
|
||||
|
||||
/// 진행 세션 — `users/{uid}/questProgress/{questId}.session`(`fn-quest-progress` 만 쓴다 · 원장 C-83).
|
||||
/// 진행 세션 — `users/{uid}/questProgress/{questId}.session`(`fn-quest-progress` 만 쓴다 · 정책 원장 C-83).
|
||||
///
|
||||
/// **표시용 상태다.** 화면을 다시 열거나 앱을 다시 켜도 「진행중」 탭 · 「이어하기」 · 목록 「보상받기」가
|
||||
/// 남게 한다. 지급 판정은 여전히 검증 함수가 증거로 한다.
|
||||
@@ -403,7 +403,7 @@ class QuestSession {
|
||||
final Map<String, int>? judgement;
|
||||
}
|
||||
|
||||
/// 일시 정지 · 진행 세션이 바뀌었다 — 탭 화면 하단 캡슐(원장 C-83)이 다시 읽는다.
|
||||
/// 일시 정지 · 진행 세션이 바뀌었다 — 탭 화면 하단 캡슐(정책 원장 C-83)이 다시 읽는다.
|
||||
final questSessionSignal = ValueNotifier<int>(0);
|
||||
|
||||
/// 목록 카드 하나.
|
||||
@@ -433,7 +433,7 @@ class QuestCard {
|
||||
final String title;
|
||||
final String categoryName;
|
||||
|
||||
/// 서버에 남은 진행 세션(진행중 · 일시 정지 · 진행완료) — 원장 C-83. 없으면 null.
|
||||
/// 서버에 남은 진행 세션(진행중 · 일시 정지 · 진행완료) — 정책 원장 C-83. 없으면 null.
|
||||
final QuestSession? session;
|
||||
|
||||
/// 운영값(첫 박 · 판 길이)이 바뀌어 이어갈 수 없는 Music Shake 세션이 서버에 남아 있다.
|
||||
@@ -467,10 +467,10 @@ class QuestCard {
|
||||
/// 서버 경로는 null 이고, 화면은 분모 없이 참여 수만 적는다.
|
||||
final int? capacity;
|
||||
|
||||
/// 운영 Quest 의 광고 배수 — 원장 **B-03** 기본 x2, 지정 Quest 는 `quests/{id}.adMultiplier`.
|
||||
/// 운영 Quest 의 광고 배수 — 정책 원장 **B-03** 기본 x2, 지정 Quest 는 `quests/{id}.adMultiplier`.
|
||||
final int adMultiplier;
|
||||
|
||||
/// 사용자 생성 Quest 의 광고 추가 보상 — 원장 **C-02** 고정 10 기여 POP(운영값).
|
||||
/// 사용자 생성 Quest 의 광고 추가 보상 — 정책 원장 **C-02** 고정 10 기여 POP(운영값).
|
||||
final int ugcAdPop;
|
||||
|
||||
/// 참여 마감 시각(`quests.activeTo`). 타임어택만 채운다 — 화면이 남은 시간을 센다.
|
||||
@@ -566,7 +566,7 @@ class QuestDetail {
|
||||
|
||||
final QuestCard card;
|
||||
|
||||
/// 위치 Quest 의 인증 수단(`quests.verifyMethods` — `gps` · `photo` · `qr`, 원장 C-03). PRD-05
|
||||
/// 위치 Quest 의 인증 수단(`quests.verifyMethods` — `gps` · `photo` · `qr`, 정책 원장 C-03). PRD-05
|
||||
/// 「장소 상세에서 인증 방법 … 확인」. GPS 는 항상, 사진 · QR 은 생성 때 고른 추가 수단이다.
|
||||
final List<String> verifyMethods;
|
||||
|
||||
@@ -601,7 +601,7 @@ class QuestDetail {
|
||||
final List<QuestSubmission> reviews;
|
||||
}
|
||||
|
||||
/// 위치 Quest 의 추가 인증 증거(원장 C-03 · PRD-05 「사진 인증 · QR 인증」). GPS 좌표는 저장소가 따로 잰다.
|
||||
/// 위치 Quest 의 추가 인증 증거(정책 원장 C-03 · PRD-05 「사진 인증 · QR 인증」). GPS 좌표는 저장소가 따로 잰다.
|
||||
class PlaceProof {
|
||||
const PlaceProof({this.qr, this.photo});
|
||||
|
||||
@@ -630,7 +630,7 @@ enum QuestTab {
|
||||
QuestTab.all => true,
|
||||
// 명세 `518:88405` — *진행중 - 진행중 탭 / 진행완료 - 진행중 탭 / 보상완료 - 완료 탭*.
|
||||
// 보상을 받기 전(진행완료)까지는 진행중 탭에 두고, 받은 뒤에 완료 탭으로 옮긴다.
|
||||
// 일시 정지도 진행 중이다(원장 C-83 — 진행 상태 값에 「일시 정지」를 더함).
|
||||
// 일시 정지도 진행 중이다(정책 원장 C-83 — 진행 상태 값에 「일시 정지」를 더함).
|
||||
QuestTab.inProgress =>
|
||||
card.stage == QuestStage.inProgress ||
|
||||
card.stage == QuestStage.paused ||
|
||||
@@ -658,7 +658,7 @@ class QuestDraft {
|
||||
this.extraVerify = const [],
|
||||
});
|
||||
|
||||
/// 위치 Quest 의 추가 인증 수단(`photo` · `qr`, 원장 C-03). GPS 는 서버가 항상 넣는다.
|
||||
/// 위치 Quest 의 추가 인증 수단(`photo` · `qr`, 정책 원장 C-03). GPS 는 서버가 항상 넣는다.
|
||||
final List<String> extraVerify;
|
||||
|
||||
/// 지도에 꽂은 핀(등록 장소가 아닐 때) — 서버가 그 좌표로 장소를 만든다.
|
||||
@@ -739,7 +739,7 @@ abstract interface class QuestRepository {
|
||||
QuestSession? session,
|
||||
});
|
||||
|
||||
/// 가장 최근에 일시 정지한 Quest 1건 — 탭 화면 하단 캡슐(원장 C-83 · QA 3-34). 없으면 null.
|
||||
/// 가장 최근에 일시 정지한 Quest 1건 — 탭 화면 하단 캡슐(정책 원장 C-83 · QA 3-34). 없으면 null.
|
||||
Future<QuestCard?> pausedQuest();
|
||||
|
||||
Future<String> create(QuestDraft draft);
|
||||
@@ -805,7 +805,7 @@ class SampleQuestRepository implements QuestRepository {
|
||||
@override
|
||||
LocationConsent get locationConsent => SampleLocationConsent.shared;
|
||||
|
||||
/// 원장 C-01 매핑 중 사용자 생성 초기값(C-02 A안)으로 열린 활동만.
|
||||
/// 정책 원장 C-01 매핑 중 사용자 생성 초기값(C-02 A안)으로 열린 활동만.
|
||||
static QuestCatalog get _catalog => QuestCatalog(
|
||||
categories: [
|
||||
QuestCategory(
|
||||
|
||||
@@ -76,7 +76,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
/// 방금 끝낸 Music Shake 판의 판정 합계 — 결과 화면 · 결과 카드에 쓴다.
|
||||
Map<String, int>? _shakeResult;
|
||||
|
||||
/// 진행 세션(원장 C-83) — 서버에서 읽은 값을 이 화면에서 멈추면 바로 갈아 끼운다(「이어하기」 시작점).
|
||||
/// 진행 세션(정책 원장 C-83) — 서버에서 읽은 값을 이 화면에서 멈추면 바로 갈아 끼운다(「이어하기」 시작점).
|
||||
QuestSession? _session;
|
||||
|
||||
/// [QuestDetailScreen.autoAct] 를 한 번만 쓴다.
|
||||
@@ -125,7 +125,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 진행 세션을 서버에 남긴다(원장 C-83). 실패해도 이 화면의 진행은 계속된다 — 표시용 상태다.
|
||||
/// 진행 세션을 서버에 남긴다(정책 원장 C-83). 실패해도 이 화면의 진행은 계속된다 — 표시용 상태다.
|
||||
Future<void> _persist(
|
||||
String questId,
|
||||
QuestStage next, [
|
||||
@@ -267,7 +267,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
value:
|
||||
'${formatPop(_live ?? card.progress)} / ${formatPop(card.goal)}',
|
||||
),
|
||||
// 일시 정지 — 멈춘 시점의 진행값을 그대로 둔다(원장 C-83 · 해석 확인 요청서 Q-OB-01 A 5절).
|
||||
// 일시 정지 — 멈춘 시점의 진행값을 그대로 둔다(정책 원장 C-83 · 해석 확인 요청서 Q-OB-01 A 5절).
|
||||
if (stage == QuestStage.paused && _session != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
_Row(
|
||||
@@ -306,7 +306,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
// 인증 방법 — PRD-05 MVP 수용 기준 「장소 상세에서 인증 방법 · 보상 · 참여 현황 확인」 · 원장 C-03.
|
||||
// 인증 방법 — PRD-05 MVP 수용 기준 「장소 상세에서 인증 방법 · 보상 · 참여 현황 확인」 · 정책 원장 C-03.
|
||||
if (card.type == QuestType.place) ...[
|
||||
_Row(
|
||||
label: context.l10n.questVerifyMethods,
|
||||
@@ -841,7 +841,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
}
|
||||
|
||||
/// Music Shake 한 판 — 공식 영상을 보며 흔드는 진행 화면을 띄운다(PRD-04).
|
||||
/// 끝까지 했으면 판정표를 남기고 「보상받기」로, 중간에 나왔으면 **일시 정지**로 둔다(원장 C-83).
|
||||
/// 끝까지 했으면 판정표를 남기고 「보상받기」로, 중간에 나왔으면 **일시 정지**로 둔다(정책 원장 C-83).
|
||||
/// [resume] 이 있으면 멈춘 판정 · 영상 시각부터 잇는다(「이어하기」).
|
||||
Future<void> _playShake(QuestDetail detail, {QuestSession? resume}) async {
|
||||
final MusicShakeSetup setup;
|
||||
@@ -937,7 +937,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
_stage = QuestStage.completed;
|
||||
}
|
||||
});
|
||||
// 진행완료를 남긴다 — 목록 「보상받기」 · 진행중 탭이 다시 읽어도 같게(원장 C-83).
|
||||
// 진행완료를 남긴다 — 목록 「보상받기」 · 진행중 탭이 다시 읽어도 같게(정책 원장 C-83).
|
||||
if (reached) {
|
||||
unawaited(
|
||||
_persist(
|
||||
@@ -1087,7 +1087,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 기본 보상은 이미 원장에 있다. 광고는 그 위의 선택적 증분이다(원장 B-03 · C-122) —
|
||||
// 기본 보상은 이미 원장에 있다. 광고는 그 위의 선택적 증분이다(정책 원장 B-03 · C-122) —
|
||||
// 광고가 실패해도 기본 보상은 그대로다.
|
||||
// 일 한도를 다 쓴 사람에게는 모달을 띄우지 않는다(별첨 1 ⑥ 「일일 한도 도달 시 노출 제한」) —
|
||||
// 띄우면 광고를 끝까지 보고도 증분 0 이다.
|
||||
@@ -1142,7 +1142,7 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
/// 광고 시청 전 대기(`494:14332`)를 띄운 채 광고를 불러와 보여 준다.
|
||||
///
|
||||
/// 끝까지 봤으면 노출 ID, 아니면 null 이다. 불러오지 못했거나 중간에 닫았으면
|
||||
/// 그 사실을 알리고 **기본 보상으로 넘어간다**(원장 B-03 — 실패 시 기본 보상 지급 ·
|
||||
/// 그 사실을 알리고 **기본 보상으로 넘어간다**(정책 원장 B-03 — 실패 시 기본 보상 지급 ·
|
||||
/// 횟수 미차감). 대기 중 「건너뛰기」를 누르면 늦게 온 광고는 띄우지 않고 버린다.
|
||||
/// 이번 보상에서 광고가 실제로 화면에 떴는가 — skip 으로 닫았을 때도 시청 후 애니메이션을 거친다.
|
||||
bool _adShown = false;
|
||||
|
||||
@@ -147,7 +147,7 @@ typedef ShakeLive = ({
|
||||
ShakeHit? last,
|
||||
});
|
||||
|
||||
/// Music Shake 구간 판정표 — `fn-quest-verify-music-shake` 가 받는 **증거**(원장 B-24).
|
||||
/// Music Shake 구간 판정표 — `fn-quest-verify-music-shake` 가 받는 **증거**(정책 원장 B-24).
|
||||
///
|
||||
/// 시각은 **영상 재생 시각**(0 = 영상 처음)이다 — 공식 YouTube 영상을 보며 흔드는 퀘스트라
|
||||
/// (PRD-04) 박은 영상에 붙는다. 곡의 박(`quests.bpm`)마다 한 구간이고 첫 박은 `quests.firstBeatMs` 이며(판 길이 `totalSegments` 는 곡 전체를 덮도록 운영자가 정한다), 흔들기는 가장 가까운 박
|
||||
@@ -163,7 +163,7 @@ class ShakeJudge {
|
||||
List<double> hits = const [],
|
||||
this.position = Duration.zero,
|
||||
}) : assert(bpm > 0 && segments > 0) {
|
||||
// 일시 정지에서 「이어하기」 — 멈추기 전 판정을 그대로 잇는다(원장 C-83).
|
||||
// 일시 정지에서 「이어하기」 — 멈추기 전 판정을 그대로 잇는다(정책 원장 C-83).
|
||||
for (var i = 0; i < hits.length && i < segments; i++) {
|
||||
if (hits[i] >= 0) _best[i] = hits[i];
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ class _QuestListScreenState extends State<QuestListScreen> {
|
||||
|
||||
Future<void> _act(QuestCard card) async {
|
||||
// 명세 `518:88405` *보상 받기 버튼 클릭 시 POP 수령* — 목록에서 바로 받는다. 일시 정지는 「이어하기」
|
||||
// (원장 C-83). 판정 · 광고 모달 · 보상 완료 화면은 상세의 같은 경로를 쓴다.
|
||||
// (정책 원장 C-83). 판정 · 광고 모달 · 보상 완료 화면은 상세의 같은 경로를 쓴다.
|
||||
if (card.stage == QuestStage.completed || card.stage == QuestStage.paused) {
|
||||
await _open(card, act: true);
|
||||
return;
|
||||
|
||||
@@ -146,7 +146,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
return cards;
|
||||
}
|
||||
|
||||
/// 진행 세션이 있는 걸음 Quest 의 오늘 걸음 — Walk 는 화면 밖 걸음까지 **실제 상태**로 보인다(원장 C-62 · C-83).
|
||||
/// 진행 세션이 있는 걸음 Quest 의 오늘 걸음 — Walk 는 화면 밖 걸음까지 **실제 상태**로 보인다(정책 원장 C-62 · C-83).
|
||||
/// Health 를 한 번 읽고, 못 쓰면 이번 실행에서 센서로 센 값, 그것도 없으면 null(세션의 마지막 값).
|
||||
Future<int?> _walkFor(Map<String, dynamic> quest, Map<String, dynamic> progress) async {
|
||||
if (QuestType.parse(quest.strOr('type')) != QuestType.steps || progress['session'] is! Map) {
|
||||
@@ -183,7 +183,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
s != null &&
|
||||
!s.fits(Duration(milliseconds: quest.intOr('firstBeatMs')), quest.intOr('totalSegments'));
|
||||
|
||||
/// 진행 세션(`questProgress.session` — `fn-quest-progress` 만 쓴다 · 원장 C-83).
|
||||
/// 진행 세션(`questProgress.session` — `fn-quest-progress` 만 쓴다 · 정책 원장 C-83).
|
||||
static QuestSession? sessionOf(Map<String, dynamic> progress) {
|
||||
final raw = progress['session'];
|
||||
if (raw is! Map) return null;
|
||||
@@ -560,7 +560,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
'description': description,
|
||||
});
|
||||
|
||||
/// 진행중 · 일시 정지 · 진행완료 · 중단을 서버 진행 문서에 남긴다(`fn-quest-progress` · 원장 C-83).
|
||||
/// 진행중 · 일시 정지 · 진행완료 · 중단을 서버 진행 문서에 남긴다(`fn-quest-progress` · 정책 원장 C-83).
|
||||
///
|
||||
/// 진행 문서는 규칙상 서버 전용이라 함수로만 쓴다. 보상 상태는 여전히 [verify] 가 지급에 성공한 뒤
|
||||
/// 서버 카운터로 확정되고, 지급되면 서버가 세션을 지운다.
|
||||
@@ -839,7 +839,7 @@ class FirestoreQuestRepository implements QuestRepository {
|
||||
|
||||
Future<Map<String, dynamic>> _verifyShake(QuestCard card) async {
|
||||
final run = _shakeRun;
|
||||
// 끝낸 판을 서버 세션에 남겨 두었다면 그 판정표로 — 목록에서 바로 「보상받기」(원장 C-83).
|
||||
// 끝낸 판을 서버 세션에 남겨 두었다면 그 판정표로 — 목록에서 바로 「보상받기」(정책 원장 C-83).
|
||||
final saved = card.session?.state == QuestStage.completed ? card.session : null;
|
||||
final judgement = run?.judgement() ?? saved?.judgement;
|
||||
final segments = run?.segments ?? saved?.total ?? 0;
|
||||
|
||||
@@ -5,7 +5,7 @@ import '../quest_data.dart';
|
||||
import '../quest_detail_screen.dart';
|
||||
import 'quest_card_tile.dart' show pausedLabel;
|
||||
|
||||
/// 탭 화면(HOME · INSIDE · GALAXY · MY) 하단 탭 바로 위 한 줄 캡슐 — 원장 C-83(10/3 통합회신 Q-OB-01 A).
|
||||
/// 탭 화면(HOME · INSIDE · GALAXY · MY) 하단 탭 바로 위 한 줄 캡슐 — 정책 원장 C-83(10/3 통합회신 Q-OB-01 A).
|
||||
///
|
||||
/// 일시 정지한 Quest 가 있을 때만 가장 최근 1건을 「일시 정지 · Quest명 · 43/60」으로 띄우고, 누르면 그
|
||||
/// Quest 상세로 간다. Walk · 출석은 대상이 아니다(일시 정지가 되지 않는다). 새 탭 · 독립 화면이 아니다.
|
||||
|
||||
@@ -70,7 +70,7 @@ class QuestIconBox extends StatelessWidget {
|
||||
_ => (bg: AppColors.onCosmic, fg: Colors.black),
|
||||
};
|
||||
|
||||
/// 일시 정지 표기 — 「카테고리 · 일시 정지 · 43/60」. 카드와 탭 위 캡슐이 같이 쓴다(원장 C-83).
|
||||
/// 일시 정지 표기 — 「카테고리 · 일시 정지 · 43/60」. 카드와 탭 위 캡슐이 같이 쓴다(정책 원장 C-83).
|
||||
String pausedLabel(QuestCard card, {bool title = false}) =>
|
||||
title ? _paused(card.title, card.session, titleLast: true)
|
||||
: _paused(card.categoryName, card.session);
|
||||
@@ -159,7 +159,7 @@ class QuestCardTile extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
// 진행 상태 값 「일시 정지」 · 멈춘 진행값(원장 C-83 — 기존 카드 영역 안).
|
||||
// 진행 상태 값 「일시 정지」 · 멈춘 진행값(정책 원장 C-83 — 기존 카드 영역 안).
|
||||
questCardSubLine(card),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
|
||||
Reference in New Issue
Block a user