사용자 화면 문구·표본 데이터 · 퀘스트 참여 흐름 · HOME 진입 구획 · 미니맵 · 공통 확인 창 배치 수정
This commit is contained in:
@@ -179,6 +179,7 @@ GoRouter buildRouter(AuthRepository auth, {Repositories? repositories}) {
|
||||
push: repos.push,
|
||||
auth: auth,
|
||||
campaigns: repos.campaign,
|
||||
insides: repos.inside,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../i18n/app_locale.dart';
|
||||
import '../theme/tokens.dart';
|
||||
|
||||
/// 앱 공통 확인 창 — Figma `2066:17799`(행성 생성 확인) · `554:24669`(설정 확인 팝업).
|
||||
///
|
||||
/// 카드 312 폭 · #282828 r12 · 안쪽 24/16 · 문구 16/600 가운데 정렬,
|
||||
/// 그 아래 **취소(흰 테두리) · 실행(분홍 채움)을 가로로 반씩**(48 높이 · 간격 8 · r8).
|
||||
/// 단일 버튼 알림(Figma `511:86714` · `554:23103`)은 실행 버튼 하나가 폭을 다 쓴다.
|
||||
///
|
||||
/// [content] 는 입력 칸이 있는 창(반려 사유 · 인증 제출 등)에서 문구 대신 넣는다.
|
||||
class AppDialog extends StatelessWidget {
|
||||
const AppDialog({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.body,
|
||||
this.content,
|
||||
this.cancelLabel,
|
||||
required this.confirmLabel,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String? body;
|
||||
final Widget? content;
|
||||
|
||||
/// null 이면 실행 버튼 하나만 둔다.
|
||||
final String? cancelLabel;
|
||||
final String confirmLabel;
|
||||
|
||||
static const _shape = RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(AppRadius.sm)),
|
||||
);
|
||||
|
||||
static TextStyle _text(double size, FontWeight weight, Color color) =>
|
||||
TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: size,
|
||||
fontWeight: weight,
|
||||
height: 1.5,
|
||||
letterSpacing: size * -0.025,
|
||||
color: color,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget button(String label, bool value, {required bool filled}) {
|
||||
final text = Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: _text(
|
||||
16,
|
||||
FontWeight.w600,
|
||||
filled ? AppColors.onCosmicAccent : AppColors.onCosmic,
|
||||
).copyWith(height: 1),
|
||||
);
|
||||
void pop() => Navigator.of(context).pop(value);
|
||||
return Expanded(
|
||||
child: filled
|
||||
? FilledButton(
|
||||
onPressed: pop,
|
||||
style: FilledButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(48),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
backgroundColor: AppColors.cosmicAccent,
|
||||
shape: _shape,
|
||||
),
|
||||
child: text,
|
||||
)
|
||||
: OutlinedButton(
|
||||
onPressed: pop,
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(48),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
side: const BorderSide(color: AppColors.onCosmic),
|
||||
shape: _shape,
|
||||
),
|
||||
child: text,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Dialog(
|
||||
backgroundColor: const Color(0xFF282828), // Figma 2066:17799 fill
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 31.5, vertical: 24),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(AppRadius.md)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: _text(16, FontWeight.w600, AppColors.onCosmic),
|
||||
),
|
||||
if (body case final b?) ...[
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
b,
|
||||
textAlign: TextAlign.center,
|
||||
style: _text(16, FontWeight.w500, AppColors.onCosmic)
|
||||
.copyWith(height: 1.4),
|
||||
),
|
||||
],
|
||||
if (content case final c?) ...[
|
||||
const SizedBox(height: 16),
|
||||
c,
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
if (cancelLabel case final c?) ...[
|
||||
button(c, false, filled: false),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
button(confirmLabel, true, filled: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const _barrier = Color(0xB3000000);
|
||||
|
||||
/// 취소 · 실행 두 갈래. 실행이면 true. [confirmLabel] 기본은 「변경」.
|
||||
Future<bool> showConfirmDialog(
|
||||
BuildContext context,
|
||||
String title, {
|
||||
String? body,
|
||||
Widget? content,
|
||||
String? cancelLabel,
|
||||
String? confirmLabel,
|
||||
}) async {
|
||||
final r = await showDialog<bool>(
|
||||
context: context,
|
||||
barrierColor: _barrier,
|
||||
builder: (context) => AppDialog(
|
||||
title: title,
|
||||
body: body,
|
||||
content: content,
|
||||
cancelLabel: cancelLabel ?? context.l10n.commonCancel,
|
||||
confirmLabel: confirmLabel ?? context.l10n.commonChange,
|
||||
),
|
||||
);
|
||||
return r ?? false;
|
||||
}
|
||||
|
||||
/// 확인 하나뿐인 알림 — Figma `511:86714`(타이틀 가운데 · 확인 버튼 가운데).
|
||||
Future<void> showAlertDialog(
|
||||
BuildContext context,
|
||||
String title, {
|
||||
String? body,
|
||||
String? confirmLabel,
|
||||
}) => showDialog<void>(
|
||||
context: context,
|
||||
barrierColor: _barrier,
|
||||
builder: (context) => AppDialog(
|
||||
title: title,
|
||||
body: body,
|
||||
confirmLabel: confirmLabel ?? context.l10n.commonConfirm,
|
||||
),
|
||||
);
|
||||
@@ -1,39 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/tokens.dart';
|
||||
|
||||
/// 표본 데이터 알림(G-08) — 본문을 밀지 않도록 앱바 오른쪽에 작은 「MOCK」 알약으로 둔다.
|
||||
/// 사유 문구는 길게 눌렀을 때와 스크린리더로 읽힌다.
|
||||
class MockTag extends StatelessWidget {
|
||||
const MockTag({super.key, required this.note});
|
||||
|
||||
final String note;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Tooltip(
|
||||
message: note,
|
||||
child: Semantics(
|
||||
label: 'MOCK · $note',
|
||||
excludeSemantics: true,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(right: 16),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(AppRadius.sm),
|
||||
border: Border.all(color: AppColors.neonViolet),
|
||||
),
|
||||
child: Text(
|
||||
'MOCK',
|
||||
style: const TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.2,
|
||||
letterSpacing: -0.25,
|
||||
color: AppColors.neonViolet,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user