퀘스트 일시 정지 · 이어하기 · 진행 상태 서버 저장 · 목록 보상받기

This commit is contained in:
Sn-Kinos
2026-10-06 03:20:46 +09:00
parent ecf5998725
commit abe5f1ae50
28 changed files with 1023 additions and 118 deletions
+34 -4
View File
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../../core/data/backend.dart' show BackendException;
import '../../core/theme/tokens.dart';
import '../home/home_screen.dart' show formatPop;
import '../planet/moderation.dart';
@@ -127,12 +128,14 @@ class _QuestListScreenState extends State<QuestListScreen> {
/// 줄로, 사용자 퀘스트를 아래 카드로 나눈다. 다른 탭은 카드만 있다.
bool get _split => _tab == QuestTab.all;
Future<void> _open(QuestCard card) async {
/// 상세로 간다. [act] 면 상세가 열리자마자 카드 버튼 동작(보상받기 · 이어하기 · 참여)을 한다.
Future<void> _open(QuestCard card, {bool act = false}) async {
await Navigator.of(context, rootNavigator: true).push<void>(
MaterialPageRoute(
builder: (_) => QuestDetailScreen(
questId: card.id,
repository: widget.repository,
autoAct: act,
),
),
);
@@ -140,9 +143,14 @@ class _QuestListScreenState extends State<QuestListScreen> {
}
Future<void> _act(QuestCard card) async {
// 명세 `518:88405` *보상 받기 버튼 클릭 시 POP 수령* — 목록에서 바로 받는다. 일시 정지는 「이어하기」
// (원장 C-83). 판정 · 광고 모달 · 보상 완료 화면은 상세의 같은 경로를 쓴다.
if (card.stage == QuestStage.completed || card.stage == QuestStage.paused) {
await _open(card, act: true);
return;
}
// 사용자 생성 Quest 는 상세에서 링크 · 마감 · 참여 규칙을 본 뒤 참여한다(C-05 · C-06 · C-12).
if (card.stage == QuestStage.mine || card.stage == QuestStage.completed ||
card.author == QuestAuthor.user) {
if (card.stage == QuestStage.mine || card.author == QuestAuthor.user) {
await _open(card);
return;
}
@@ -159,7 +167,29 @@ class _QuestListScreenState extends State<QuestListScreen> {
));
return;
}
final next = await widget.repository.advance(card.id, QuestStage.inProgress);
// 진행중을 거치는 것은 실행률을 모으는 Quest(걸음)뿐이다 — 나머지는 누르는 순간 판정이라
// 상세의 같은 참여 경로로 보낸다(해석 확인 요청서 영역B Q-B-12 A · Music Shake 는 진행 화면).
if (!(card.goal > 1 && card.type.gathers)) {
await _open(card, act: true);
return;
}
final QuestStage next;
try {
next = await widget.repository.advance(
card.id,
QuestStage.inProgress,
session: QuestSession(state: QuestStage.inProgress, total: card.goal),
);
} on Exception catch (error) {
if (!mounted) return;
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(SnackBar(
content: Text(error is BackendException ? error.message : context.l10n.commonRequestFailed),
behavior: SnackBarBehavior.floating,
));
return;
}
if (!mounted) return;
setState(() {
_cards = [