약관 동의 화면에 개인정보처리방침 고지 · 보기 링크 추가

This commit is contained in:
Sn-Kinos
2026-10-12 00:03:46 +09:00
parent c42fd615a6
commit 6e0aa5d43c
2 changed files with 71 additions and 28 deletions
+34 -27
View File
@@ -13,7 +13,7 @@ import 'auth_repository.dart';
/// - 필수: 서비스 이용약관 · 개인정보 수집·이용 동의 · 만 14세 이상. /// - 필수: 서비스 이용약관 · 개인정보 수집·이용 동의 · 만 14세 이상.
/// - 선택: 마케팅 수신(기본 OFF). /// - 선택: 마케팅 수신(기본 OFF).
/// - 위치기반 서비스 약관은 여기서 받지 않는다 — 위치기능 최초 사용 직전에 따로 받는다. /// - 위치기반 서비스 약관은 여기서 받지 않는다 — 위치기능 최초 사용 직전에 따로 받는다.
/// - 개인정보처리방침은 동의 항목이 아니라 고지다 — 체크 칸 없이 목록 끝에 안내와 보기 링크만 둔다. /// - 개인정보처리방침은 동의 항목이 아니라 고지다 — 체크 칸 없이 하단 버튼 위에 안내와 보기 링크만 둔다.
/// ///
/// 약관 본문은 확정 문구를 받기 전까지 시안의 자리 표시 문구다 — 받으면 /// 약관 본문은 확정 문구를 받기 전까지 시안의 자리 표시 문구다 — 받으면
/// [termsPlaceholderBody] 와 [signupTermsVersion] 을 함께 바꾼다(동의 기록에 버전이 남는다). /// [termsPlaceholderBody] 와 [signupTermsVersion] 을 함께 바꾼다(동의 기록에 버전이 남는다).
@@ -143,7 +143,39 @@ class _TermsScreenState extends State<TermsScreen> {
bottomNavigationBar: SafeArea( bottomNavigationBar: SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.all(AppSpace.s4), padding: const EdgeInsets.all(AppSpace.s4),
child: _buttons(), child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 개인정보처리방침 — 동의 항목과 구분한 고지. 체크 칸이 없고 「보기」로 본문을 연다.
// 목록 끝에 두면 iPhone 11 높이에서 하단 버튼 뒤로 가려지므로 버튼 위에 고정한다.
Padding(
key: const ValueKey('privacy-policy-notice'),
padding: const EdgeInsets.only(bottom: AppSpace.s2),
child: Row(
children: [
const Expanded(
child: Text(
'개인정보 처리 내용은 개인정보처리방침에서 확인할 수 있습니다.',
style: TextStyle(
fontFamily: AppFonts.display,
fontFamilyFallback: [AppFonts.body],
fontSize: 12,
height: 1.36,
color: AppColors.onCosmicMuted,
),
),
),
TextButton(
key: const ValueKey('privacy-policy-link'),
onPressed: _showPrivacyPolicy,
child: const Text('보기'),
),
],
),
),
_buttons(),
],
),
), ),
), ),
body: ListView( body: ListView(
@@ -206,31 +238,6 @@ class _TermsScreenState extends State<TermsScreen> {
), ),
), ),
], ],
// 개인정보처리방침 — 동의 항목과 구분한 고지. 체크 칸이 없고 「보기」로 본문을 연다.
Padding(
padding: const EdgeInsets.symmetric(vertical: AppSpace.s4),
child: Row(
children: [
const Expanded(
child: Text(
'개인정보 처리 내용은 개인정보처리방침에서 확인할 수 있습니다.',
style: TextStyle(
fontFamily: AppFonts.display,
fontFamilyFallback: [AppFonts.body],
fontSize: 12,
height: 1.36,
color: AppColors.onCosmicMuted,
),
),
),
TextButton(
key: const ValueKey('privacy-policy-link'),
onPressed: _showPrivacyPolicy,
child: const Text('보기'),
),
],
),
),
], ],
), ),
); );
+37 -1
View File
@@ -65,7 +65,6 @@ void main() {
} }
// 개인정보처리방침은 체크 칸 없는 고지 · 보기 링크. // 개인정보처리방침은 체크 칸 없는 고지 · 보기 링크.
final policy = find.byKey(const ValueKey('privacy-policy-link')); final policy = find.byKey(const ValueKey('privacy-policy-link'));
await tester.scrollUntilVisible(policy, 200);
await tester.tap(policy); await tester.tap(policy);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('개인정보처리방침'), findsOneWidget); expect(find.text('개인정보처리방침'), findsOneWidget);
@@ -81,6 +80,43 @@ void main() {
expect(find.byType(BlockingProgress), findsNothing); expect(find.byType(BlockingProgress), findsNothing);
}); });
testWidgets('개인정보처리방침 고지는 스크롤 없이 하단 버튼 위에 보이고 체크 칸이 없다', (tester) async {
// iPhone 11 — 414x896pt · 상단 48 · 하단 34.
tester.view.physicalSize = const Size(828, 1792);
tester.view.devicePixelRatio = 2;
tester.view.padding = const FakeViewPadding(top: 96, bottom: 68);
addTearDown(tester.view.reset);
await tester.pumpWidget(const MaterialApp(home: TermsScreen()));
await tester.pumpAndSettle();
final notice = find.byKey(const ValueKey('privacy-policy-notice'));
expect(
find.descendant(
of: notice,
matching: find.text('개인정보 처리 내용은 개인정보처리방침에서 확인할 수 있습니다.'),
),
findsOneWidget,
);
final link = find.descendant(of: notice, matching: find.text('보기'));
expect(link, findsOneWidget);
expect(
find.descendant(of: notice, matching: find.byType(ImageIcon)),
findsNothing,
);
// 화면 안 · 「이전」 버튼 위.
expect(tester.getRect(link).bottom, lessThanOrEqualTo(896 - 34));
expect(
tester.getRect(notice).bottom,
lessThanOrEqualTo(
tester.getRect(find.widgetWithText(FilledButton, '이전')).top,
),
);
await tester.tap(link);
await tester.pumpAndSettle();
expect(find.text('개인정보처리방침'), findsOneWidget);
});
testWidgets('이미 동의한 계정은 약관 없이 HOME', (tester) async { testWidgets('이미 동의한 계정은 약관 없이 HOME', (tester) async {
final auth = AuthRepository( final auth = AuthRepository(
providers: [ providers: [