From f7f41da5780ae7e7cf81c9b8d58b3dd3ae754234 Mon Sep 17 00:00:00 2001 From: kkosang Date: Fri, 25 Apr 2025 21:08:02 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=BD=94=EB=93=9C=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20MBTI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profile_mbti/profile_mbti_state.dart | 21 ++++ .../pages/profile_mbti/profile_mbti_page.dart | 96 +++++++++++++++++++ .../profile_mbti/profile_mbti_viewmodel.dart | 27 ++++++ .../pages/profile_mbti/providers.dart | 10 ++ 4 files changed, 154 insertions(+) create mode 100644 lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart create mode 100644 lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart create mode 100644 lib/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart create mode 100644 lib/sign_up/presentation/pages/profile_mbti/providers.dart diff --git a/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart b/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart new file mode 100644 index 0000000..d9915fd --- /dev/null +++ b/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart @@ -0,0 +1,21 @@ +class MBTIState { + final String? ei, ns, tf, pj; + + const MBTIState({this.ei, this.ns, this.tf, this.pj}); + + MBTIState copyWith({ + String? ei, + String? ns, + String? tf, + String? pj, + }) { + return MBTIState( + ei: ei ?? this.ei, + ns: ns ?? this.ns, + tf: tf ?? this.tf, + pj: pj ?? this.pj, + ); + } + + bool get isValid => ei != null && ns != null && tf != null && pj != null; +} diff --git a/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart new file mode 100644 index 0000000..a458366 --- /dev/null +++ b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart @@ -0,0 +1,96 @@ +import 'package:code_l/sign_up/presentation/pages/profile_mbti/providers.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 '../../widgets/sign_up_app_bar.dart'; +import '../../widgets/sign_up_confirm_button.dart'; + +class ProfileMBTIPage extends ConsumerWidget { + const ProfileMBTIPage({super.key}); + + final mbtiOptions = const [ + ['E', 'I'], + ['N', 'S'], + ['T', 'F'], + ['P', 'J'], + ]; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final screenHeight = MediaQuery.of(context).size.height; + final mbtiState = ref.watch(profileMBTIProvider); + final viewModel = ref.read(profileMBTIProvider.notifier); + + return Scaffold( + appBar: const SignUpAppBar(), + bottomNavigationBar: Padding( + padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20, vertical: 34), + child: ConfirmButton( + enabled: mbtiState.isValid, + onPressed: () { + // TODO: 다음 페이지 이동 로직 + }, + ), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: screenHeight * 0.05), + Text("MBTI를\n선택해주세요", style: AppTypography.header1), + const SizedBox(height: AppGaps.gap40), + + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: mbtiOptions.length, + itemBuilder: (context, groupIndex) { + final group = mbtiOptions[groupIndex]; + return Padding( + padding: const EdgeInsets.only(bottom: AppGaps.gap20), + child: Row( + children: group.map((option) { + final isSelected = viewModel.isSelected(groupIndex, option); + return Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: GestureDetector( + onTap: () => viewModel.select(groupIndex, option), + child: Container( + padding: const EdgeInsets.symmetric(horizontal:74,vertical: 34), + decoration: BoxDecoration( + color: isSelected ? AppColors.primaryLight : AppColors.grey100, + border: Border.all( + color: isSelected ? AppColors.primary : AppColors.grey100, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + option, + style: AppTypography.body1.copyWith(color: AppColors.grey900), + ), + ), + ), + ), + ), + ); + }).toList(), + ), + ); + }, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart new file mode 100644 index 0000000..ccbc8b0 --- /dev/null +++ b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart @@ -0,0 +1,27 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../domain/model/profile_mbti/profile_mbti_state.dart'; + +class ProfileMBTIViewModel extends StateNotifier { + ProfileMBTIViewModel() : super(const MBTIState()); + + void select(int groupIndex, String value) { + state = switch (groupIndex) { + 0 => state.copyWith(ei: value), + 1 => state.copyWith(ns: value), + 2 => state.copyWith(tf: value), + 3 => state.copyWith(pj: value), + _ => state, + }; + } + + bool isSelected(int groupIndex, String value) { + return switch (groupIndex) { + 0 => state.ei == value, + 1 => state.ns == value, + 2 => state.tf == value, + 3 => state.pj == value, + _ => false, + }; + } +} diff --git a/lib/sign_up/presentation/pages/profile_mbti/providers.dart b/lib/sign_up/presentation/pages/profile_mbti/providers.dart new file mode 100644 index 0000000..5a9773c --- /dev/null +++ b/lib/sign_up/presentation/pages/profile_mbti/providers.dart @@ -0,0 +1,10 @@ + +import 'package:code_l/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../domain/model/profile_mbti/profile_mbti_state.dart'; + +final profileMBTIProvider = +StateNotifierProvider( + (ref) => ProfileMBTIViewModel(), +); From c8514bfd73525ebea3788a76fab73a1028b49793 Mon Sep 17 00:00:00 2001 From: kkosang Date: Fri, 25 Apr 2025 21:08:24 +0900 Subject: [PATCH 2/2] chore: dart format --- .../profile_mbti/profile_mbti_state.dart | 7 +- .../pages/profile_mbti/profile_mbti_page.dart | 72 ++++++++++++------- .../pages/profile_mbti/providers.dart | 5 +- 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart b/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart index d9915fd..7ae2731 100644 --- a/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart +++ b/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart @@ -3,12 +3,7 @@ class MBTIState { const MBTIState({this.ei, this.ns, this.tf, this.pj}); - MBTIState copyWith({ - String? ei, - String? ns, - String? tf, - String? pj, - }) { + MBTIState copyWith({String? ei, String? ns, String? tf, String? pj}) { return MBTIState( ei: ei ?? this.ei, ns: ns ?? this.ns, diff --git a/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart index a458366..7b8a276 100644 --- a/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart +++ b/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart @@ -27,7 +27,10 @@ class ProfileMBTIPage extends ConsumerWidget { return Scaffold( appBar: const SignUpAppBar(), bottomNavigationBar: Padding( - padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20, vertical: 34), + padding: const EdgeInsets.symmetric( + horizontal: AppGaps.gap20, + vertical: 34, + ), child: ConfirmButton( enabled: mbtiState.isValid, onPressed: () { @@ -55,33 +58,54 @@ class ProfileMBTIPage extends ConsumerWidget { return Padding( padding: const EdgeInsets.only(bottom: AppGaps.gap20), child: Row( - children: group.map((option) { - final isSelected = viewModel.isSelected(groupIndex, option); - return Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6), - child: GestureDetector( - onTap: () => viewModel.select(groupIndex, option), - child: Container( - padding: const EdgeInsets.symmetric(horizontal:74,vertical: 34), - decoration: BoxDecoration( - color: isSelected ? AppColors.primaryLight : AppColors.grey100, - border: Border.all( - color: isSelected ? AppColors.primary : AppColors.grey100, - ), - borderRadius: BorderRadius.circular(8), + children: + group.map((option) { + final isSelected = viewModel.isSelected( + groupIndex, + option, + ); + return Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 6, ), - child: Center( - child: Text( - option, - style: AppTypography.body1.copyWith(color: AppColors.grey900), + child: GestureDetector( + onTap: + () => viewModel.select( + groupIndex, + option, + ), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 74, + vertical: 34, + ), + decoration: BoxDecoration( + color: + isSelected + ? AppColors.primaryLight + : AppColors.grey100, + border: Border.all( + color: + isSelected + ? AppColors.primary + : AppColors.grey100, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + option, + style: AppTypography.body1.copyWith( + color: AppColors.grey900, + ), + ), + ), ), ), ), - ), - ), - ); - }).toList(), + ); + }).toList(), ), ); }, diff --git a/lib/sign_up/presentation/pages/profile_mbti/providers.dart b/lib/sign_up/presentation/pages/profile_mbti/providers.dart index 5a9773c..90f47cd 100644 --- a/lib/sign_up/presentation/pages/profile_mbti/providers.dart +++ b/lib/sign_up/presentation/pages/profile_mbti/providers.dart @@ -1,10 +1,9 @@ - import 'package:code_l/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../domain/model/profile_mbti/profile_mbti_state.dart'; final profileMBTIProvider = -StateNotifierProvider( + StateNotifierProvider( (ref) => ProfileMBTIViewModel(), -); + );