diff --git a/ios/Podfile.lock b/ios/Podfile.lock index aa223dd..c574659 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1462,10 +1462,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: abseil: a05cc83bf02079535e17169a73c5be5ba47f714b BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508 - cloud_firestore: aef3217af294cd35afda47e63112d306f4c9a2e2 + cloud_firestore: 07742f115155e19201e77b4cafb155011892d7b7 Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2 - firebase_auth: e37065f3f80ff90580c13ad0e5a48e3bb8d2ad77 - firebase_core: 432718558359a8c08762151b5f49bb0f093eb6e0 + firebase_auth: ad485af7f854ba5f86634f81725b22b37f317883 + firebase_core: 2d4534e7b489907dcede540c835b48981d890943 FirebaseAppCheckInterop: f23709c9ce92d810aa53ff4ce12ad3e666a3c7be FirebaseAuth: c4146bdfdc87329f9962babd24dae89373f49a32 FirebaseAuthInterop: ac22ed402c2f4e3a8c63ebd3278af9a06073c1be @@ -1476,22 +1476,22 @@ SPEC CHECKSUMS: FirebaseFirestoreInternal: 97a2bb5f16951c77753c860d3519379702ab6f8a FirebaseSharedSwift: d2475748a2d2a36242ed13baa34b2acda846c925 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 - fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f + flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 + fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d "gRPC-C++": cc207623316fb041a7a3e774c252cf68a058b9e8 gRPC-Core: 860978b7db482de8b4f5e10677216309b5ff6330 GTMSessionFetcher: 75b671f9e551e4c49153d4c4f8659ef4f559b970 - image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - kakao_flutter_sdk_common: 3dc8492c202af7853585d151490b1c5c6b7576cb + image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a + kakao_flutter_sdk_common: 600d55b532da0bd37268a529e1add49302477710 leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba - screen_protector: 6f92086bd2f2f4b54f54913289b9d1310610140b + screen_protector: 3d90d44ac886b25335aebd93230b454aef45794a ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440 + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418 PODFILE CHECKSUM: f8c2dcdfb50bb67645580d28a6bf814fca30bdec diff --git a/lib/core/utills/network/profile_api_service.dart b/lib/core/utills/network/profile_api_service.dart new file mode 100644 index 0000000..b7e181a --- /dev/null +++ b/lib/core/utills/network/profile_api_service.dart @@ -0,0 +1,28 @@ +import 'dart:developer'; + +import 'package:code_l/auth/data/datasources/local/login_local_datasource.dart'; +import 'package:dio/dio.dart'; + +import '../../../sign_up/data/models/request/profile_request.dart'; + +class ProfileApiService { + final Dio _dio; + + ProfileApiService(this._dio); + + Future profile(ProfileRequest request) async { + final token = await LoginLocalDataSource.loadToken(); + log(request.toJson().toString()); + final response = await _dio.post( + '/v1/member/profile', + data: request.toJson(), + options: Options( + headers: { + 'Authorization': '$token', + }, + ), + ); + log(response.statusCode.toString()); + return response; + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b2ec713..1138b75 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,8 +2,10 @@ import 'package:code_l/auth/presentation/pages/identity/identity_verification_pa 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:code_l/sign_up/presentation/pages/pending_approval/pending_approval_page.dart'; +import 'package:code_l/sign_up/presentation/pages/profile_image/profile_face_image_page.dart'; import 'package:code_l/sign_up/presentation/pages/profile_image/profile_image_page.dart'; import 'package:code_l/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart'; +import 'package:code_l/sign_up/presentation/pages/profile_name/profile_name_page.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; @@ -71,8 +73,8 @@ class InitialRouteLoader extends StatelessWidget { return switch (snapshot.data!) { SignUpState.SIGNUP => const PhoneVerificationPage(), SignUpState.IDENTIFY => const TermsAndConditionPage(), - SignUpState.CODE_SURVEY => const ProfileInterestPage(), - SignUpState.CODE_PROFILE_IMAGE => const ProfileImagePage(), + SignUpState.CODE_SURVEY => const ProfileImagePage(), + SignUpState.CODE_PROFILE_IMAGE => const ProfileFaceImagePage(), SignUpState.PENDING => const PendingApprovalPage(), SignUpState.DONE => const LoginPage(), // todo home SignUpState.NONE => const LoginPage(), diff --git a/lib/sign_up/data/datasources/local/drink_options.dart b/lib/sign_up/data/datasources/local/drink_options.dart new file mode 100644 index 0000000..2a2f84c --- /dev/null +++ b/lib/sign_up/data/datasources/local/drink_options.dart @@ -0,0 +1 @@ +final drinkOptions = ['음주는 안해요', '약속 있을 때만 먹어요', '음주를 즐기는 매니아', '금주중']; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/interest_options.dart b/lib/sign_up/data/datasources/local/interest_options.dart new file mode 100644 index 0000000..0b5eb81 --- /dev/null +++ b/lib/sign_up/data/datasources/local/interest_options.dart @@ -0,0 +1,22 @@ +final List interestOptions = [ + '게임 🎮', + '방탈출/보드게임 🎲', + '야외활동 🚴', + '운동 🏋️', + '독서 & 글쓰기 📚✍️', + '음악 & 악기 🎵🎸', + '영화 🎬', + '캠핑 🏕️', + 'OTT/드라마 📺', + '여행 ✈', + '요리 🍳', + '맛집 탐방 🍽', + '패션 & 뷰티 👗💄', + '쇼핑 🛍', + '동물 🐶🐱', + 'IT기술 💻', + '댄스 & 퍼포먼스 💃🕺', + '인테리어 & DIY 🏠🔨', + '사지 & 영상 제작 🎥', + '전시관람 🖼', +]; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/job_options.dart b/lib/sign_up/data/datasources/local/job_options.dart new file mode 100644 index 0000000..65dcd02 --- /dev/null +++ b/lib/sign_up/data/datasources/local/job_options.dart @@ -0,0 +1,14 @@ +final List> jobList = [ + {'label': '직장인', 'image': 'assets/icons/ic_job_office_worker.png'}, + {'label': '학생', 'image': 'assets/icons/ic_job_student.png'}, + {'label': '취준생', 'image': 'assets/icons/ic_job_seeker.png'}, + {'label': '프리랜서', 'image': 'assets/icons/ic_job_freelancer.png'}, + {'label': '자영업자', 'image': 'assets/icons/ic_job_self_employed.png'}, + {'label': '공무원', 'image': 'assets/icons/ic_job_government_employee.png'}, + {'label': '서비스직', 'image': 'assets/icons/ic_job_servicer.png'}, + {'label': '의료인', 'image': 'assets/icons/ic_job_healthcare.png'}, + {'label': '교육자', 'image': 'assets/icons/ic_job_educator.png'}, + {'label': '엔터테이너', 'image': 'assets/icons/ic_job_entertainer.png'}, + {'label': '크리에이터', 'image': 'assets/icons/ic_job_creator.png'}, + {'label': '기타', 'image': 'assets/icons/ic_job_etc.png'}, +]; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/love_style.dart b/lib/sign_up/data/datasources/local/love_style.dart new file mode 100644 index 0000000..040bca4 --- /dev/null +++ b/lib/sign_up/data/datasources/local/love_style.dart @@ -0,0 +1,41 @@ +final List relationshipStyles = [ + '천천히 알아가는 스타일 ⏳', + '만나면 운명이라고 믿는 직진형 💫', + '안정적이고 신뢰감 있는 연애 선호 🏡', + '서로의 성장과 자립을 중요시하는 스타일 🌱', + '항상 새롭고 설레는 연애를 추구하는 스타일 💃', +]; + +final List communicationStyles = [ + '하루 종일 연락하는 스타일 📲', + '중요한 순간에만 연락하는 스타일 🕰', + '전화보다 톡을 선호하는 스타일 💬', + '하루 한 통이라도 진심을 담는 스타일 💌', + '상대가 필요할 때 항상 먼저 연락하는 스타일 🙋‍♂️', +]; + +final List dateStyles = [ + '집에서 함께 영화 보는 홈 데이트 🏠', + '맛집 탐방하고 새로운 곳 찾기 🍔', + '야외활동이나 스포츠 즐기기 🚴‍♂️', + '문화생활 (전시회, 공연 등) 즐기기 🎭', + '계획적이고 철저한 데이트 스케줄러 📅', + '즉흥적으로 놀러 가는 스타일 🌍', +]; + +final List conflictResolutionStyles = [ + '바로 대화해서 푸는 직설형💬', + '시간이 지난 후 차분하게 이야기하는 스타일🤫', + '상대방의 입장을 먼저 이해하는 배려형🤝', + '잘못을 빠르게 인정하고 사과하는 솔직형🙇‍♂️', + '화가 나도 조용히 마음을 가라앉히는 침착형🧘‍♀️', +]; + +final List affectionExpressions = [ + '표현을 잘하는 직진형 💬', + '은근하게 마음을 전하는 무뚝뚝형 😎', + '말보다는 행동으로 표현하는 실천파 🚶‍♂', + '애교 많고 귀여운 스타일 🥰', + '진지하고 깊이 있는 스타일 🤔', + '다정다감한 배려형 💕', +]; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/mbti_options.dart b/lib/sign_up/data/datasources/local/mbti_options.dart new file mode 100644 index 0000000..c2a4dc5 --- /dev/null +++ b/lib/sign_up/data/datasources/local/mbti_options.dart @@ -0,0 +1,6 @@ +final mbtiOptions = const [ + ['E', 'I'], + ['N', 'S'], + ['T', 'F'], + ['P', 'J'], +]; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/region_options.dart b/lib/sign_up/data/datasources/local/region_options.dart new file mode 100644 index 0000000..adcc7ec --- /dev/null +++ b/lib/sign_up/data/datasources/local/region_options.dart @@ -0,0 +1,273 @@ +final List mainRegions = [ + '서울', + '경기', + '부산', + '대구', + '인천', + '광주', + '대전', + '울산', + '세종', + '충북', + '충남', + '전북', + '전남', + '경북', + '경남', + '제주', +]; + +final Map> subRegions = { + '서울': [ + '강남', + '강동', + '강북', + '강서', + '관악', + '광진', + '구로', + '금천', + '노원', + '도봉', + '동대문', + '동작', + '마포', + '서대문', + '서초', + '성동', + '성북', + '송파', + '양천', + '영등포', + '용산', + '은평', + '종로', + '중구', + '중랑', + ], + '경기': [ + '가평군', + '고양시', + '덕양구', + '일산동구', + '일산서구', + '과천시', + '광명시', + '광주시', + '구리시', + '군포시', + '김포시', + '남양주시', + '동두천시', + '부천시', + '소사구', + '오정구', + '원미구', + '성남시', + '분당구', + '수정구', + '중원구', + '수원시', + '권선구', + '영통구', + '장안구', + '팔달구', + '시흥시', + '안산시', + '단원구', + '상록구', + '안성시', + '안양시', + '동안구', + '만안구', + '양주시', + '양평군', + '여주시', + '연천군', + '오산시', + '용인시', + '기흥구', + '수지구', + '처인구', + '의왕시', + '의정부시', + '이천시', + '파주시', + '평택시', + '포천시', + '하남시', + '화성시', + ], + '부산': [ + '강서구', + '금정구', + '기장군', + '남구', + '동구', + '동래구', + '부산진구', + '북구', + '사상구', + '사하구', + '서구', + '수영구', + '연제구', + '영도구', + '중구', + '해운대구', + '해운대', + '서면', + '남포동', + '광안리', + '기장', + ], + '대구': ['군위군', '남구', '달서구', '달성군', '동구', '북구', '서구', '수성구', '중구', '동성로'], + '인천': [ + '강화군', + '계양구', + '남동구', + '동구', + '미추홀구', + '부평구', + '서구', + '연수구', + '옹진군', + '중구', + '송도', + '부평', + '청라', + ], + '광주': ['상무지구', '충장로', '광산구', '남구', '동구', '북구', '서구'], + '대전': ['대덕구', '동구', '서구', '유성구', '중구'], + '울산': ['남구', '동구', '북구', '울주군', '중구'], + '세종': ['세종 전체'], + '충북': [ + '괴산군', + '단양군', + '보은군', + '영동군', + '옥천군', + '음성군', + '제천시', + '증평군', + '진천군', + '청주시', + '상당구', + '서원구', + '청원구', + '흥덕구', + '충주시', + ], + '충남': [ + '계룡시', + '공주시', + '금산군', + '논산시', + '당진시', + '보령시', + '부여군', + '서산시', + '서천군', + '아산시', + '예산군', + '천안시', + '동남구', + '서북구', + '청양군', + '태안군', + '홍성군', + ], + '전북': [ + '고창군', + '군산시', + '김제시', + '남원시', + '무주군', + '부안군', + '순창군', + '완주군', + '익산시', + '임실군', + '장수군', + '전주시', + '전주시 덕진구', + '전주시 완산구', + '정읍시', + '진안군', + ], + '전남': [ + '강진군', + '고흥군', + '곡성군', + '광양시', + '구례군', + '나주시', + '담양군', + '목포시', + '무안군', + '보성군', + '순천시', + '신안군', + '여수시', + '영광군', + '영암군', + '완도군', + '장성군', + '장흥군', + '진도군', + '함평군', + '해남군', + '화순군', + ], + '경북': [ + '경산시', + '경주시', + '고령군', + '구미시', + '군위군', + '김천시', + '문경시', + '봉화군', + '상주시', + '성주군', + '안동시', + '영덕군', + '영양군', + '영주시', + '영천시', + '예천군', + '울릉군', + '울진군', + '의성군', + '청도군', + '청송군', + '칠곡군', + '포항시', + ], + '경남': [ + '거제시', + '거창군', + '고성군', + '김해시', + '남해군', + '밀양시', + '사천시', + '산청군', + '양산시', + '의령군', + '진주시', + '창녕군', + '창원시', + '창원시 마산합포구', + '창원시 마산회원구', + '창원시 성산구', + '창원시 의창구', + '창원시 진해구', + '통영시', + '하동군', + '함안군', + '함양군', + '합천군', + ], + '제주': ['서귀포시', '제주시'], +}; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/local/smoke_options.dart b/lib/sign_up/data/datasources/local/smoke_options.dart new file mode 100644 index 0000000..c1fc5b1 --- /dev/null +++ b/lib/sign_up/data/datasources/local/smoke_options.dart @@ -0,0 +1,6 @@ +final smokeOptions = [ + '흡연중이에요', + '가끔 흡연해요', + '비흡연자지만 흡연에 거부감은 없어요', + '비흡연자이며, 흡연자는 원치 않아요', +]; \ No newline at end of file diff --git a/lib/sign_up/data/datasources/providers.dart b/lib/sign_up/data/datasources/providers.dart new file mode 100644 index 0000000..6dd8d19 --- /dev/null +++ b/lib/sign_up/data/datasources/providers.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../core/utills/network/dio_provider.dart'; +import '../../../core/utills/network/profile_api_service.dart'; + +final profileApiServiceProvider = Provider((ref) { + final dio = ref.watch(dioProvider); + return ProfileApiService(dio); +}); diff --git a/lib/sign_up/data/datasources/remote/profile_remote_datasource.dart b/lib/sign_up/data/datasources/remote/profile_remote_datasource.dart new file mode 100644 index 0000000..cde9377 --- /dev/null +++ b/lib/sign_up/data/datasources/remote/profile_remote_datasource.dart @@ -0,0 +1,46 @@ +import 'dart:developer'; + +import '../../../../auth/domain/model/sign_up_state.dart'; +import '../../../../core/utills/network/auth_api_service.dart'; +import '../../../../core/utills/network/profile_api_service.dart'; +import '../../../../main.dart'; +import '../../models/request/profile_request.dart'; + +class ProfileRemoteDatasource { + final ProfileApiService api; + + ProfileRemoteDatasource(this.api); + + Future sendProfile({ + required String name, + required int age, + required String job, + required String drink, + required String smoke, + required List interest, + required List loveStyle, + required String bigCity, + required String smallCity, + required String mbti, + required String introduce, + }) async { + await api.profile( + ProfileRequest( + codeName: name, + age: age, + job: job, + alcohol: drink, + smoke: smoke, + hobby: interest, + style: loveStyle, + bigCity: bigCity, + smallCity: smallCity, + mbti: mbti, + introduce: introduce, + ), + ); + + final state = SignUpState.fromString('CODE_SURVEY'); + await saveSignUpState(state); + } +} diff --git a/lib/sign_up/data/models/request/profile_request.dart b/lib/sign_up/data/models/request/profile_request.dart new file mode 100644 index 0000000..9d900f3 --- /dev/null +++ b/lib/sign_up/data/models/request/profile_request.dart @@ -0,0 +1,41 @@ +class ProfileRequest { + final String codeName; + final int age; + final String job; + final String alcohol; + final String smoke; + final List hobby; + final List style; + final String bigCity; + final String smallCity; + final String mbti; + final String introduce; + + ProfileRequest({ + required this.codeName, + required this.age, + required this.job, + required this.alcohol, + required this.smoke, + required this.hobby, + required this.style, + required this.bigCity, + required this.smallCity, + required this.mbti, + required this.introduce, + }); + + Map toJson() => { + 'codeName': codeName, + 'age': age, + 'job': job, + 'alcohol': alcohol, + 'smoke': smoke, + 'hobby': hobby, + 'style': style, + 'bigCity': bigCity, + 'smallCity': smallCity, + 'mbti': mbti, + 'introduce': introduce, + }; +} diff --git a/lib/sign_up/data/repositories/default_profile_repository.dart b/lib/sign_up/data/repositories/default_profile_repository.dart new file mode 100644 index 0000000..4bc954f --- /dev/null +++ b/lib/sign_up/data/repositories/default_profile_repository.dart @@ -0,0 +1,43 @@ +import 'dart:developer'; + +import 'package:code_l/auth/domain/repositories/login_repository.dart'; +import 'package:code_l/sign_up/data/datasources/remote/profile_remote_datasource.dart'; +import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart'; +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; + +import '../../domain/repositories/profile_repository.dart'; + +class DefaultProfileRepository implements ProfileRepository { + final ProfileRemoteDatasource profileRemoteDataSource; + + DefaultProfileRepository({required this.profileRemoteDataSource}); + + @override + Future sendProfile( + String name, + int age, + String job, + String drink, + String smoke, + List interest, + List loveStyle, + String bigCity, + String smallCity, + String mbti, + String introduce, + ) async { + await profileRemoteDataSource.sendProfile( + name: name, + age: age, + job: job, + drink: drink, + smoke: smoke, + interest: interest, + loveStyle: loveStyle, + bigCity: bigCity, + smallCity: smallCity, + mbti: mbti, + introduce: introduce, + ); + } +} 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 deleted file mode 100644 index 7ae2731..0000000 --- a/lib/sign_up/domain/model/profile_mbti/profile_mbti_state.dart +++ /dev/null @@ -1,16 +0,0 @@ -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/domain/model/profile_state.dart b/lib/sign_up/domain/model/profile_state.dart new file mode 100644 index 0000000..7caa479 --- /dev/null +++ b/lib/sign_up/domain/model/profile_state.dart @@ -0,0 +1,132 @@ +class ProfileState { + final String introduction; + final bool introductionIsValid; + + final int? age; + final bool ageIsValid; + + final List selectedInterestOptions; + final bool isSelectedInterestOptionsValid; + + late final String? selectedJob; + final bool isJobValid; + + final int? selectedDrinkIndex; + final bool isDrinkValid; + + final int? selectedSmokeIndex; + final bool isSmokeValid; + + int? selectedRelationshipIndex; + int? selectedAffectionIndex; + int? selectedCommunicationIndex; + int? selectedDateIndex; + int? selectedConflictIndex; + bool get isLoveStyleValid => + selectedRelationshipIndex != null && + selectedAffectionIndex != null && + selectedCommunicationIndex != null && + selectedDateIndex != null && + selectedConflictIndex != null; + + final String? ei, ns, tf, pj; + bool get isMbtiValid => ei != null && ns != null && tf != null && pj != null; + + final String? name; + final bool isNameValid; + + int? selectedMainRegionIndex; + int? selectedSubRegionIndex; + bool get isRegionValid => selectedMainRegionIndex != null && selectedSubRegionIndex != null; + + ProfileState({ + this.introduction = '', + this.introductionIsValid = false, + this.age, + this.ageIsValid = false, + this.selectedInterestOptions = const [], + this.isSelectedInterestOptionsValid = false, + this.selectedJob, + this.isJobValid = false, + this.selectedDrinkIndex, + this.isDrinkValid = false, + this.selectedSmokeIndex, + this.isSmokeValid = false, + this.selectedRelationshipIndex, + this.selectedAffectionIndex, + this.selectedCommunicationIndex, + this.selectedDateIndex, + this.selectedConflictIndex, + this.ei, + this.ns, + this.tf, + this.pj, + this.name, + this.isNameValid = false, + this.selectedMainRegionIndex, + this.selectedSubRegionIndex, + }); + + ProfileState copyWith({ + String? introduction, + bool? introductionIsValid, + int? age, + bool? ageIsValid, + List? selectedIndexes, + bool? isSelectedOptionsValid, + String? selectedJob, + bool? isJobValid, + int? selectedDrinkIndex, + bool? isDrinkValid, + int? selectedSmokeIndex, + bool? isSmokeValid, + int? selectedRelationshipIndex, + int? selectedAffectionIndex, + int? selectedCommunicationIndex, + int? selectedDateIndex, + int? selectedConflictIndex, + String? ei, + String? ns, + String? tf, + String? pj, + String? name, + bool? isNameValid, + int? selectedMainRegionIndex, + int? selectedSubRegionIndex, + }) { + return ProfileState( + introduction: introduction ?? this.introduction, + introductionIsValid: introductionIsValid ?? this.introductionIsValid, + age: age ?? this.age, + ageIsValid: ageIsValid ?? this.ageIsValid, + selectedInterestOptions: selectedIndexes ?? this.selectedInterestOptions, + isSelectedInterestOptionsValid: + isSelectedOptionsValid ?? this.isSelectedInterestOptionsValid, + selectedJob: selectedJob ?? this.selectedJob, + isJobValid: isJobValid ?? this.isJobValid, + selectedDrinkIndex: selectedDrinkIndex ?? this.selectedDrinkIndex, + isDrinkValid: isDrinkValid ?? this.isDrinkValid, + selectedSmokeIndex: selectedSmokeIndex ?? this.selectedSmokeIndex, + isSmokeValid: isSmokeValid ?? this.isSmokeValid, + selectedRelationshipIndex: + selectedRelationshipIndex ?? this.selectedRelationshipIndex, + selectedAffectionIndex: + selectedAffectionIndex ?? this.selectedAffectionIndex, + selectedCommunicationIndex: + selectedCommunicationIndex ?? this.selectedCommunicationIndex, + selectedDateIndex: selectedDateIndex ?? this.selectedDateIndex, + selectedConflictIndex: + selectedConflictIndex ?? this.selectedConflictIndex, + ei: ei ?? this.ei, + ns: ns ?? this.ns, + tf: tf ?? this.tf, + pj: pj ?? this.pj, + name: name ?? this.name, + isNameValid: isNameValid ?? this.isNameValid, + selectedMainRegionIndex: + selectedMainRegionIndex ?? this.selectedMainRegionIndex, + selectedSubRegionIndex: + selectedSubRegionIndex ?? this.selectedSubRegionIndex, + ); + } +} \ No newline at end of file diff --git a/lib/sign_up/domain/repositories/profile_repository.dart b/lib/sign_up/domain/repositories/profile_repository.dart new file mode 100644 index 0000000..4fff2c2 --- /dev/null +++ b/lib/sign_up/domain/repositories/profile_repository.dart @@ -0,0 +1,18 @@ +import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart'; +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; + +abstract class ProfileRepository { + Future sendProfile( + String codeName, + int age, + String job, + String alcohol, + String smoke, + List hobby, + List style, + String bigCity, + String smallCity, + String mbti, + String introduce, + ); +} diff --git a/lib/sign_up/presentation/pages/.gitkeep b/lib/sign_up/presentation/pages/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/lib/sign_up/presentation/pages/profile_age/profile_age_page.dart b/lib/sign_up/presentation/pages/profile_age/profile_age_page.dart index 5a920a9..a2c900c 100644 --- a/lib/sign_up/presentation/pages/profile_age/profile_age_page.dart +++ b/lib/sign_up/presentation/pages/profile_age/profile_age_page.dart @@ -3,25 +3,28 @@ import 'package:code_l/sign_up/presentation/widgets/sign_up_app_bar.dart'; import 'package:code_l/sign_up/presentation/widgets/sign_up_confirm_button.dart'; import 'package:flutter/cupertino.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 '../providers.dart'; -class ProfileAgePage extends StatelessWidget { +class ProfileAgePage extends ConsumerWidget { const ProfileAgePage({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = true; // todo 상태관리 + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: SignUpAppBar(currentPage: 2), bottomNavigationBar: Padding( padding: const EdgeInsets.all(AppGaps.gap20), child: ConfirmButton( - enabled: isValid, + enabled: state.ageIsValid, onPressed: () { Navigator.push( context, @@ -48,6 +51,7 @@ class ProfileAgePage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( + onChanged: notifier.updateAge, decoration: InputDecoration( hintText: '나이를 입력해주세요', hintStyle: AppTypography.header2.copyWith( @@ -76,7 +80,9 @@ class ProfileAgePage extends StatelessWidget { ), suffixIcon: IconButton( icon: Icon(Icons.clear, size: 16), - onPressed: () => {/*todo 삭제버튼*/}, + onPressed: () => { + notifier.updateAge(''), + }, ), ), ), diff --git a/lib/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart b/lib/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart index 2f1fc44..b0cd9d0 100644 --- a/lib/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart +++ b/lib/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart @@ -1,51 +1,24 @@ import 'package:code_l/sign_up/presentation/pages/profile_lovestyle/profile_lovestyle_page.dart'; import 'package:code_l/sign_up/presentation/widgets/sign_up_app_bar.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 '../../../data/datasources/local/interest_options.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.dart'; -class ProfileInterestPage extends StatefulWidget { +class ProfileInterestPage extends ConsumerWidget { const ProfileInterestPage({super.key}); @override - State createState() => _ProfileInterestPageState(); -} - -class _ProfileInterestPageState extends State { - // todo 상태관리 - final List interestOptions = [ - '게임 🎮', - '방탈출/보드게임 🎲', - '야외활동 🚴', - '운동 🏋️', - '독서 & 글쓰기 📚✍️', - '음악 & 악기 🎵🎸', - '영화 🎬', - '캠핑 🏕️', - 'OTT/드라마 📺', - '여행 ✈', - '요리 🍳', - '맛집 탐방 🍽', - '패션 & 뷰티 👗💄', - '쇼핑 🛍', - '동물 🐶🐱', - 'IT기술 💻', - '댄스 & 퍼포먼스 💃🕺', - '인테리어 & DIY 🏠🔨', - '사지 & 영상 제작 🎥', - '전시관람 🖼', - ]; - - final List selectedIndexes = []; - final int maxSelection = 5; - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = selectedIndexes.isNotEmpty; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); + final maxSelection = 5; + return Scaffold( appBar: SignUpAppBar(currentPage: 6), @@ -55,7 +28,7 @@ class _ProfileInterestPageState extends State { vertical: 34, ), child: ConfirmButton( - enabled: isValid, + enabled: state.isSelectedInterestOptionsValid, onPressed: () { Navigator.push( context, @@ -83,7 +56,7 @@ class _ProfileInterestPageState extends State { Align( alignment: Alignment.centerRight, child: Text( - "${selectedIndexes.length} / $maxSelection", + "${state.selectedInterestOptions.length} / $maxSelection", style: AppTypography.body2.copyWith(color: AppColors.grey500), ), ), @@ -94,19 +67,17 @@ class _ProfileInterestPageState extends State { spacing: 12, runSpacing: 12, children: List.generate(interestOptions.length, (index) { - final isSelected = selectedIndexes.contains(index); + final isSelected = state.selectedInterestOptions.contains(index); return GestureDetector( onTap: () { - setState(() { - if (isSelected) { - selectedIndexes.remove(index); - } else { - if (selectedIndexes.length < maxSelection) { - selectedIndexes.add(index); - } + if (isSelected) { + notifier.deleteSelectedInterestIndexes(index); + } else { + if (state.selectedInterestOptions.length < 5) { + notifier.addSelectedInterestIndexes(index); } - }); + } }, child: Container( padding: const EdgeInsets.symmetric( diff --git a/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_page.dart b/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_page.dart index 10009b3..4a53cce 100644 --- a/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_page.dart +++ b/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_page.dart @@ -1,15 +1,20 @@ import 'package:code_l/core/utills/design/app_colors.dart'; import 'package:code_l/core/utills/design/app_gaps.dart'; import 'package:code_l/core/utills/design/app_typography.dart'; -import 'package:code_l/sign_up/presentation/pages/profile_introduce/providers.dart'; +import 'package:code_l/sign_up/data/datasources/local/drink_options.dart'; +import 'package:code_l/sign_up/data/datasources/local/love_style.dart'; +import 'package:code_l/sign_up/data/datasources/local/smoke_options.dart'; +import 'package:code_l/sign_up/presentation/pages/providers.dart'; import 'package:flutter/material.dart'; +import '../../../data/datasources/local/interest_options.dart'; +import '../../../data/datasources/local/region_options.dart'; import '../../widgets/sign_up_app_bar.dart'; import '../../widgets/sign_up_confirm_button.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../profile_image/profile_image_page.dart'; -import 'profile_introduce_viewmodel.dart'; +import '../profile_viewmodel.dart'; class ProfileIntroducePage extends ConsumerWidget { const ProfileIntroducePage({super.key}); @@ -17,11 +22,25 @@ class ProfileIntroducePage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final state = ref.watch(profileIntroduceProvider); - final notifier = ref.read(profileIntroduceProvider.notifier); + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); + final repository = ref.read(profileRepositoryProvider); return Scaffold( appBar: SignUpAppBar(currentPage: 10), + bottomNavigationBar: ConfirmButton( + enabled: state.introductionIsValid, + onPressed: + state.introductionIsValid + ? () => { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => ProfileImagePage()), + ), + notifier.sendTotalProfile(repository) + } + : null, + ), body: SafeArea( child: Padding( padding: const EdgeInsets.all(AppGaps.gap24), @@ -32,21 +51,6 @@ class ProfileIntroducePage extends ConsumerWidget { _buildHeaderText(), SizedBox(height: AppGaps.gap40 + AppGaps.gap40), _buildCodeNameInputField(state.introduction, notifier), - Spacer(), - ConfirmButton( - enabled: state.isValid, - onPressed: - state.isValid - ? () => { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ProfileImagePage(), - ), - ), - } - : null, - ), ], ), ), @@ -71,7 +75,7 @@ class ProfileIntroducePage extends ConsumerWidget { Widget _buildCodeNameInputField( String introduction, - ProfileIntroduceViewmodel notifier, + ProfileViewmodel notifier, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_viewmodel.dart b/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_viewmodel.dart deleted file mode 100644 index e23e02f..0000000 --- a/lib/sign_up/presentation/pages/profile_introduce/profile_introduce_viewmodel.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -class ProfileIntroduceState { - final String introduction; - final bool isValid; - - ProfileIntroduceState({ - this.introduction = '', - this.isValid = false, - }); - - ProfileIntroduceState copyWith({ - String? introduction, - bool? isValid, - }) { - return ProfileIntroduceState( - introduction: introduction ?? this.introduction, - isValid: isValid ?? this.isValid, - ); - } -} - -class ProfileIntroduceViewmodel extends StateNotifier { - ProfileIntroduceViewmodel() : super(ProfileIntroduceState()); - - void updateIntroduction(String introduction) { - state = state.copyWith( - introduction: introduction, - isValid: introduction.isNotEmpty && introduction.length <= 15, - ); - } -} diff --git a/lib/sign_up/presentation/pages/profile_introduce/providers.dart b/lib/sign_up/presentation/pages/profile_introduce/providers.dart deleted file mode 100644 index 1be260c..0000000 --- a/lib/sign_up/presentation/pages/profile_introduce/providers.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:code_l/sign_up/presentation/pages/profile_introduce/profile_introduce_viewmodel.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final profileIntroduceProvider = - StateNotifierProvider( - (ref) => ProfileIntroduceViewmodel()); diff --git a/lib/sign_up/presentation/pages/profile_job/profile_job_page.dart b/lib/sign_up/presentation/pages/profile_job/profile_job_page.dart index 93cc678..3f0c3be 100644 --- a/lib/sign_up/presentation/pages/profile_job/profile_job_page.dart +++ b/lib/sign_up/presentation/pages/profile_job/profile_job_page.dart @@ -7,52 +7,36 @@ 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 '../../../data/datasources/local/job_options.dart'; import '../../widgets/sign_up_app_bar.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.dart'; -class ProfileJobPage extends ConsumerStatefulWidget { +class ProfileJobPage extends ConsumerWidget { const ProfileJobPage({super.key}); @override - ConsumerState createState() => _JobSelectionPageState(); -} - -class _JobSelectionPageState extends ConsumerState { - String? selectedJob; - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = true; // todo 상태관리 - - final List> jobList = [ - {'label': '직장인', 'image': 'assets/icons/ic_job_office_worker.png'}, - {'label': '학생', 'image': 'assets/icons/ic_job_student.png'}, - {'label': '취준생', 'image': 'assets/icons/ic_job_seeker.png'}, - {'label': '프리랜서', 'image': 'assets/icons/ic_job_freelancer.png'}, - {'label': '자영업자', 'image': 'assets/icons/ic_job_self_employed.png'}, - {'label': '공무원', 'image': 'assets/icons/ic_job_government_employee.png'}, - {'label': '서비스직', 'image': 'assets/icons/ic_job_servicer.png'}, - {'label': '의료인', 'image': 'assets/icons/ic_job_healthcare.png'}, - {'label': '교육자', 'image': 'assets/icons/ic_job_educator.png'}, - {'label': '엔터테이너', 'image': 'assets/icons/ic_job_entertainer.png'}, - {'label': '크리에이터', 'image': 'assets/icons/ic_job_creator.png'}, - {'label': '기타', 'image': 'assets/icons/ic_job_etc.png'}, - ]; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: SignUpAppBar(currentPage: 3), bottomNavigationBar: Padding( padding: const EdgeInsets.all(AppGaps.gap20), child: ConfirmButton( - enabled: isValid, + enabled: state.isJobValid, onPressed: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => ProfileLifestyleDrinkPage()), + MaterialPageRoute( + builder: (context) => ProfileLifestyleDrinkPage(), + ), ); }, - ),), + ), + ), body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric( @@ -74,10 +58,10 @@ class _JobSelectionPageState extends ConsumerState { childAspectRatio: 1.1, children: jobList.map((job) { - final isSelected = selectedJob == job['label']; + final isSelected = state.selectedJob == job['label']; return GestureDetector( onTap: () { - setState(() => selectedJob = job['label']); + notifier.updateSelectedJob(job['label']); }, child: Container( decoration: BoxDecoration( diff --git a/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_drink_page.dart b/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_drink_page.dart index 24cbd87..9849041 100644 --- a/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_drink_page.dart +++ b/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_drink_page.dart @@ -1,35 +1,31 @@ import 'package:code_l/sign_up/presentation/pages/profile_lifestyle/widgets/profile_lifestyle_check_icon.dart'; import 'package:code_l/sign_up/presentation/widgets/sign_up_app_bar.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 '../../../data/datasources/local/drink_options.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.dart'; import 'profile_lifestyle_smoke_page.dart'; -class ProfileLifestyleDrinkPage extends StatefulWidget { +class ProfileLifestyleDrinkPage extends ConsumerWidget { const ProfileLifestyleDrinkPage({super.key}); @override - State createState() => _ProfileLifestyleDrinkPageState(); -} - -class _ProfileLifestyleDrinkPageState extends State { - int? selectedIndex; - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = true; - final drinkOptions = ['음주는 안해요', '약속 있을 때만 먹어요', '음주를 즐기는 매니아', '금주중']; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: SignUpAppBar(currentPage: 4), bottomNavigationBar: Padding( padding: const EdgeInsets.all(AppGaps.gap20), child: ConfirmButton( - enabled: selectedIndex != null, + enabled: state.isDrinkValid, onPressed: () { Navigator.push( context, @@ -59,13 +55,11 @@ class _ProfileLifestyleDrinkPageState extends State { (_, __) => const SizedBox(height: AppGaps.gap16), itemBuilder: (context, index) { final item = drinkOptions[index]; - final isSelected = selectedIndex == index; + final isSelected = state.selectedDrinkIndex == index; return GestureDetector( onTap: () { - setState(() { - selectedIndex = index; - }); + notifier.updateSelectedDrinkIndex(index); }, child: Container( padding: const EdgeInsets.symmetric( diff --git a/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_smoke_page.dart b/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_smoke_page.dart index 30f79fd..f343d9c 100644 --- a/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_smoke_page.dart +++ b/lib/sign_up/presentation/pages/profile_lifestyle/profile_lifestyle_smoke_page.dart @@ -1,41 +1,32 @@ +import 'package:code_l/sign_up/data/datasources/local/smoke_options.dart'; import 'package:code_l/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart'; import 'package:code_l/sign_up/presentation/pages/profile_lifestyle/widgets/profile_lifestyle_check_icon.dart'; import 'package:flutter/cupertino.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'; +import '../providers.dart'; -class ProfileLifestyleSmokePage extends StatefulWidget { +class ProfileLifestyleSmokePage extends ConsumerWidget { const ProfileLifestyleSmokePage({super.key}); @override - State createState() => _CodeLifestyleDrinkPageState(); -} - -class _CodeLifestyleDrinkPageState extends State { - int? selectedIndex; - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = true; - final drinkOptions = [ - '흡연중이에요', - '가끔 흡연해요', - '비흡연자지만 흡연에 거부감은 없어요', - '비흡연자이며, 흡연자는 원치 않아요', - ]; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: SignUpAppBar(currentPage: 5), bottomNavigationBar: Padding( padding: const EdgeInsets.all(AppGaps.gap20), child: ConfirmButton( - enabled: selectedIndex != null, + enabled: state.isSmokeValid, onPressed: () { Navigator.push( context, @@ -62,18 +53,16 @@ class _CodeLifestyleDrinkPageState extends State { Expanded( child: ListView.separated( - itemCount: drinkOptions.length, + itemCount: smokeOptions.length, separatorBuilder: (_, __) => const SizedBox(height: AppGaps.gap16), itemBuilder: (context, index) { - final item = drinkOptions[index]; - final isSelected = selectedIndex == index; + final item = smokeOptions[index]; + final isSelected = state.selectedSmokeIndex == index; return GestureDetector( onTap: () { - setState(() { - selectedIndex = index; - }); + notifier.updateSelectedSmokeIndex(index); }, child: Container( padding: const EdgeInsets.symmetric( @@ -97,7 +86,7 @@ class _CodeLifestyleDrinkPageState extends State { buildCheckIcon(isSelected), const SizedBox(width: 10), Text( - drinkOptions[index], + smokeOptions[index], style: AppTypography.body2.copyWith( color: AppColors.grey800, ), diff --git a/lib/sign_up/presentation/pages/profile_lovestyle/profile_lovestyle_page.dart b/lib/sign_up/presentation/pages/profile_lovestyle/profile_lovestyle_page.dart index e44c72d..14d6527 100644 --- a/lib/sign_up/presentation/pages/profile_lovestyle/profile_lovestyle_page.dart +++ b/lib/sign_up/presentation/pages/profile_lovestyle/profile_lovestyle_page.dart @@ -1,78 +1,22 @@ import 'package:code_l/sign_up/presentation/widgets/sign_up_app_bar.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 '../../../data/datasources/local/love_style.dart'; import '../../widgets/sign_up_confirm_button.dart'; import '../profile_region/profile_region_page.dart'; +import '../providers.dart'; -class ProfileLoveStylePage extends StatefulWidget { +class ProfileLoveStylePage extends ConsumerWidget { const ProfileLoveStylePage({super.key}); - - @override - State createState() => _ProfileLoveStylePageState(); -} - -class _ProfileLoveStylePageState extends State { - int? selectedRelationshipIndex; - int? selectedAffectionIndex; - int? selectedCommunicationIndex; - int? selectedDateIndex; - int? selectedConflictIndex; - - final List relationshipStyles = [ - '천천히 알아가는 스타일 ⏳', - '만나면 운명이라고 믿는 직진형 💫', - '안정적이고 신뢰감 있는 연애 선호 🏡', - '서로의 성장과 자립을 중요시하는 스타일 🌱', - '항상 새롭고 설레는 연애를 추구하는 스타일 💃', - ]; - - final List communicationStyles = [ - '하루 종일 연락하는 스타일 📲', - '중요한 순간에만 연락하는 스타일 🕰', - '전화보다 톡을 선호하는 스타일 💬', - '하루 한 통이라도 진심을 담는 스타일 💌', - '상대가 필요할 때 항상 먼저 연락하는 스타일 🙋‍♂️', - ]; - - final List dateStyles = [ - '집에서 함께 영화 보는 홈 데이트 🏠', - '맛집 탐방하고 새로운 곳 찾기 🍔', - '야외활동이나 스포츠 즐기기 🚴‍♂️', - '문화생활 (전시회, 공연 등) 즐기기 🎭', - '계획적이고 철저한 데이트 스케줄러 📅', - '즉흥적으로 놀러 가는 스타일 🌍', - ]; - - final List conflictResolutionStyles = [ - '바로 대화해서 푸는 직설형💬', - '시간이 지난 후 차분하게 이야기하는 스타일🤫', - '상대방의 입장을 먼저 이해하는 배려형🤝', - '잘못을 빠르게 인정하고 사과하는 솔직형🙇‍♂️', - '화가 나도 조용히 마음을 가라앉히는 침착형🧘‍♀️', - ]; - - final List affectionExpressions = [ - '표현을 잘하는 직진형 💬', - '은근하게 마음을 전하는 무뚝뚝형 😎', - '말보다는 행동으로 표현하는 실천파 🚶‍♂', - '애교 많고 귀여운 스타일 🥰', - '진지하고 깊이 있는 스타일 🤔', - '다정다감한 배려형 💕', - ]; - - bool get isValid => - selectedRelationshipIndex != null && - selectedAffectionIndex != null && - selectedCommunicationIndex != null && - selectedDateIndex != null && - selectedConflictIndex != null; - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: const SignUpAppBar(currentPage: 7), @@ -82,7 +26,7 @@ class _ProfileLoveStylePageState extends State { vertical: 34, ), child: ConfirmButton( - enabled: isValid, + enabled: state.isLoveStyleValid, onPressed: () { Navigator.push( context, @@ -114,11 +58,9 @@ class _ProfileLoveStylePageState extends State { relationshipStyles.length, (index) => _buildSelectableItem( text: relationshipStyles[index], - isSelected: selectedRelationshipIndex == index, + isSelected: state.selectedRelationshipIndex == index, onTap: () { - setState(() { - selectedRelationshipIndex = index; - }); + notifier.updateSelectedRelationship(index); }, ), ), @@ -129,11 +71,9 @@ class _ProfileLoveStylePageState extends State { affectionExpressions.length, (index) => _buildSelectableItem( text: affectionExpressions[index], - isSelected: selectedAffectionIndex == index, + isSelected: state.selectedAffectionIndex == index, onTap: () { - setState(() { - selectedAffectionIndex = index; - }); + notifier.updateSelectedAffection(index); }, ), ), @@ -144,11 +84,9 @@ class _ProfileLoveStylePageState extends State { communicationStyles.length, (index) => _buildSelectableItem( text: communicationStyles[index], - isSelected: selectedCommunicationIndex == index, + isSelected: state.selectedCommunicationIndex == index, onTap: () { - setState(() { - selectedCommunicationIndex = index; - }); + notifier.updateSelectedCommunication(index); }, ), ), @@ -159,11 +97,9 @@ class _ProfileLoveStylePageState extends State { dateStyles.length, (index) => _buildSelectableItem( text: dateStyles[index], - isSelected: selectedDateIndex == index, + isSelected: state.selectedDateIndex == index, onTap: () { - setState(() { - selectedDateIndex = index; - }); + notifier.updateSelectedDate(index); }, ), ), @@ -174,11 +110,9 @@ class _ProfileLoveStylePageState extends State { conflictResolutionStyles.length, (index) => _buildSelectableItem( text: conflictResolutionStyles[index], - isSelected: selectedConflictIndex == index, + isSelected: state.selectedConflictIndex == index, onTap: () { - setState(() { - selectedConflictIndex = index; - }); + notifier.updateSelectedConflict(index); }, ), ), 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 3a8ebd6..fc330c0 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 @@ -1,29 +1,23 @@ import 'package:code_l/sign_up/presentation/pages/profile_introduce/profile_introduce_page.dart'; -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 '../../../data/datasources/local/mbti_options.dart'; import '../../widgets/sign_up_app_bar.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.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); + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: const SignUpAppBar(currentPage: 9), @@ -33,7 +27,7 @@ class ProfileMBTIPage extends ConsumerWidget { vertical: 34, ), child: ConfirmButton( - enabled: mbtiState.isValid, + enabled: state.isMbtiValid, onPressed: () { Navigator.push( context, @@ -64,7 +58,7 @@ class ProfileMBTIPage extends ConsumerWidget { child: Row( children: group.map((option) { - final isSelected = viewModel.isSelected( + final isSelected = notifier.isMbtiSelected( groupIndex, option, ); @@ -75,7 +69,7 @@ class ProfileMBTIPage extends ConsumerWidget { ), child: GestureDetector( onTap: - () => viewModel.select( + () => notifier.selectMbti( groupIndex, option, ), 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 deleted file mode 100644 index ccbc8b0..0000000 --- a/lib/sign_up/presentation/pages/profile_mbti/profile_mbti_viewmodel.dart +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 90f47cd..0000000 --- a/lib/sign_up/presentation/pages/profile_mbti/providers.dart +++ /dev/null @@ -1,9 +0,0 @@ -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(), - ); diff --git a/lib/sign_up/presentation/pages/profile_name/profile_name_page.dart b/lib/sign_up/presentation/pages/profile_name/profile_name_page.dart index 58fd3da..db5ac45 100644 --- a/lib/sign_up/presentation/pages/profile_name/profile_name_page.dart +++ b/lib/sign_up/presentation/pages/profile_name/profile_name_page.dart @@ -3,18 +3,20 @@ import 'package:code_l/core/utills/design/app_gaps.dart'; import 'package:code_l/core/utills/design/app_typography.dart'; import 'package:code_l/sign_up/presentation/pages/profile_age/profile_age_page.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../widgets/sign_up_app_bar.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.dart'; -class ProfileNamePage extends StatelessWidget { +class ProfileNamePage extends ConsumerWidget { const ProfileNamePage({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; - final isValid = true; // todo 상태관리 - + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: SignUpAppBar(currentPage: 1), body: SafeArea( @@ -26,9 +28,9 @@ class ProfileNamePage extends StatelessWidget { SizedBox(height: screenHeight * 0.05), _buildHeaderText(), SizedBox(height: AppGaps.gap40 + AppGaps.gap40), - _buildCodeNameInputField(isValid, TextEditingController()), + _buildCodeNameInputField(state.isNameValid, notifier,state), Spacer(), - ConfirmButton(enabled: isValid, onPressed: () { + ConfirmButton(enabled: state.isNameValid, onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => ProfileAgePage()), @@ -59,13 +61,14 @@ Widget _buildHeaderText() { Widget _buildCodeNameInputField( bool isValid, - TextEditingController controller, + notifier, + state, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextField( - controller: controller, + onChanged: notifier.updateName, decoration: InputDecoration( hintText: '코드네임을 입력해주세요', hintStyle: AppTypography.header2.copyWith(color: AppColors.grey400), @@ -81,7 +84,7 @@ Widget _buildCodeNameInputField( ), suffixIcon: IconButton( icon: Icon(Icons.clear, size: 16), - onPressed: () => controller.clear(), + onPressed: () => notifier.updateName(''), ), ), ), diff --git a/lib/sign_up/presentation/pages/profile_region/profile_region_page.dart b/lib/sign_up/presentation/pages/profile_region/profile_region_page.dart index 8020206..ad062ae 100644 --- a/lib/sign_up/presentation/pages/profile_region/profile_region_page.dart +++ b/lib/sign_up/presentation/pages/profile_region/profile_region_page.dart @@ -1,303 +1,23 @@ import 'package:code_l/sign_up/presentation/pages/profile_mbti/profile_mbti_page.dart'; import 'package:code_l/sign_up/presentation/widgets/sign_up_app_bar.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 '../../../data/datasources/local/region_options.dart'; import '../../widgets/sign_up_confirm_button.dart'; +import '../providers.dart'; -class ProfileRegionPage extends StatefulWidget { +class ProfileRegionPage extends ConsumerWidget { const ProfileRegionPage({super.key}); @override - State createState() => _ProfileRegionPageState(); -} - -class _ProfileRegionPageState extends State { - int? selectedMainRegionIndex; - int? selectedSubRegionIndex; - - final List mainRegions = [ - '서울', - '경기', - '부산', - '대구', - '인천', - '광주', - '대전', - '울산', - '세종', - '충북', - '충남', - '전북', - '전남', - '경북', - '경남', - '제주', - ]; - - final Map> subRegions = { - '서울': [ - '강남', - '강동', - '강북', - '강서', - '관악', - '광진', - '구로', - '금천', - '노원', - '도봉', - '동대문', - '동작', - '마포', - '서대문', - '서초', - '성동', - '성북', - '송파', - '양천', - '영등포', - '용산', - '은평', - '종로', - '중구', - '중랑', - ], - '경기': [ - '가평군', - '고양시', - '덕양구', - '일산동구', - '일산서구', - '과천시', - '광명시', - '광주시', - '구리시', - '군포시', - '김포시', - '남양주시', - '동두천시', - '부천시', - '소사구', - '오정구', - '원미구', - '성남시', - '분당구', - '수정구', - '중원구', - '수원시', - '권선구', - '영통구', - '장안구', - '팔달구', - '시흥시', - '안산시', - '단원구', - '상록구', - '안성시', - '안양시', - '동안구', - '만안구', - '양주시', - '양평군', - '여주시', - '연천군', - '오산시', - '용인시', - '기흥구', - '수지구', - '처인구', - '의왕시', - '의정부시', - '이천시', - '파주시', - '평택시', - '포천시', - '하남시', - '화성시', - ], - '부산': [ - '강서구', - '금정구', - '기장군', - '남구', - '동구', - '동래구', - '부산진구', - '북구', - '사상구', - '사하구', - '서구', - '수영구', - '연제구', - '영도구', - '중구', - '해운대구', - '해운대', - '서면', - '남포동', - '광안리', - '기장', - ], - '대구': ['군위군', '남구', '달서구', '달성군', '동구', '북구', '서구', '수성구', '중구', '동성로'], - '인천': [ - '강화군', - '계양구', - '남동구', - '동구', - '미추홀구', - '부평구', - '서구', - '연수구', - '옹진군', - '중구', - '송도', - '부평', - '청라', - ], - '광주': ['상무지구', '충장로', '광산구', '남구', '동구', '북구', '서구'], - '대전': ['대덕구', '동구', '서구', '유성구', '중구'], - '울산': ['남구', '동구', '북구', '울주군', '중구'], - '세종': ['세종 전체'], - '충북': [ - '괴산군', - '단양군', - '보은군', - '영동군', - '옥천군', - '음성군', - '제천시', - '증평군', - '진천군', - '청주시', - '상당구', - '서원구', - '청원구', - '흥덕구', - '충주시', - ], - '충남': [ - '계룡시', - '공주시', - '금산군', - '논산시', - '당진시', - '보령시', - '부여군', - '서산시', - '서천군', - '아산시', - '예산군', - '천안시', - '동남구', - '서북구', - '청양군', - '태안군', - '홍성군', - ], - '전북': [ - '고창군', - '군산시', - '김제시', - '남원시', - '무주군', - '부안군', - '순창군', - '완주군', - '익산시', - '임실군', - '장수군', - '전주시', - '전주시 덕진구', - '전주시 완산구', - '정읍시', - '진안군', - ], - '전남': [ - '강진군', - '고흥군', - '곡성군', - '광양시', - '구례군', - '나주시', - '담양군', - '목포시', - '무안군', - '보성군', - '순천시', - '신안군', - '여수시', - '영광군', - '영암군', - '완도군', - '장성군', - '장흥군', - '진도군', - '함평군', - '해남군', - '화순군', - ], - '경북': [ - '경산시', - '경주시', - '고령군', - '구미시', - '군위군', - '김천시', - '문경시', - '봉화군', - '상주시', - '성주군', - '안동시', - '영덕군', - '영양군', - '영주시', - '영천시', - '예천군', - '울릉군', - '울진군', - '의성군', - '청도군', - '청송군', - '칠곡군', - '포항시', - ], - '경남': [ - '거제시', - '거창군', - '고성군', - '김해시', - '남해군', - '밀양시', - '사천시', - '산청군', - '양산시', - '의령군', - '진주시', - '창녕군', - '창원시', - '창원시 마산합포구', - '창원시 마산회원구', - '창원시 성산구', - '창원시 의창구', - '창원시 진해구', - '통영시', - '하동군', - '함안군', - '함양군', - '합천군', - ], - '제주': ['서귀포시', '제주시'], - }; - - bool get isValid => - selectedMainRegionIndex != null && selectedSubRegionIndex != null; - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final screenHeight = MediaQuery.of(context).size.height; + final state = ref.watch(profileProvider); + final notifier = ref.read(profileProvider.notifier); return Scaffold( appBar: const SignUpAppBar(currentPage: 8), @@ -307,7 +27,7 @@ class _ProfileRegionPageState extends State { vertical: 34, ), child: ConfirmButton( - enabled: isValid, + enabled: state.isRegionValid, onPressed: () { Navigator.push( context, @@ -334,13 +54,10 @@ class _ProfileRegionPageState extends State { child: ListView.builder( itemCount: mainRegions.length, itemBuilder: (context, index) { - final isSelected = selectedMainRegionIndex == index; + final isSelected = state.selectedMainRegionIndex == index; return GestureDetector( onTap: () { - setState(() { - selectedMainRegionIndex = index; - selectedSubRegionIndex = null; - }); + notifier.updateSelectedMainRegion(index); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 16), @@ -363,22 +80,20 @@ class _ProfileRegionPageState extends State { SizedBox(width: AppGaps.gap20), Expanded( child: - selectedMainRegionIndex == null + state.selectedMainRegionIndex == null ? const SizedBox.shrink() : ListView.builder( itemCount: - subRegions[mainRegions[selectedMainRegionIndex!]]! + subRegions[mainRegions[state.selectedMainRegionIndex!]]! .length, itemBuilder: (context, index) { final subRegionName = - subRegions[mainRegions[selectedMainRegionIndex!]]![index]; + subRegions[mainRegions[state.selectedMainRegionIndex!]]![index]; final isSelected = - selectedSubRegionIndex == index; + state.selectedSubRegionIndex == index; return GestureDetector( onTap: () { - setState(() { - selectedSubRegionIndex = index; - }); + notifier.updateSelectedSubRegion(index); }, child: Container( padding: const EdgeInsets.symmetric( diff --git a/lib/sign_up/presentation/pages/profile_viewmodel.dart b/lib/sign_up/presentation/pages/profile_viewmodel.dart new file mode 100644 index 0000000..1296368 --- /dev/null +++ b/lib/sign_up/presentation/pages/profile_viewmodel.dart @@ -0,0 +1,157 @@ +import 'package:code_l/sign_up/presentation/pages/providers.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as ref; + +import '../../data/datasources/local/drink_options.dart'; +import '../../data/datasources/local/interest_options.dart'; +import '../../data/datasources/local/love_style.dart'; +import '../../data/datasources/local/region_options.dart'; +import '../../data/datasources/local/smoke_options.dart'; +import '../../domain/model/profile_state.dart'; + + + +class ProfileViewmodel extends StateNotifier { + ProfileViewmodel() : super(ProfileState()); + + get selectedIndexes => state.selectedInterestOptions; + + void sendTotalProfile(repository) async{ + await repository.sendProfile( + state.name ?? '', + state.age ?? 0, + state.selectedJob ?? '', + drinkOptions[state.selectedDrinkIndex ?? 0], + smokeOptions[state.selectedSmokeIndex ?? 0], + state.selectedInterestOptions + .map(interestOptions.elementAt) + .toList(), + [ + relationshipStyles[state.selectedRelationshipIndex ?? 0], + affectionExpressions[state.selectedAffectionIndex ?? 0], + communicationStyles[state.selectedCommunicationIndex ?? 0], + dateStyles[state.selectedDateIndex ?? 0], + conflictResolutionStyles[state.selectedConflictIndex ?? 0], + ], + mainRegions[state.selectedMainRegionIndex ?? 0], + subRegions[mainRegions[state.selectedMainRegionIndex ?? 0]]![state.selectedSubRegionIndex ?? 0], + '${state.ei ?? ''}${state.ns ?? ''}${state.tf ?? ''}${state.pj ?? ''}', + state.introduction, + ); + } + + void updateAge(String age) { + state = state.copyWith( + age: int.parse(age), + ageIsValid: age.isNotEmpty && age.length <= 3, + ); + } + + void deleteSelectedInterestIndexes(int index) { + final updatedIndexes = List.from(state.selectedInterestOptions)..remove(index); + state = state.copyWith( + selectedIndexes: updatedIndexes, + isSelectedOptionsValid: + updatedIndexes.isNotEmpty && updatedIndexes.length <= 5, + ); + } + + void addSelectedInterestIndexes(int index) { + final updatedIndexes = List.from(state.selectedInterestOptions)..add(index); + state = state.copyWith( + selectedIndexes: updatedIndexes, + isSelectedOptionsValid: + updatedIndexes.isNotEmpty && updatedIndexes.length <= 5, + ); + } + + void updateIntroduction(String introduction) { + state = state.copyWith( + introduction: introduction, + introductionIsValid: introduction.isNotEmpty && introduction.length <= 15, + ); + } + + void updateSelectedJob(String? selectedJob) { + state = state.copyWith( + selectedJob: selectedJob, + isJobValid: selectedJob != null, + ); + } + + void updateSelectedDrinkIndex(int selectedDrinkIndex) { + state = state.copyWith( + selectedDrinkIndex: selectedDrinkIndex, + isDrinkValid: selectedDrinkIndex != null, + ); + } + + void updateSelectedSmokeIndex(int selectedSmokeIndex) { + state = state.copyWith( + selectedSmokeIndex: selectedSmokeIndex, + isSmokeValid: selectedSmokeIndex != null, + ); + } + + void updateSelectedRelationship(int? selectedRelationshipIndex) { + state = state.copyWith( + selectedRelationshipIndex: selectedRelationshipIndex, + ); + } + + void updateSelectedAffection(int? selectedAffectionIndex) { + state = state.copyWith(selectedAffectionIndex: selectedAffectionIndex); + } + + void updateSelectedCommunication(int? selectedCommunicationIndex) { + state = state.copyWith( + selectedCommunicationIndex: selectedCommunicationIndex, + ); + } + + void updateSelectedDate(int? selectedDateIndex) { + state = state.copyWith(selectedDateIndex: selectedDateIndex); + } + + void updateSelectedConflict(int? selectedConflictIndex) { + state = state.copyWith(selectedConflictIndex: selectedConflictIndex); + } + + void selectMbti(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 isMbtiSelected(int groupIndex, String value) { + return switch (groupIndex) { + 0 => state.ei == value, + 1 => state.ns == value, + 2 => state.tf == value, + 3 => state.pj == value, + _ => false, + }; + } + + void updateName(String name) { + state = state.copyWith( + name: name, + isNameValid: name.isNotEmpty && name.length <= 10, + ); + } + + void updateSelectedMainRegion(int selectedMainRegionIndex) { + state = state.copyWith( + selectedMainRegionIndex : selectedMainRegionIndex, + selectedSubRegionIndex : null + ); + } + + void updateSelectedSubRegion(int index) { + state = state.copyWith(selectedSubRegionIndex : index); + } +} diff --git a/lib/sign_up/presentation/pages/providers.dart b/lib/sign_up/presentation/pages/providers.dart new file mode 100644 index 0000000..f951f8e --- /dev/null +++ b/lib/sign_up/presentation/pages/providers.dart @@ -0,0 +1,26 @@ + +import 'package:code_l/sign_up/data/repositories/default_profile_repository.dart'; +import 'package:code_l/sign_up/presentation/pages/profile_viewmodel.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../../core/utills/network/profile_api_service.dart'; +import '../../data/datasources/providers.dart'; +import '../../data/datasources/remote/profile_remote_datasource.dart'; +import '../../domain/model/profile_state.dart'; +import '../../domain/repositories/profile_repository.dart'; + +final profileProvider = + StateNotifierProvider( + (ref) => ProfileViewmodel()); + +final profileRepositoryProvider = Provider((ref) { + final dataSource = ref.read(profileRemoteDataSourceProvider); + return DefaultProfileRepository( + profileRemoteDataSource: dataSource, + ); +}); + +final profileRemoteDataSourceProvider = Provider((ref) { + final dio = ref.read(profileApiServiceProvider); + return ProfileRemoteDatasource(dio); +}); \ No newline at end of file