From 6e0aa5d43cce951bbccf04e44830212973b2220a Mon Sep 17 00:00:00 2001 From: Sn-Kinos Date: Mon, 12 Oct 2026 00:03:46 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=BD=EA=B4=80=20=EB=8F=99=EC=9D=98=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=20=EA=B0=9C=EC=9D=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=B2=98=EB=A6=AC=EB=B0=A9=EC=B9=A8=20=EA=B3=A0?= =?UTF-8?q?=EC=A7=80=20=C2=B7=20=EB=B3=B4=EA=B8=B0=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/features/auth/signup_screens.dart | 61 +++++++++++++---------- app/test/signup_terms_test.dart | 38 +++++++++++++- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/app/lib/features/auth/signup_screens.dart b/app/lib/features/auth/signup_screens.dart index a440364..8fbba27 100644 --- a/app/lib/features/auth/signup_screens.dart +++ b/app/lib/features/auth/signup_screens.dart @@ -13,7 +13,7 @@ import 'auth_repository.dart'; /// - 필수: 서비스 이용약관 · 개인정보 수집·이용 동의 · 만 14세 이상. /// - 선택: 마케팅 수신(기본 OFF). /// - 위치기반 서비스 약관은 여기서 받지 않는다 — 위치기능 최초 사용 직전에 따로 받는다. -/// - 개인정보처리방침은 동의 항목이 아니라 고지다 — 체크 칸 없이 목록 끝에 안내와 보기 링크만 둔다. +/// - 개인정보처리방침은 동의 항목이 아니라 고지다 — 체크 칸 없이 하단 버튼 위에 안내와 보기 링크만 둔다. /// /// 약관 본문은 확정 문구를 받기 전까지 시안의 자리 표시 문구다 — 받으면 /// [termsPlaceholderBody] 와 [signupTermsVersion] 을 함께 바꾼다(동의 기록에 버전이 남는다). @@ -143,7 +143,39 @@ class _TermsScreenState extends State { bottomNavigationBar: SafeArea( child: Padding( 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( @@ -206,31 +238,6 @@ class _TermsScreenState extends State { ), ), ], - // 개인정보처리방침 — 동의 항목과 구분한 고지. 체크 칸이 없고 「보기」로 본문을 연다. - 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('보기'), - ), - ], - ), - ), ], ), ); diff --git a/app/test/signup_terms_test.dart b/app/test/signup_terms_test.dart index 6a0fc2f..df5d4e5 100644 --- a/app/test/signup_terms_test.dart +++ b/app/test/signup_terms_test.dart @@ -65,7 +65,6 @@ void main() { } // 개인정보처리방침은 체크 칸 없는 고지 · 보기 링크. final policy = find.byKey(const ValueKey('privacy-policy-link')); - await tester.scrollUntilVisible(policy, 200); await tester.tap(policy); await tester.pumpAndSettle(); expect(find.text('개인정보처리방침'), findsOneWidget); @@ -81,6 +80,43 @@ void main() { 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 { final auth = AuthRepository( providers: [