번역 평가 버튼 · 내 퀘스트 검토 버튼 · MY 질문 상세 · MY 완료 퀘스트 수 · 행성/성운 칸 · 라운지 빈 상태 수정
This commit is contained in:
@@ -86,7 +86,8 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
});
|
||||
// 목록에서 「시작하기」를 눌러 진행중으로 들어온 경우다. 여기서 다시 켜지 않으면
|
||||
// 상세를 열어도 실행률이 0 에 멈춘 채로 남는다.
|
||||
if (_stage == QuestStage.inProgress && detail.card.type == QuestType.steps) {
|
||||
if (_stage == QuestStage.inProgress &&
|
||||
detail.card.type == QuestType.steps) {
|
||||
_watch(detail.card);
|
||||
}
|
||||
}
|
||||
@@ -110,20 +111,36 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
actions: [
|
||||
PopupMenuButton<String>(
|
||||
tooltip: context.l10n.commonMore,
|
||||
icon: const ImageIcon(AppIcons.ellipsisVertical, size: 24, color: AppColors.onCosmic),
|
||||
icon: const ImageIcon(
|
||||
AppIcons.ellipsisVertical,
|
||||
size: 24,
|
||||
color: AppColors.onCosmic,
|
||||
),
|
||||
onSelected: (value) =>
|
||||
value == 'edit' ? _edit(detail) : _report(card.title),
|
||||
itemBuilder: (_) => [
|
||||
// 공개 후 수정은 생성자의 제목 · 설명뿐이다(C-07).
|
||||
if (stage == QuestStage.mine && ugc)
|
||||
PopupMenuItem(value: 'edit', child: Text(context.l10n.questEdit)),
|
||||
PopupMenuItem(value: 'report', child: Text(context.l10n.reportTitle)),
|
||||
PopupMenuItem(
|
||||
value: 'edit',
|
||||
child: Text(context.l10n.questEdit),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'report',
|
||||
child: Text(context.l10n.reportTitle),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 10, 16, 16),
|
||||
// 하단 바가 없는 상태(내 퀘스트)에서도 시스템 내비게이션 바 아래로 깔리지 않게.
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
16,
|
||||
10,
|
||||
16,
|
||||
16 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
children: [
|
||||
// 명세 `518:88429` — 대표 이미지 · 카테고리 · 퀘스트 명 · 중앙 정렬.
|
||||
// 시안 `264:48835` — #2e2e2e 240 원 안에 200 이미지.
|
||||
@@ -178,13 +195,16 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
// 명세 `518:88435` — 설정 목표 수치 · 실행한 목표 수치 · 설정 보상 POP.
|
||||
_Row(
|
||||
label: context.l10n.questGoal,
|
||||
value: '${formatPop(_live ?? card.progress)} / ${formatPop(card.goal)}',
|
||||
value:
|
||||
'${formatPop(_live ?? card.progress)} / ${formatPop(card.goal)}',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_Row(
|
||||
label: context.l10n.questReward,
|
||||
bolt: card.rewardPop != null,
|
||||
value: card.rewardPop == null ? context.l10n.questPopGrant : '+${formatPop(card.rewardPop!)}',
|
||||
value: card.rewardPop == null
|
||||
? context.l10n.questPopGrant
|
||||
: '+${formatPop(card.rewardPop!)}',
|
||||
),
|
||||
// 타임어택 — 남은 시간. 마감 판정은 서버 시각이 다시 한다(FR-QST-06).
|
||||
if (endsAt != null) ...[
|
||||
@@ -193,14 +213,19 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
endsAt: endsAt,
|
||||
builder: (context, left) => _Row(
|
||||
label: context.l10n.questTimeLeft,
|
||||
value: left == null ? context.l10n.questTimeAttackClosed : formatLeft(left),
|
||||
value: left == null
|
||||
? context.l10n.questTimeAttackClosed
|
||||
: formatLeft(left),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
// 마감 순간은 서버값 그대로, 표시만 기기 시간대(C-06 · G-04).
|
||||
if (detail.endsAt != null) ...[
|
||||
_Row(label: context.l10n.questDeadline, value: _deadline(detail.endsAt!)),
|
||||
_Row(
|
||||
label: context.l10n.questDeadline,
|
||||
value: _deadline(detail.endsAt!),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
// 참여 전 간격 · 최대 횟수 안내(C-12).
|
||||
@@ -210,7 +235,10 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
child: Text(
|
||||
detail.repeatHours == null
|
||||
? context.l10n.questRepeatOnce
|
||||
: context.l10n.questRepeatEvery('${detail.repeatHours}', '${detail.repeatMax}'),
|
||||
: context.l10n.questRepeatEvery(
|
||||
'${detail.repeatHours}',
|
||||
'${detail.repeatMax}',
|
||||
),
|
||||
style: _body,
|
||||
),
|
||||
),
|
||||
@@ -218,9 +246,15 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('assets/figma/quest-check.png', width: 20, height: 20),
|
||||
Image.asset(
|
||||
'assets/figma/quest-check.png',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(context.l10n.questParticipants, style: _strong)),
|
||||
Expanded(
|
||||
child: Text(context.l10n.questParticipants, style: _strong),
|
||||
),
|
||||
Text(
|
||||
card.capacity == null
|
||||
? formatPop(card.participants)
|
||||
@@ -245,8 +279,14 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
? null
|
||||
: endsAt == null
|
||||
// 사용자 생성 Quest 는 서버 시각 기준 마감이 지나면 잠근다(C-06 · G-04). 판정은 서버가 다시 한다.
|
||||
? _button(detail, stage, blocked,
|
||||
closed: detail.endsAt != null && !ServerClock.now().isBefore(detail.endsAt!))
|
||||
? _button(
|
||||
detail,
|
||||
stage,
|
||||
blocked,
|
||||
closed:
|
||||
detail.endsAt != null &&
|
||||
!ServerClock.now().isBefore(detail.endsAt!),
|
||||
)
|
||||
: TimeAttackCountdown(
|
||||
endsAt: endsAt,
|
||||
builder: (_, left) =>
|
||||
@@ -266,50 +306,52 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
final open = !closed || stage == QuestStage.rewarded;
|
||||
final submission = detail.submission;
|
||||
// 사람 검토형의 제출 상태(C-08 · G-03) — 검토 중 · 최종 반려는 다시 누를 수 없다.
|
||||
final held = submission != null && (submission.pending || submission.finalRejected);
|
||||
final held =
|
||||
submission != null && (submission.pending || submission.finalRejected);
|
||||
return SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: FilledButton(
|
||||
onPressed: stage.tappable && !_busy && blocked == null && open && !held
|
||||
? () => _act(detail, stage)
|
||||
: null,
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(56),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
backgroundColor: colors.bg,
|
||||
foregroundColor: colors.fg,
|
||||
disabledBackgroundColor: const Color(0xFF333333),
|
||||
disabledForegroundColor: const Color(0xFF777777),
|
||||
textStyle: const TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 24 / 16,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
blocked != null
|
||||
? context.l10n.commonComingSoon
|
||||
: !open
|
||||
? context.l10n.questTimeAttackClosed
|
||||
: _busy
|
||||
? context.l10n.commonChecking
|
||||
: submission != null && submission.pending
|
||||
? context.l10n.questReviewButton
|
||||
: submission != null && submission.rejected
|
||||
? (!submission.finalRejected
|
||||
? context.l10n.questResubmit
|
||||
: context.l10n.questRejectedButton)
|
||||
: detail.card.type.reviewed && stage == QuestStage.notStarted
|
||||
? context.l10n.questSubmit
|
||||
: stage.buttonLabel,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: FilledButton(
|
||||
onPressed:
|
||||
stage.tappable && !_busy && blocked == null && open && !held
|
||||
? () => _act(detail, stage)
|
||||
: null,
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(56),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
),
|
||||
backgroundColor: colors.bg,
|
||||
foregroundColor: colors.fg,
|
||||
disabledBackgroundColor: const Color(0xFF333333),
|
||||
disabledForegroundColor: const Color(0xFF777777),
|
||||
textStyle: const TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 24 / 16,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
blocked != null
|
||||
? context.l10n.commonComingSoon
|
||||
: !open
|
||||
? context.l10n.questTimeAttackClosed
|
||||
: _busy
|
||||
? context.l10n.commonChecking
|
||||
: submission != null && submission.pending
|
||||
? context.l10n.questReviewButton
|
||||
: submission != null && submission.rejected
|
||||
? (!submission.finalRejected
|
||||
? context.l10n.questResubmit
|
||||
: context.l10n.questRejectedButton)
|
||||
: detail.card.type.reviewed && stage == QuestStage.notStarted
|
||||
? context.l10n.questSubmit
|
||||
: stage.buttonLabel,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static const _caption = TextStyle(
|
||||
@@ -331,7 +373,8 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
/// 기기 시간대의 마감 시각과 남은 시간.
|
||||
String _deadline(DateTime endsAt) {
|
||||
final local = endsAt.toLocal();
|
||||
final at = '${local.year}.${_two(local.month)}.${_two(local.day)} '
|
||||
final at =
|
||||
'${local.year}.${_two(local.month)}.${_two(local.day)} '
|
||||
'${_two(local.hour)}:${_two(local.minute)}';
|
||||
final left = endsAt.difference(ServerClock.now());
|
||||
return left.isNegative
|
||||
@@ -352,16 +395,22 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
: context.l10n.questResubmitNotAllowed,
|
||||
],
|
||||
];
|
||||
return [for (final line in lines) Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
||||
child: Text(line, style: _body),
|
||||
)];
|
||||
return [
|
||||
for (final line in lines)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
||||
child: Text(line, style: _body),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// 생성자 검토 대기열 — 승인 · 반려. 시간이 지나도 자동 승인하지 않는다(C-08).
|
||||
List<Widget> _reviewQueue(QuestDetail detail) => [
|
||||
const SizedBox(height: 16),
|
||||
Text(context.l10n.questReviewQueue('${detail.reviews.length}'), style: _strong),
|
||||
Text(
|
||||
context.l10n.questReviewQueue('${detail.reviews.length}'),
|
||||
style: _strong,
|
||||
),
|
||||
for (final s in detail.reviews)
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
@@ -400,7 +449,9 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
children: [
|
||||
TextField(
|
||||
controller: input,
|
||||
decoration: InputDecoration(labelText: context.l10n.questRejectReason),
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.questRejectReason,
|
||||
),
|
||||
),
|
||||
CheckboxListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
@@ -416,12 +467,14 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
input.dispose();
|
||||
if (!ok || reason.isEmpty) return;
|
||||
}
|
||||
await _run(() => widget.repository.review(
|
||||
s.id,
|
||||
approve: approve,
|
||||
reason: reason,
|
||||
resubmitAllowed: resubmit,
|
||||
));
|
||||
await _run(
|
||||
() => widget.repository.review(
|
||||
s.id,
|
||||
approve: approve,
|
||||
reason: reason,
|
||||
resubmitAllowed: resubmit,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 인증 제출 · 보완 제출(C-08 · G-01) — 링크 또는 내용 중 하나 이상.
|
||||
@@ -433,21 +486,25 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
context.l10n.questSubmit,
|
||||
confirmLabel: context.l10n.commonSubmit,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: url,
|
||||
keyboardType: TextInputType.url,
|
||||
decoration: InputDecoration(labelText: context.l10n.questEvidenceUrl),
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: url,
|
||||
keyboardType: TextInputType.url,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.questEvidenceUrl,
|
||||
),
|
||||
TextField(
|
||||
controller: text,
|
||||
maxLines: 3,
|
||||
minLines: 1,
|
||||
decoration: InputDecoration(labelText: context.l10n.questEvidenceText),
|
||||
),
|
||||
TextField(
|
||||
controller: text,
|
||||
maxLines: 3,
|
||||
minLines: 1,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.questEvidenceText,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final proofUrl = url.text.trim();
|
||||
final proofText = text.text.trim();
|
||||
@@ -455,7 +512,11 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
text.dispose();
|
||||
if (!ok || (proofUrl.isEmpty && proofText.isEmpty)) return;
|
||||
final done = await _run(
|
||||
() => widget.repository.submit(detail.card.id, url: proofUrl, text: proofText),
|
||||
() => widget.repository.submit(
|
||||
detail.card.id,
|
||||
url: proofUrl,
|
||||
text: proofText,
|
||||
),
|
||||
);
|
||||
if (done && mounted) _toast(context.l10n.questSubmitted);
|
||||
}
|
||||
@@ -469,32 +530,36 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
context.l10n.questEdit,
|
||||
confirmLabel: context.l10n.commonEdit,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(context.l10n.questEditNotice, style: _caption),
|
||||
TextField(
|
||||
controller: title,
|
||||
decoration: InputDecoration(labelText: context.l10n.questName),
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(context.l10n.questEditNotice, style: _caption),
|
||||
TextField(
|
||||
controller: title,
|
||||
decoration: InputDecoration(labelText: context.l10n.questName),
|
||||
),
|
||||
TextField(
|
||||
controller: description,
|
||||
maxLines: 3,
|
||||
minLines: 1,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.questDescriptionOptional,
|
||||
),
|
||||
TextField(
|
||||
controller: description,
|
||||
maxLines: 3,
|
||||
minLines: 1,
|
||||
decoration: InputDecoration(labelText: context.l10n.questDescriptionOptional),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final newTitle = title.text.trim();
|
||||
final newDescription = description.text.trim();
|
||||
title.dispose();
|
||||
description.dispose();
|
||||
if (ok != true || newTitle.isEmpty) return;
|
||||
await _run(() => widget.repository.edit(
|
||||
detail.card.id,
|
||||
title: newTitle,
|
||||
description: newDescription,
|
||||
));
|
||||
await _run(
|
||||
() => widget.repository.edit(
|
||||
detail.card.id,
|
||||
title: newTitle,
|
||||
description: newDescription,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 서버 호출 한 번 — 실패는 알리고, 성공하면 상세를 다시 읽는다.
|
||||
@@ -546,8 +611,10 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
|
||||
/// 「시작하기」 — 진행중으로 바꾸고 실측 수집을 켠다.
|
||||
Future<void> _start(QuestDetail detail) async {
|
||||
final next =
|
||||
await widget.repository.advance(detail.card.id, QuestStage.inProgress);
|
||||
final next = await widget.repository.advance(
|
||||
detail.card.id,
|
||||
QuestStage.inProgress,
|
||||
);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_stage = next;
|
||||
@@ -562,27 +629,29 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
/// 이 값은 화면 진행률과 서버에 보낼 증거로만 쓴다.
|
||||
void _watch(QuestCard card) {
|
||||
_walk?.cancel();
|
||||
_walk = widget.repository.progressStream(card).listen(
|
||||
(value) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_live = value;
|
||||
if (card.goal > 0 && value >= card.goal) {
|
||||
_stage = QuestStage.completed;
|
||||
}
|
||||
});
|
||||
},
|
||||
onError: (Object error) {
|
||||
// 권한 거부·센서 부재. 진행 상태를 시작 전으로 되돌려야 사용자가 다시
|
||||
// 시도할 수 있고, 미동의 상태에서도 화면은 그대로 쓸 수 있다(B-27).
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_stage = QuestStage.notStarted;
|
||||
_live = null;
|
||||
});
|
||||
_fail(error);
|
||||
},
|
||||
);
|
||||
_walk = widget.repository
|
||||
.progressStream(card)
|
||||
.listen(
|
||||
(value) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_live = value;
|
||||
if (card.goal > 0 && value >= card.goal) {
|
||||
_stage = QuestStage.completed;
|
||||
}
|
||||
});
|
||||
},
|
||||
onError: (Object error) {
|
||||
// 권한 거부·센서 부재. 진행 상태를 시작 전으로 되돌려야 사용자가 다시
|
||||
// 시도할 수 있고, 미동의 상태에서도 화면은 그대로 쓸 수 있다(B-27).
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_stage = QuestStage.notStarted;
|
||||
_live = null;
|
||||
});
|
||||
_fail(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 명세 `518:88552` — *진행중 버튼 클릭 시 노출 · 취소 버튼 모달 종료 ·*
|
||||
@@ -596,8 +665,10 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
);
|
||||
if (!stop) return;
|
||||
_stopWatching();
|
||||
final next =
|
||||
await widget.repository.advance(detail.card.id, QuestStage.notStarted);
|
||||
final next = await widget.repository.advance(
|
||||
detail.card.id,
|
||||
QuestStage.notStarted,
|
||||
);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_stage = next;
|
||||
@@ -651,7 +722,8 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
// 기본 보상은 이미 원장에 있다. 광고는 그 위의 선택적 증분이다(원장 B-03 · C-122) —
|
||||
// 광고가 실패해도 기본 보상은 그대로다.
|
||||
final bonus =
|
||||
await showQuestAdBonus(context, bonusPop: detail.card.adBonusPop) ?? false;
|
||||
await showQuestAdBonus(context, bonusPop: detail.card.adBonusPop) ??
|
||||
false;
|
||||
if (!mounted) return;
|
||||
int? adPop;
|
||||
if (bonus) {
|
||||
@@ -674,8 +746,11 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
|
||||
await Navigator.of(context, rootNavigator: true).push<bool>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) =>
|
||||
QuestRewardScreen(detail: detail, reward: reward, adBonusPop: adPop),
|
||||
builder: (_) => QuestRewardScreen(
|
||||
detail: detail,
|
||||
reward: reward,
|
||||
adBonusPop: adPop,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (!mounted) return;
|
||||
@@ -730,31 +805,37 @@ class _QuestDetailScreenState extends State<QuestDetailScreen> {
|
||||
final permission = error is BackendException && error.code == 'E-PERM-01';
|
||||
ScaffoldMessenger.of(context)
|
||||
..hideCurrentSnackBar()
|
||||
..showSnackBar(SnackBar(
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
action: permission
|
||||
? SnackBarAction(
|
||||
label: context.l10n.openSettings,
|
||||
onPressed: openQuestPermissionSettings,
|
||||
)
|
||||
: null,
|
||||
));
|
||||
..showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
action: permission
|
||||
? SnackBarAction(
|
||||
label: context.l10n.openSettings,
|
||||
onPressed: openQuestPermissionSettings,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _warp(QuestAdWarpScreen screen) =>
|
||||
Navigator.of(context, rootNavigator: true).push<void>(
|
||||
MaterialPageRoute(builder: (_) => screen),
|
||||
);
|
||||
Future<void> _warp(QuestAdWarpScreen screen) => Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).push<void>(MaterialPageRoute(builder: (_) => screen));
|
||||
|
||||
Future<void> _report(String title) async {
|
||||
final reason = await Navigator.of(context, rootNavigator: true).push<String>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => ReportScreen(
|
||||
target: ModerationTarget(authorName: title, title: context.l10n.questNamed(title)),
|
||||
),
|
||||
),
|
||||
);
|
||||
final reason = await Navigator.of(context, rootNavigator: true)
|
||||
.push<String>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => ReportScreen(
|
||||
target: ModerationTarget(
|
||||
authorName: title,
|
||||
title: context.l10n.questNamed(title),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (reason != null && mounted) _toast(context.l10n.reportReceived);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user