diff --git a/.gitignore b/.gitignore
index afa86de..70c3083 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,7 +111,7 @@ lib/generated_plugin_registrant.dart
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
-
+ios/Podfile.lock
## User settings
xcuserdata/
diff --git a/assets/icons/bubble.svg b/assets/icons/bubble.svg
new file mode 100644
index 0000000..cb7118f
--- /dev/null
+++ b/assets/icons/bubble.svg
@@ -0,0 +1,31 @@
+
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
deleted file mode 100644
index 55d7bf5..0000000
--- a/ios/Podfile.lock
+++ /dev/null
@@ -1,124 +0,0 @@
-PODS:
- - Firebase/Auth (11.10.0):
- - Firebase/CoreOnly
- - FirebaseAuth (~> 11.10.0)
- - Firebase/CoreOnly (11.10.0):
- - FirebaseCore (~> 11.10.0)
- - firebase_auth (5.5.2):
- - Firebase/Auth (= 11.10.0)
- - firebase_core
- - Flutter
- - firebase_core (3.13.0):
- - Firebase/CoreOnly (= 11.10.0)
- - Flutter
- - FirebaseAppCheckInterop (11.11.0)
- - FirebaseAuth (11.10.0):
- - FirebaseAppCheckInterop (~> 11.0)
- - FirebaseAuthInterop (~> 11.0)
- - FirebaseCore (~> 11.10.0)
- - FirebaseCoreExtension (~> 11.10.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/Environment (~> 8.0)
- - GTMSessionFetcher/Core (< 5.0, >= 3.4)
- - RecaptchaInterop (~> 101.0)
- - FirebaseAuthInterop (11.11.0)
- - FirebaseCore (11.10.0):
- - FirebaseCoreInternal (~> 11.10.0)
- - GoogleUtilities/Environment (~> 8.0)
- - GoogleUtilities/Logger (~> 8.0)
- - FirebaseCoreExtension (11.10.0):
- - FirebaseCore (~> 11.10.0)
- - FirebaseCoreInternal (11.10.0):
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
- - Flutter (1.0.0)
- - GoogleUtilities/AppDelegateSwizzler (8.0.2):
- - GoogleUtilities/Environment
- - GoogleUtilities/Logger
- - GoogleUtilities/Network
- - GoogleUtilities/Privacy
- - GoogleUtilities/Environment (8.0.2):
- - GoogleUtilities/Privacy
- - GoogleUtilities/Logger (8.0.2):
- - GoogleUtilities/Environment
- - GoogleUtilities/Privacy
- - GoogleUtilities/Network (8.0.2):
- - GoogleUtilities/Logger
- - "GoogleUtilities/NSData+zlib"
- - GoogleUtilities/Privacy
- - GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (8.0.2)":
- - GoogleUtilities/Privacy
- - GoogleUtilities/Privacy (8.0.2)
- - GoogleUtilities/Reachability (8.0.2):
- - GoogleUtilities/Logger
- - GoogleUtilities/Privacy
- - GTMSessionFetcher/Core (4.4.0)
- - kakao_flutter_sdk_common (1.9.7-3):
- - Flutter
- - RecaptchaInterop (101.0.0)
- - screen_protector (1.2.1):
- - Flutter
- - ScreenProtectorKit (~> 1.3.1)
- - ScreenProtectorKit (1.3.1)
- - shared_preferences_foundation (0.0.1):
- - Flutter
- - FlutterMacOS
-
-DEPENDENCIES:
- - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- - Flutter (from `Flutter`)
- - kakao_flutter_sdk_common (from `.symlinks/plugins/kakao_flutter_sdk_common/ios`)
- - screen_protector (from `.symlinks/plugins/screen_protector/ios`)
- - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
-
-SPEC REPOS:
- trunk:
- - Firebase
- - FirebaseAppCheckInterop
- - FirebaseAuth
- - FirebaseAuthInterop
- - FirebaseCore
- - FirebaseCoreExtension
- - FirebaseCoreInternal
- - GoogleUtilities
- - GTMSessionFetcher
- - RecaptchaInterop
- - ScreenProtectorKit
-
-EXTERNAL SOURCES:
- firebase_auth:
- :path: ".symlinks/plugins/firebase_auth/ios"
- firebase_core:
- :path: ".symlinks/plugins/firebase_core/ios"
- Flutter:
- :path: Flutter
- kakao_flutter_sdk_common:
- :path: ".symlinks/plugins/kakao_flutter_sdk_common/ios"
- screen_protector:
- :path: ".symlinks/plugins/screen_protector/ios"
- shared_preferences_foundation:
- :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
-
-SPEC CHECKSUMS:
- Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
- firebase_auth: e37065f3f80ff90580c13ad0e5a48e3bb8d2ad77
- firebase_core: 432718558359a8c08762151b5f49bb0f093eb6e0
- FirebaseAppCheckInterop: f23709c9ce92d810aa53ff4ce12ad3e666a3c7be
- FirebaseAuth: c4146bdfdc87329f9962babd24dae89373f49a32
- FirebaseAuthInterop: ac22ed402c2f4e3a8c63ebd3278af9a06073c1be
- FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
- FirebaseCoreExtension: 6f357679327f3614e995dc7cf3f2d600bdc774ac
- FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
- Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
- GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
- GTMSessionFetcher: 75b671f9e551e4c49153d4c4f8659ef4f559b970
- kakao_flutter_sdk_common: 3dc8492c202af7853585d151490b1c5c6b7576cb
- RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
- screen_protector: 6f92086bd2f2f4b54f54913289b9d1310610140b
- ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4
- shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
-
-PODFILE CHECKSUM: f8c2dcdfb50bb67645580d28a6bf814fca30bdec
-
-COCOAPODS: 1.16.2
diff --git a/lib/auth/presentation/pages/congratulation/congratulation_page.dart b/lib/auth/presentation/pages/congratulation/congratulation_page.dart
new file mode 100644
index 0000000..a3d7180
--- /dev/null
+++ b/lib/auth/presentation/pages/congratulation/congratulation_page.dart
@@ -0,0 +1,117 @@
+import 'package:code_l/auth/presentation/pages/congratulation/widgets/congratulation_app_bar.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import '../../../../core/utills/design/app_colors.dart';
+import '../../../../core/utills/design/app_gaps.dart';
+import '../../../../core/utills/design/app_typography.dart';
+import 'widgets/congratulation_confirm_button.dart';
+
+class CongratulationPage extends StatelessWidget {
+ const CongratulationPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: const CongratulationAppBar(),
+ body: _buildContentField(),
+ );
+ }
+
+ Widget _buildContentField() {
+ return SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 30),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SvgPicture.asset("assets/icons/logo_with_image.svg"),
+ SizedBox(height: AppGaps.gap12),
+ Text(
+ "가입을 축하합니다!",
+ style: AppTypography.header2.copyWith(
+ color: AppColors.grey900,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ SizedBox(height: 54),
+ Row(
+ children: [Text("개성있는 익명 활동 🤫", style: AppTypography.subtitle3)],
+ ),
+ Flexible(
+ child: Text(
+ "자신의 얼굴을 바로 공개하지 않고도 자유롭게 소통할 수 있어요.",
+ style: AppTypography.body2,
+ ),
+ ),
+ SizedBox(height: AppGaps.gap20),
+ Row(
+ children: [
+ Text("안심할 수 있는 공개 시스템 🔐", style: AppTypography.subtitle3),
+ ],
+ ),
+ Flexible(
+ child: Text(
+ "원치 않는 사람에게 얼굴이 공개될 걱정 없이, 내가 선택한 사람에게만 보여줄 수 있어요.",
+ style: AppTypography.body2,
+ ),
+ ),
+ SizedBox(height: 54),
+ Container(
+ height: 114,
+ width: double.infinity,
+ alignment: Alignment.center,
+ color: AppColors.grey100,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap16),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("코드 프로필이란?", style: AppTypography.caption1),
+ SizedBox(height: AppGaps.gap8),
+ Flexible(
+ child: Text(
+ "이름 대신 코드 네임과 개성있는 정보를 통해 나를 표현하는 Code : L의 특별한 프로필 입니다. 관심사, 취향, 스타일 등 나만의 프로필로 나를 보여주세요!",
+ style: AppTypography.caption1.copyWith(
+ color: AppColors.grey700,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ SizedBox(height: 120),
+ Padding(
+ padding: const EdgeInsets.only(left: 18.0),
+ child: SvgPicture.asset(
+ "assets/icons/bubble.svg",
+ width: double.infinity,
+ height: 40,
+ ),
+ ),
+
+ Padding(
+ padding: const EdgeInsets.all(AppGaps.gap4),
+ child: CongratulationConfirmButton(
+ enabled: true,
+ text: "코드 프로필 작성하기",
+ onPressed: () {},
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/auth/presentation/pages/congratulation/widgets/congratulation_app_bar.dart b/lib/auth/presentation/pages/congratulation/widgets/congratulation_app_bar.dart
new file mode 100644
index 0000000..dab9184
--- /dev/null
+++ b/lib/auth/presentation/pages/congratulation/widgets/congratulation_app_bar.dart
@@ -0,0 +1,40 @@
+import 'package:code_l/core/utills/design/app_gaps.dart';
+import 'package:flutter/material.dart';
+
+import '../../../../../core/utills/design/app_colors.dart';
+import '../../../../../core/utills/design/app_typography.dart';
+
+class CongratulationAppBar extends StatelessWidget
+ implements PreferredSizeWidget {
+ const CongratulationAppBar({super.key});
+
+ @override
+ Size get preferredSize => Size.fromHeight(56);
+ @override
+ Widget build(BuildContext context) {
+ return SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(
+ width: AppGaps.gap36,
+ ),
+ Text(
+ "회원가입",
+ style: AppTypography.subtitle2.copyWith(color: AppColors.grey900),
+ ),
+ IconButton(
+ icon: const Icon(Icons.close),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/congratulation/widgets/congratulation_confirm_button.dart b/lib/auth/presentation/pages/congratulation/widgets/congratulation_confirm_button.dart
new file mode 100644
index 0000000..1e95f38
--- /dev/null
+++ b/lib/auth/presentation/pages/congratulation/widgets/congratulation_confirm_button.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/cupertino.dart';
+
+import '../../../../../core/utills/design/app_colors.dart';
+import '../../../../../core/utills/design/app_typography.dart';
+
+class CongratulationConfirmButton extends StatelessWidget {
+ const CongratulationConfirmButton({
+ super.key,
+ required this.enabled,
+ this.onPressed,
+ this.text = "확인",
+ });
+
+ final bool enabled;
+ final VoidCallback? onPressed;
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: enabled ? onPressed : null,
+ child: Container(
+ height: 54,
+ width: double.infinity,
+ padding: EdgeInsets.symmetric(vertical: 16),
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ color: enabled ? AppColors.primary : AppColors.grey200,
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Text(
+ text,
+ style: AppTypography.subtitle2.copyWith(
+ color: enabled ? AppColors.white : AppColors.grey400,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/login/login_viewmodel.dart b/lib/auth/presentation/pages/login/login_viewmodel.dart
index 830484f..68b315d 100644
--- a/lib/auth/presentation/pages/login/login_viewmodel.dart
+++ b/lib/auth/presentation/pages/login/login_viewmodel.dart
@@ -15,10 +15,9 @@ class LoginViewModel extends ChangeNotifier {
try {
bool installed = await isKakaoTalkInstalled();
- OAuthToken token =
- installed
- ? await UserApi.instance.loginWithKakaoTalk()
- : await UserApi.instance.loginWithKakaoAccount();
+ OAuthToken token = installed
+ ? await UserApi.instance.loginWithKakaoTalk()
+ : await UserApi.instance.loginWithKakaoAccount();
final user = await UserApi.instance.me();
diff --git a/lib/auth/presentation/pages/terms_and_conditions/providers.dart b/lib/auth/presentation/pages/terms_and_conditions/providers.dart
new file mode 100644
index 0000000..578c774
--- /dev/null
+++ b/lib/auth/presentation/pages/terms_and_conditions/providers.dart
@@ -0,0 +1,5 @@
+import 'package:code_l/auth/presentation/pages/terms_and_conditions/terms_and_conditions_viewmodel.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final termsAndConditionsViewModelProvider =
+ ChangeNotifierProvider((ref) => TermsAndConditionsViewmodel());
diff --git a/lib/auth/presentation/pages/terms_and_conditions/terms_and_condition_page.dart b/lib/auth/presentation/pages/terms_and_conditions/terms_and_condition_page.dart
new file mode 100644
index 0000000..704acc9
--- /dev/null
+++ b/lib/auth/presentation/pages/terms_and_conditions/terms_and_condition_page.dart
@@ -0,0 +1,132 @@
+import 'package:code_l/auth/presentation/pages/terms_and_conditions/providers.dart';
+import 'package:code_l/auth/presentation/pages/woman/woman_verification_Page.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../../../../core/utills/design/app_colors.dart';
+import '../../../../core/utills/design/app_gaps.dart';
+import '../../../../core/utills/design/app_typography.dart';
+import '../../../../sign_up/presentation/widgets/sign_up_confirm_button.dart';
+import '../../widgets/auth_confirm_button.dart';
+import 'widgets/terms_and_conditions_app_bar.dart';
+import '../login/login_page.dart';
+
+class TermsAndConditionPage extends ConsumerWidget {
+ const TermsAndConditionPage({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final viewmodel = ref.watch(termsAndConditionsViewModelProvider);
+ final notifier = ref.read(termsAndConditionsViewModelProvider.notifier);
+ String getLabel(int index) {
+ switch (index) {
+ case 1:
+ return "서비스 이용 약관 동의 (필수)";
+ case 2:
+ return "개인정보 수집 및 이용 동의 (필수)";
+ case 3:
+ return "민감정보 수집 및 이용 동의 (필수)";
+ case 4:
+ return "마케팅 정보 수신 동의 (선택)";
+ default:
+ return "";
+ }
+ }
+
+ return Scaffold(
+ appBar: const AgreeToTermsAndConditionsAppBar(),
+ bottomNavigationBar: Padding(
+ padding: const EdgeInsets.all(AppGaps.gap20),
+ child: AuthConfirmButton(
+ enabled: viewmodel.isValid,
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const WomanVerificationPage()),
+ );
+ },
+ ),
+ ),
+ body: SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap24),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 20),
+ Text(
+ "서비스 이용에 필요한 약관 및 정책에\n동의해주세요",
+ style: AppTypography.subtitle1.copyWith(
+ color: AppColors.grey900,
+ ),
+ ),
+ const SizedBox(height: 60),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ // "모두 동의합니다." Row
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "모두 동의합니다.",
+ style: AppTypography.subtitle2.copyWith(
+ color: viewmodel.checkState[0]
+ ? AppColors.grey900
+ : AppColors.grey500,
+ ),
+ ),
+ IconButton(
+ onPressed: () => notifier.toggleAll(),
+ iconSize: 36,
+ icon: Icon(
+ Icons.check_circle_outline,
+ color: viewmodel.checkState[0]
+ ? AppColors.grey900
+ : AppColors.grey500,
+ ),
+ ),
+ ],
+ ),
+ // Individual agreement rows
+ for (int i = 1; i < viewmodel.checkState.length; i++)
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ TextButton(
+ style: TextButton.styleFrom(
+ padding: EdgeInsets.zero,
+ ),
+ onPressed: () {},
+ child: Text(
+ getLabel(i),
+ style: AppTypography.body2.copyWith(
+ decoration: TextDecoration.underline,
+ color: viewmodel.checkState[i]
+ ? AppColors.grey900
+ : AppColors.grey500,
+ ),
+ ),
+ ),
+ IconButton(
+ onPressed: () => notifier.toggle(i),
+ iconSize: 24,
+ icon: Icon(
+ Icons.check,
+ color: viewmodel.checkState[i]
+ ? AppColors.grey900
+ : AppColors.grey500,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/terms_and_conditions/terms_and_conditions_viewmodel.dart b/lib/auth/presentation/pages/terms_and_conditions/terms_and_conditions_viewmodel.dart
new file mode 100644
index 0000000..4c6e039
--- /dev/null
+++ b/lib/auth/presentation/pages/terms_and_conditions/terms_and_conditions_viewmodel.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+class TermsAndConditionsViewmodel extends ChangeNotifier {
+ List checkState = [false, false, false, false, false];
+ bool isValid = false;
+ void toggle(int index) {
+ checkState[index] = !checkState[index];
+
+ if (index > 0) {
+ final allChecked = checkState.sublist(1).every((e) => e);
+ checkState[0] = allChecked;
+ }
+ if (checkState.sublist(1, 4).every((checked) => checked)) {
+ isValid = true;
+ } else {
+ isValid = false;
+ }
+ notifyListeners();
+ }
+
+ void toggleAll() {
+ final allAgree = !checkState[0];
+ checkState = [allAgree, for (int i = 1; i < checkState.length; i++) allAgree];
+ if (checkState.sublist(1, 4).every((checked) => checked)) {
+ isValid = true;
+ } else {
+ isValid = false;
+ }
+ notifyListeners();
+ }
+}
diff --git a/lib/auth/presentation/pages/terms_and_conditions/widgets/terms_and_conditions_app_bar.dart b/lib/auth/presentation/pages/terms_and_conditions/widgets/terms_and_conditions_app_bar.dart
new file mode 100644
index 0000000..b16db4e
--- /dev/null
+++ b/lib/auth/presentation/pages/terms_and_conditions/widgets/terms_and_conditions_app_bar.dart
@@ -0,0 +1,41 @@
+import 'package:code_l/core/utills/design/app_typography.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+
+import '../../../../../core/utills/design/app_colors.dart';
+
+class AgreeToTermsAndConditionsAppBar extends StatelessWidget
+ implements PreferredSizeWidget {
+ const AgreeToTermsAndConditionsAppBar({super.key});
+ @override
+ Size get preferredSize => Size.fromHeight(56);
+
+ @override
+ Widget build(BuildContext context) {
+ return SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ IconButton(
+ icon: const Icon(Icons.arrow_back_ios_new_rounded),
+ onPressed: () => Navigator.pop(context),
+ ),
+ Text(
+ "서비스 이용 약관 및 정책",
+ style: AppTypography.subtitle2.copyWith(color: AppColors.grey800),
+ ),
+ IconButton(
+ icon: const Icon(Icons.close),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/woman/providers.dart b/lib/auth/presentation/pages/woman/providers.dart
new file mode 100644
index 0000000..1bfd11e
--- /dev/null
+++ b/lib/auth/presentation/pages/woman/providers.dart
@@ -0,0 +1,5 @@
+import 'package:code_l/auth/presentation/pages/woman/woman_verification_viewmodel.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final womanViewmodelProvider =
+ ChangeNotifierProvider((ref) => WomanVerificationViewmodel());
diff --git a/lib/auth/presentation/pages/woman/widgets/woman_verification_app_bar.dart b/lib/auth/presentation/pages/woman/widgets/woman_verification_app_bar.dart
new file mode 100644
index 0000000..2a96d2d
--- /dev/null
+++ b/lib/auth/presentation/pages/woman/widgets/woman_verification_app_bar.dart
@@ -0,0 +1,40 @@
+import 'package:code_l/core/utills/design/app_gaps.dart';
+import 'package:flutter/material.dart';
+
+import '../../../../../core/utills/design/app_colors.dart';
+import '../../../../../core/utills/design/app_typography.dart';
+
+class WomanVerificationAppBar extends StatelessWidget
+ implements PreferredSizeWidget {
+ const WomanVerificationAppBar({super.key});
+
+ @override
+ Size get preferredSize => Size.fromHeight(56);
+ @override
+ Widget build(BuildContext context) {
+ return SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(
+ width: AppGaps.gap36,
+ ),
+ Text(
+ "여성확인 안내",
+ style: AppTypography.subtitle2.copyWith(color: AppColors.grey900),
+ ),
+ IconButton(
+ icon: const Icon(Icons.close),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/woman/woman_verification_Page.dart b/lib/auth/presentation/pages/woman/woman_verification_Page.dart
new file mode 100644
index 0000000..4370524
--- /dev/null
+++ b/lib/auth/presentation/pages/woman/woman_verification_Page.dart
@@ -0,0 +1,273 @@
+import 'dart:developer';
+
+import 'package:code_l/auth/presentation/pages/woman/providers.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:http/http.dart' as ref;
+
+import '../../../../core/utills/design/app_colors.dart';
+import '../../../../core/utills/design/app_gaps.dart';
+import '../../../../core/utills/design/app_typography.dart';
+import '../../../../sign_up/presentation/widgets/sign_up_confirm_button.dart';
+import '../congratulation/congratulation_page.dart';
+import 'widgets/woman_verification_app_bar.dart';
+import '../login/login_page.dart';
+
+class WomanVerificationPage extends ConsumerWidget {
+ const WomanVerificationPage({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final viewModel = ref.watch(womanViewmodelProvider);
+ final notifier = ref.read(womanViewmodelProvider.notifier);
+ return Scaffold(
+ appBar: WomanVerificationAppBar(),
+ bottomNavigationBar: Padding(
+ padding: const EdgeInsets.all(AppGaps.gap20),
+ child: ConfirmButton(
+ enabled: true,
+ onPressed: () {
+ _buildBottomSheetField(context, viewModel, notifier);
+ },
+ ),
+ ),
+ body: _buildInformationField(),
+ );
+ }
+
+ Future _buildBottomSheetField(context, viewModel, notifier) async {
+ return showModalBottomSheet(
+ context: context,
+ builder: (BuildContext context) {
+ return Consumer(
+ builder: (context, ref, _) {
+ final viewModel = ref.watch(womanViewmodelProvider);
+ final notifier = ref.read(womanViewmodelProvider.notifier);
+ return Container(
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(AppGaps.gap20),
+ topRight: Radius.circular(AppGaps.gap20),
+ ),
+ color: AppColors.white,
+ ),
+ height: MediaQuery.sizeOf(context).height * 0.5,
+ child: Center(
+ child: Padding(
+ padding: const EdgeInsets.all(AppGaps.gap20),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "꼭 확인해 주세요",
+ style: AppTypography.subtitle2.copyWith(
+ color: AppColors.grey900,
+ ),
+ ),
+ IconButton(
+ onPressed: () => Navigator.pop(context),
+ icon: Icon(Icons.close),
+ ),
+ ],
+ ),
+ SizedBox(height: AppGaps.gap20),
+ Flexible(
+ child: Text(
+ "code:L은 여러분의 안전을 소중히 생각합니다.\n해당 확인서는 여성들만의 안전한 커뮤니티를 함께 지키기 위한 약속입니다.",
+ style: AppTypography.subtitle2.copyWith(
+ color: AppColors.grey900,
+ ),
+ ),
+ ),
+ SizedBox(height: AppGaps.gap20),
+ Row(
+ children: [
+ Text(
+ "1",
+ style: AppTypography.subtitle3.copyWith(
+ color: AppColors.grey800,
+ ),
+ ),
+ SizedBox(width: AppGaps.gap16),
+ Flexible(
+ child: Text(
+ "본 서비스가 여성들끼리의 소중한 인연을 위한 플랫폼임을 이해했으며, 여성 사용자임을 확인합니다.",
+ style: AppTypography.body2.copyWith(
+ color: AppColors.grey800,
+ ),
+ ),
+ ),
+ ],
+ ),
+ SizedBox(height: AppGaps.gap20),
+ Row(
+ children: [
+ Text(
+ "2",
+ style: AppTypography.subtitle3.copyWith(
+ color: AppColors.grey800,
+ ),
+ ),
+ SizedBox(width: AppGaps.gap16),
+ Flexible(
+ child: Text(
+ "여성이 아님에도 가입할 경우 발생하는 모든 법적 책임은 사용자 본인에게 있습니다.",
+ style: AppTypography.body2.copyWith(
+ color: AppColors.grey800,
+ ),
+ ),
+ ),
+ ],
+ ),
+ SizedBox(height: AppGaps.gap20),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "위 안내사항을 모두 확인하였습니다.",
+ style: AppTypography.subtitle2.copyWith(
+ color: viewModel.isChecked
+ ? AppColors.grey800
+ : AppColors.grey400,
+ ),
+ ),
+ IconButton(
+ onPressed: () {
+ notifier.toggle();
+ },
+ icon: Icon(
+ Icons.check_circle_outline,
+ color: viewModel.isChecked
+ ? AppColors.grey800
+ : AppColors.grey400,
+ ),
+ ),
+ ],
+ ),
+ SizedBox(height: AppGaps.gap20),
+ ConfirmButton(
+ enabled: viewModel.isChecked,
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) =>
+ const CongratulationPage(),
+ ),
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ );
+ });
+ }
+
+ Widget _buildInformationField() {
+ return SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: 30),
+ SvgPicture.asset("assets/icons/logo.svg"),
+ SizedBox(height: AppGaps.gap12),
+ Row(
+ children: [
+ Text(
+ "레즈비언",
+ style: AppTypography.header2.copyWith(
+ color: AppColors.primary,
+ ),
+ ),
+ Text("을 위한", style: AppTypography.header2),
+ ],
+ ),
+ Text(
+ "더 깊이있는 매칭 공간",
+ style: AppTypography.header2.copyWith(color: AppColors.grey900),
+ ),
+ SizedBox(height: AppGaps.gap36),
+ Text(
+ "CODE:L은 여성들이 서로의 마음을 나누고,\n인연을 찾을 수 있는 안전한 커뮤니티입니다.\n",
+ style: AppTypography.body1,
+ ),
+ Text(
+ "같은 마음을 가진 사람들과 더 안전하고 편안하게\n소통할 수 있는 공간을 만들기 위해 다음 규칙을\n꼭 지켜주세요.",
+ style: AppTypography.body1,
+ ),
+ SizedBox(height: AppGaps.gap36),
+ Row(
+ children: [
+ Icon(Icons.favorite, color: AppColors.error),
+ SizedBox(width: AppGaps.gap8),
+ Text("여성 사용자만 가입 가능합니다.", style: AppTypography.subtitle3),
+ ],
+ ),
+ Row(
+ children: [
+ Icon(Icons.favorite, color: AppColors.error),
+ SizedBox(width: AppGaps.gap8),
+ Text("모든 프로필은 심사 후 승인됩니다.", style: AppTypography.subtitle3),
+ ],
+ ),
+ Row(
+ children: [
+ Icon(Icons.favorite, color: AppColors.error),
+ SizedBox(width: AppGaps.gap8),
+ Text("서로를 존중하는 대화를 지향합니다.", style: AppTypography.subtitle3),
+ ],
+ ),
+ Row(
+ children: [
+ Icon(Icons.favorite, color: AppColors.error),
+ SizedBox(width: AppGaps.gap8),
+ Text(
+ "코드가 맞는 사람과 깊이 있는 연결을 만들어 갑니다.",
+ style: AppTypography.subtitle3,
+ ),
+ ],
+ ),
+ SizedBox(height: AppGaps.gap36),
+ Container(
+ height: 114,
+ width: double.infinity,
+ alignment: Alignment.center,
+ color: AppColors.grey100,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: AppGaps.gap16,
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("💌운영진의 노력", style: AppTypography.caption1),
+ SizedBox(height: AppGaps.gap8),
+ Flexible(
+ child: Text(
+ "CODE 가 맞는 사람들의 진심 어린 연결을 위해 운영진은\n언제나 보이지 않는 곳에서 신중히 고민하고 정성스럽게 공간을\n지켜가고 있어요.",
+ style: AppTypography.caption1.copyWith(
+ color: AppColors.grey700,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/auth/presentation/pages/woman/woman_verification_viewmodel.dart b/lib/auth/presentation/pages/woman/woman_verification_viewmodel.dart
new file mode 100644
index 0000000..3a26a5e
--- /dev/null
+++ b/lib/auth/presentation/pages/woman/woman_verification_viewmodel.dart
@@ -0,0 +1,13 @@
+import 'dart:developer';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+class WomanVerificationViewmodel extends ChangeNotifier {
+ bool isChecked = false;
+
+ void toggle() {
+ isChecked = !isChecked;
+ notifyListeners();
+ }
+}
diff --git a/lib/auth/presentation/widgets/.gitkeep b/lib/auth/presentation/widgets/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/auth/presentation/widgets/auth_confirm_button.dart b/lib/auth/presentation/widgets/auth_confirm_button.dart
new file mode 100644
index 0000000..4e41969
--- /dev/null
+++ b/lib/auth/presentation/widgets/auth_confirm_button.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/cupertino.dart';
+
+import '../../../core/utills/design/app_colors.dart';
+import '../../../core/utills/design/app_typography.dart';
+
+class AuthConfirmButton extends StatelessWidget {
+ const AuthConfirmButton({
+ super.key,
+ required this.enabled,
+ this.onPressed,
+ this.text = "확인",
+ });
+
+ final bool enabled;
+ final VoidCallback? onPressed;
+ final String text;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: enabled ? onPressed : null,
+ child: Container(
+ height: 54,
+ width: double.infinity,
+ padding: EdgeInsets.symmetric(vertical: 16),
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ color: enabled ? AppColors.primary : AppColors.grey200,
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Text(
+ text,
+ style: AppTypography.subtitle2.copyWith(
+ color: enabled ? AppColors.white : AppColors.grey400,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/core/utills/design/app_colors.dart b/lib/core/utills/design/app_colors.dart
index d28487a..0ae9df5 100644
--- a/lib/core/utills/design/app_colors.dart
+++ b/lib/core/utills/design/app_colors.dart
@@ -13,8 +13,9 @@ class AppColors {
static const grey400 = Color(0xFFCCCCCC);
static const grey500 = Color(0xFFB0B0B0);
static const grey600 = Color(0xFF999999);
- static const grey700 = Color(0xFF333333);
- static const grey800 = Color(0xFF222222);
+ static const grey700 = Color(0xFF666666);
+ static const grey800 = Color(0xFF333333);
+ static const grey900 = Color(0xFF222222);
static const error = Color(0xFFEF2B2A);
static const success = Color(0xFF27C937);
static const warning = Color(0xFFFFAA00);
diff --git a/lib/main.dart b/lib/main.dart
index d2dee9d..335e24e 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,4 +1,5 @@
import 'package:code_l/auth/presentation/pages/login/login_page.dart';
+import 'package:code_l/auth/presentation/pages/terms_and_conditions/terms_and_condition_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
@@ -25,7 +26,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Kakao Login Demo',
- home: const LoginPage(),
+ home: const TermsAndConditionPage(),
theme: ThemeData(primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
),
diff --git a/lib/sign_up/presentation/pages/code_age/code_age_page.dart b/lib/sign_up/presentation/pages/code_age/code_age_page.dart
index e9795b0..2a6e6f5 100644
--- a/lib/sign_up/presentation/pages/code_age/code_age_page.dart
+++ b/lib/sign_up/presentation/pages/code_age/code_age_page.dart
@@ -17,58 +17,66 @@ class CodeAgePage extends StatelessWidget {
final isValid = true; // todo 상태관리
return Scaffold(
- appBar: SignUpAppBar(),
+ appBar: SignUpAppBar(),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(AppGaps.gap20),
- child: ConfirmButton(enabled: isValid,onPressed: () { Navigator.push(
- context,
- MaterialPageRoute(builder: (context) => CodeJobPage()),
- );}, ),
+ child: ConfirmButton(
+ enabled: isValid,
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(builder: (context) => CodeJobPage()),
+ );
+ },
+ ),
),
- body: SafeArea(child: Padding( padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap24,vertical: AppGaps.gap40),
-
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(height: screenHeight * 0.05),
- Text("나이를", style: AppTypography.header1),
- Text("입력해주세요", style: AppTypography.header1),
- SizedBox(height: AppGaps.gap12),
- SizedBox(height: AppGaps.gap40 + AppGaps.gap40 + AppGaps.gap40),
-
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- TextField(
- decoration: InputDecoration(
- hintText: '나이를 입력해주세요',
- hintStyle: AppTypography.header2.copyWith(color: AppColors.grey400),
- contentPadding: EdgeInsets.symmetric(vertical: AppGaps.gap8),
- border: UnderlineInputBorder(
- borderSide: BorderSide(color: AppColors.grey400, width: 0.6),
- ),
- enabledBorder: UnderlineInputBorder(
- borderSide: BorderSide(color: AppColors.grey400, width: 0.6),
- ),
- focusedBorder: UnderlineInputBorder(
- borderSide: BorderSide(
- color: AppColors.grey400,
- width: 0.6,
+ body: SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: AppGaps.gap24, vertical: AppGaps.gap40),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(height: screenHeight * 0.05),
+ Text("나이를", style: AppTypography.header1),
+ Text("입력해주세요", style: AppTypography.header1),
+ SizedBox(height: AppGaps.gap12),
+ SizedBox(height: AppGaps.gap40 + AppGaps.gap40 + AppGaps.gap40),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ TextField(
+ decoration: InputDecoration(
+ hintText: '나이를 입력해주세요',
+ hintStyle: AppTypography.header2
+ .copyWith(color: AppColors.grey400),
+ contentPadding:
+ EdgeInsets.symmetric(vertical: AppGaps.gap8),
+ border: UnderlineInputBorder(
+ borderSide:
+ BorderSide(color: AppColors.grey400, width: 0.6),
+ ),
+ enabledBorder: UnderlineInputBorder(
+ borderSide:
+ BorderSide(color: AppColors.grey400, width: 0.6),
+ ),
+ focusedBorder: UnderlineInputBorder(
+ borderSide: BorderSide(
+ color: AppColors.grey400,
+ width: 0.6,
+ ),
+ ),
+ suffixIcon: IconButton(
+ icon: Icon(Icons.clear, size: 16),
+ onPressed: () => {/*todo 삭제버튼*/}),
+ ),
),
- ),
- suffixIcon: IconButton(
- icon: Icon(Icons.clear, size: 16),
- onPressed: () => {/*todo 삭제버튼*/}
- ),
+ SizedBox(height: AppGaps.gap4),
+ ],
),
- ),
- SizedBox(height: AppGaps.gap4),
- ],
+ ],
+ ),
),
- ],
- ),
- )
- ,)
- );
+ ));
}
}
diff --git a/lib/sign_up/presentation/pages/code_job/code_job_page.dart b/lib/sign_up/presentation/pages/code_job/code_job_page.dart
index 66aa283..312ff63 100644
--- a/lib/sign_up/presentation/pages/code_job/code_job_page.dart
+++ b/lib/sign_up/presentation/pages/code_job/code_job_page.dart
@@ -15,7 +15,7 @@ class CodeJobPage extends ConsumerStatefulWidget {
ConsumerState createState() => _JobSelectionPageState();
}
-class _JobSelectionPageState extends ConsumerState{
+class _JobSelectionPageState extends ConsumerState {
String? selectedJob;
@override
@@ -46,7 +46,8 @@ class _JobSelectionPageState extends ConsumerState{
),
body: SafeArea(
child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap24,vertical: AppGaps.gap40),
+ padding: const EdgeInsets.symmetric(
+ horizontal: AppGaps.gap24, vertical: AppGaps.gap40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -89,7 +90,8 @@ class _JobSelectionPageState extends ConsumerState{
height: 22,
),
SizedBox(height: AppGaps.gap4),
- Text(job['label'] ?? '', style: AppTypography.body2),
+ Text(job['label'] ?? '',
+ style: AppTypography.body2),
],
),
),
diff --git a/lib/sign_up/presentation/pages/code_name/code_name_page.dart b/lib/sign_up/presentation/pages/code_name/code_name_page.dart
index 21d0d83..b155be3 100644
--- a/lib/sign_up/presentation/pages/code_name/code_name_page.dart
+++ b/lib/sign_up/presentation/pages/code_name/code_name_page.dart
@@ -56,7 +56,8 @@ Widget _buildHeaderText() {
);
}
-Widget _buildCodeNameInputField(bool isValid, TextEditingController controller) {
+Widget _buildCodeNameInputField(
+ bool isValid, TextEditingController controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -83,9 +84,7 @@ Widget _buildCodeNameInputField(bool isValid, TextEditingController controller)
),
SizedBox(height: AppGaps.gap4),
Text(
- isValid
- ? '멋진 코드네임이네요!'
- : '한글, 숫자 최대 10글자까지 사용 가능합니다',
+ isValid ? '멋진 코드네임이네요!' : '한글, 숫자 최대 10글자까지 사용 가능합니다',
style: AppTypography.caption2.copyWith(
color: isValid ? AppColors.success : AppColors.error,
),
@@ -93,5 +92,3 @@ Widget _buildCodeNameInputField(bool isValid, TextEditingController controller)
],
);
}
-
-
diff --git a/lib/sign_up/presentation/widgets/.gitkeep b/lib/sign_up/presentation/widgets/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/sign_up/presentation/widgets/sign_up_app_bar.dart b/lib/sign_up/presentation/widgets/sign_up_app_bar.dart
index 75e6de9..cad93d3 100644
--- a/lib/sign_up/presentation/widgets/sign_up_app_bar.dart
+++ b/lib/sign_up/presentation/widgets/sign_up_app_bar.dart
@@ -1,4 +1,3 @@
-
import 'package:code_l/core/utills/design/app_colors.dart';
import 'package:flutter/material.dart';
@@ -24,28 +23,28 @@ class SignUpAppBar extends StatelessWidget implements PreferredSizeWidget {
),
// 진행률
- Expanded(
- child: Container(
- height: 6,
- margin: EdgeInsets.symmetric(horizontal: 8),
- decoration: BoxDecoration(
- color: AppColors.primaryLight, // 배경 (전체 바)
- borderRadius: BorderRadius.circular(2),
- ),
- child: FractionallySizedBox(
- alignment: Alignment.centerLeft,
- widthFactor: progress, // 진행률
- child: Container(
- decoration: BoxDecoration(
- color: AppColors.primary,
- borderRadius: BorderRadius.circular(2),
- ),
- ),
- ),
- ),
- ),
+ Expanded(
+ child: Container(
+ height: 6,
+ margin: EdgeInsets.symmetric(horizontal: 8),
+ decoration: BoxDecoration(
+ color: AppColors.primaryLight, // 배경 (전체 바)
+ borderRadius: BorderRadius.circular(2),
+ ),
+ child: FractionallySizedBox(
+ alignment: Alignment.centerLeft,
+ widthFactor: progress, // 진행률
+ child: Container(
+ decoration: BoxDecoration(
+ color: AppColors.primary,
+ borderRadius: BorderRadius.circular(2),
+ ),
+ ),
+ ),
+ ),
+ ),
- // 닫기 버튼
+ // 닫기 버튼
IconButton(
icon: Icon(Icons.close),
onPressed: () {
diff --git a/lib/sign_up/presentation/widgets/sign_up_confirm_button.dart b/lib/sign_up/presentation/widgets/sign_up_confirm_button.dart
index a73ab39..e4df7d4 100644
--- a/lib/sign_up/presentation/widgets/sign_up_confirm_button.dart
+++ b/lib/sign_up/presentation/widgets/sign_up_confirm_button.dart
@@ -28,12 +28,10 @@ class ConfirmButton extends StatelessWidget {
color: enabled ? AppColors.primary : AppColors.grey200,
borderRadius: BorderRadius.circular(8),
),
- child: Text(
- text,
+ child: Text(text,
style: AppTypography.subtitle2.copyWith(
color: enabled ? AppColors.white : AppColors.grey400,
- )
- ),
+ )),
),
);
}