퀘스트 일시 정지 · 이어하기 · 진행 상태 서버 저장 · 목록 보상받기
This commit is contained in:
@@ -8,6 +8,8 @@ library;
|
||||
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
|
||||
import 'package:flutter/foundation.dart' show ValueNotifier;
|
||||
|
||||
import '../../core/data/backend.dart' show BackendException;
|
||||
import '../../core/monetization/rewarded_ad.dart';
|
||||
import '../../core/i18n/app_locale.dart';
|
||||
@@ -28,6 +30,10 @@ enum QuestStage {
|
||||
mine,
|
||||
notStarted,
|
||||
inProgress,
|
||||
|
||||
/// 화면 안에서 진행하는 Quest(Music Shake)를 진행 화면 밖으로 나와 멈춘 상태 — 원장 C-83(10/3 통합회신
|
||||
/// Q-OB-01 A): 진행 상태 값 「일시 정지」 · 버튼 「이어하기」. Walk · 출석은 이 상태가 되지 않는다.
|
||||
paused,
|
||||
completed,
|
||||
rewarded;
|
||||
|
||||
@@ -36,6 +42,7 @@ enum QuestStage {
|
||||
mine => appL10n.questDetails,
|
||||
notStarted => appL10n.questStart,
|
||||
inProgress => appL10n.questInProgress,
|
||||
paused => appL10n.questResume,
|
||||
completed => appL10n.questClaim,
|
||||
rewarded => appL10n.questRewardDone,
|
||||
};
|
||||
@@ -335,6 +342,42 @@ bool questFull(QuestCard card) =>
|
||||
card.capacity! > 0 &&
|
||||
card.participants >= card.capacity!;
|
||||
|
||||
/// 진행 세션 — `users/{uid}/questProgress/{questId}.session`(`fn-quest-progress` 만 쓴다 · 원장 C-83).
|
||||
///
|
||||
/// **표시용 상태다.** 화면을 다시 열거나 앱을 다시 켜도 「진행중」 탭 · 「이어하기」 · 목록 「보상받기」가
|
||||
/// 남게 한다. 지급 판정은 여전히 검증 함수가 증거로 한다.
|
||||
class QuestSession {
|
||||
const QuestSession({
|
||||
required this.state,
|
||||
this.progress = 0,
|
||||
this.total = 0,
|
||||
this.position = Duration.zero,
|
||||
this.hits = const [],
|
||||
this.judgement,
|
||||
});
|
||||
|
||||
/// [QuestStage.inProgress] · [QuestStage.paused] · [QuestStage.completed] 중 하나.
|
||||
final QuestStage state;
|
||||
|
||||
/// 실행한 값 — 걸음 수 · Music Shake 판정이 끝난 박 수.
|
||||
final int progress;
|
||||
|
||||
/// 목표 — 걸음 목표 · Music Shake 박 수.
|
||||
final int total;
|
||||
|
||||
/// Music Shake 를 멈춘 영상 시각 — 「이어하기」 시작점.
|
||||
final Duration position;
|
||||
|
||||
/// Music Shake 박마다 가장 가까운 흔들기의 거리(박 비율). 흔들기가 없으면 -1.
|
||||
final List<double> hits;
|
||||
|
||||
/// 끝까지 한 Music Shake 판의 판정 합계 — 목록에서 바로 「보상받기」할 때 서버에 보낸다.
|
||||
final Map<String, int>? judgement;
|
||||
}
|
||||
|
||||
/// 일시 정지 · 진행 세션이 바뀌었다 — 탭 화면 하단 캡슐(원장 C-83)이 다시 읽는다.
|
||||
final questSessionSignal = ValueNotifier<int>(0);
|
||||
|
||||
/// 목록 카드 하나.
|
||||
class QuestCard {
|
||||
const QuestCard({
|
||||
@@ -354,12 +397,16 @@ class QuestCard {
|
||||
this.endsAt,
|
||||
this.publishState = '',
|
||||
this.authorName = '',
|
||||
this.session,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String title;
|
||||
final String categoryName;
|
||||
|
||||
/// 서버에 남은 진행 세션(진행중 · 일시 정지 · 진행완료) — 원장 C-83. 없으면 null.
|
||||
final QuestSession? session;
|
||||
|
||||
/// 만든 사람의 공개 닉네임(`quests.authorName`). 운영 Quest 는 빈 값이다.
|
||||
/// 신고하기 「신고 정보 영역 — 작성자 닉네임」(Figma `548:21389`)에 쓴다.
|
||||
final String authorName;
|
||||
@@ -409,6 +456,7 @@ class QuestCard {
|
||||
|
||||
/// 상태·진행도만 바꾼 사본. [QuestCard] 는 불변이라 갈아 끼운다.
|
||||
QuestCard copyWith({QuestStage? stage, int? progress}) => QuestCard(
|
||||
session: session,
|
||||
id: id,
|
||||
title: title,
|
||||
categoryName: categoryName,
|
||||
@@ -536,8 +584,11 @@ enum QuestTab {
|
||||
QuestTab.all => true,
|
||||
// 명세 `518:88405` — *진행중 - 진행중 탭 / 진행완료 - 진행중 탭 / 보상완료 - 완료 탭*.
|
||||
// 보상을 받기 전(진행완료)까지는 진행중 탭에 두고, 받은 뒤에 완료 탭으로 옮긴다.
|
||||
// 일시 정지도 진행 중이다(원장 C-83 — 진행 상태 값에 「일시 정지」를 더함).
|
||||
QuestTab.inProgress =>
|
||||
card.stage == QuestStage.inProgress || card.stage == QuestStage.completed,
|
||||
card.stage == QuestStage.inProgress ||
|
||||
card.stage == QuestStage.paused ||
|
||||
card.stage == QuestStage.completed,
|
||||
QuestTab.done => card.stage == QuestStage.rewarded,
|
||||
QuestTab.mine => card.stage == QuestStage.mine,
|
||||
};
|
||||
@@ -630,7 +681,17 @@ abstract interface class QuestRepository {
|
||||
Future<void> cancel(String questId);
|
||||
|
||||
/// 상태 전이. 서버가 확정한 상태를 돌려준다.
|
||||
Future<QuestStage> advance(String questId, QuestStage next);
|
||||
///
|
||||
/// 실행률을 모으는 Quest(걸음 · Music Shake)는 진행 세션을 서버에 남긴다(`fn-quest-progress` · C-83).
|
||||
/// [session] 은 그 진행값이다. [QuestStage.notStarted] 는 중단(세션 삭제)이다.
|
||||
Future<QuestStage> advance(
|
||||
String questId,
|
||||
QuestStage next, {
|
||||
QuestSession? session,
|
||||
});
|
||||
|
||||
/// 가장 최근에 일시 정지한 Quest 1건 — 탭 화면 하단 캡슐(원장 C-83 · QA 3-34). 없으면 null.
|
||||
Future<QuestCard?> pausedQuest();
|
||||
|
||||
Future<String> create(QuestDraft draft);
|
||||
|
||||
@@ -881,7 +942,14 @@ class SampleQuestRepository implements QuestRepository {
|
||||
Future<void> cancel(String questId) async {}
|
||||
|
||||
@override
|
||||
Future<QuestStage> advance(String questId, QuestStage next) async => next;
|
||||
Future<QuestStage> advance(
|
||||
String questId,
|
||||
QuestStage next, {
|
||||
QuestSession? session,
|
||||
}) async => next;
|
||||
|
||||
@override
|
||||
Future<QuestCard?> pausedQuest() async => null;
|
||||
|
||||
@override
|
||||
Future<String> create(QuestDraft draft) async => 'q-new';
|
||||
|
||||
Reference in New Issue
Block a user