diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 70d1b84..cadf740 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -54,6 +54,19 @@
+
+
+
+
+
+
+
+
+
11.10.0)
- Firebase/CoreOnly (11.10.0):
- FirebaseCore (~> 11.10.0)
+ - Firebase/Firestore (11.10.0):
+ - Firebase/CoreOnly
+ - FirebaseFirestore (~> 11.10.0)
- firebase_auth (5.5.2):
- Firebase/Auth (= 11.10.0)
- firebase_core
@@ -30,7 +1232,30 @@ PODS:
- FirebaseCore (~> 11.10.0)
- FirebaseCoreInternal (11.10.0):
- "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - FirebaseFirestore (11.10.0):
+ - FirebaseCore (~> 11.10.0)
+ - FirebaseCoreExtension (~> 11.10.0)
+ - FirebaseFirestoreInternal (= 11.10.0)
+ - FirebaseSharedSwift (~> 11.0)
+ - FirebaseFirestoreInternal (11.10.0):
+ - abseil/algorithm (~> 1.20240722.0)
+ - abseil/base (~> 1.20240722.0)
+ - abseil/container/flat_hash_map (~> 1.20240722.0)
+ - abseil/memory (~> 1.20240722.0)
+ - abseil/meta (~> 1.20240722.0)
+ - abseil/strings/strings (~> 1.20240722.0)
+ - abseil/time (~> 1.20240722.0)
+ - abseil/types (~> 1.20240722.0)
+ - FirebaseAppCheckInterop (~> 11.0)
+ - FirebaseCore (~> 11.10.0)
+ - "gRPC-C++ (~> 1.69.0)"
+ - gRPC-Core (~> 1.69.0)
+ - leveldb-library (~> 1.22)
+ - nanopb (~> 3.30910.0)
+ - FirebaseSharedSwift (11.12.0)
- Flutter (1.0.0)
+ - flutter_secure_storage (6.0.0):
+ - Flutter
- fluttertoast (0.0.2):
- Flutter
- GoogleUtilities/AppDelegateSwizzler (8.0.2):
@@ -54,9 +1279,112 @@ PODS:
- GoogleUtilities/Reachability (8.0.2):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
+ - "gRPC-C++ (1.69.0)":
+ - "gRPC-C++/Implementation (= 1.69.0)"
+ - "gRPC-C++/Interface (= 1.69.0)"
+ - "gRPC-C++/Implementation (1.69.0)":
+ - abseil/algorithm/container (~> 1.20240722.0)
+ - abseil/base/base (~> 1.20240722.0)
+ - abseil/base/config (~> 1.20240722.0)
+ - abseil/base/core_headers (~> 1.20240722.0)
+ - abseil/base/log_severity (~> 1.20240722.0)
+ - abseil/base/no_destructor (~> 1.20240722.0)
+ - abseil/cleanup/cleanup (~> 1.20240722.0)
+ - abseil/container/flat_hash_map (~> 1.20240722.0)
+ - abseil/container/flat_hash_set (~> 1.20240722.0)
+ - abseil/container/inlined_vector (~> 1.20240722.0)
+ - abseil/flags/flag (~> 1.20240722.0)
+ - abseil/flags/marshalling (~> 1.20240722.0)
+ - abseil/functional/any_invocable (~> 1.20240722.0)
+ - abseil/functional/bind_front (~> 1.20240722.0)
+ - abseil/functional/function_ref (~> 1.20240722.0)
+ - abseil/hash/hash (~> 1.20240722.0)
+ - abseil/log/absl_check (~> 1.20240722.0)
+ - abseil/log/absl_log (~> 1.20240722.0)
+ - abseil/log/check (~> 1.20240722.0)
+ - abseil/log/globals (~> 1.20240722.0)
+ - abseil/log/log (~> 1.20240722.0)
+ - abseil/memory/memory (~> 1.20240722.0)
+ - abseil/meta/type_traits (~> 1.20240722.0)
+ - abseil/numeric/bits (~> 1.20240722.0)
+ - abseil/random/bit_gen_ref (~> 1.20240722.0)
+ - abseil/random/distributions (~> 1.20240722.0)
+ - abseil/random/random (~> 1.20240722.0)
+ - abseil/status/status (~> 1.20240722.0)
+ - abseil/status/statusor (~> 1.20240722.0)
+ - abseil/strings/cord (~> 1.20240722.0)
+ - abseil/strings/str_format (~> 1.20240722.0)
+ - abseil/strings/strings (~> 1.20240722.0)
+ - abseil/synchronization/synchronization (~> 1.20240722.0)
+ - abseil/time/time (~> 1.20240722.0)
+ - abseil/types/optional (~> 1.20240722.0)
+ - abseil/types/span (~> 1.20240722.0)
+ - abseil/types/variant (~> 1.20240722.0)
+ - abseil/utility/utility (~> 1.20240722.0)
+ - "gRPC-C++/Interface (= 1.69.0)"
+ - "gRPC-C++/Privacy (= 1.69.0)"
+ - gRPC-Core (= 1.69.0)
+ - "gRPC-C++/Interface (1.69.0)"
+ - "gRPC-C++/Privacy (1.69.0)"
+ - gRPC-Core (1.69.0):
+ - gRPC-Core/Implementation (= 1.69.0)
+ - gRPC-Core/Interface (= 1.69.0)
+ - gRPC-Core/Implementation (1.69.0):
+ - abseil/algorithm/container (~> 1.20240722.0)
+ - abseil/base/base (~> 1.20240722.0)
+ - abseil/base/config (~> 1.20240722.0)
+ - abseil/base/core_headers (~> 1.20240722.0)
+ - abseil/base/log_severity (~> 1.20240722.0)
+ - abseil/base/no_destructor (~> 1.20240722.0)
+ - abseil/cleanup/cleanup (~> 1.20240722.0)
+ - abseil/container/flat_hash_map (~> 1.20240722.0)
+ - abseil/container/flat_hash_set (~> 1.20240722.0)
+ - abseil/container/inlined_vector (~> 1.20240722.0)
+ - abseil/flags/flag (~> 1.20240722.0)
+ - abseil/flags/marshalling (~> 1.20240722.0)
+ - abseil/functional/any_invocable (~> 1.20240722.0)
+ - abseil/functional/bind_front (~> 1.20240722.0)
+ - abseil/functional/function_ref (~> 1.20240722.0)
+ - abseil/hash/hash (~> 1.20240722.0)
+ - abseil/log/check (~> 1.20240722.0)
+ - abseil/log/globals (~> 1.20240722.0)
+ - abseil/log/log (~> 1.20240722.0)
+ - abseil/memory/memory (~> 1.20240722.0)
+ - abseil/meta/type_traits (~> 1.20240722.0)
+ - abseil/numeric/bits (~> 1.20240722.0)
+ - abseil/random/bit_gen_ref (~> 1.20240722.0)
+ - abseil/random/distributions (~> 1.20240722.0)
+ - abseil/random/random (~> 1.20240722.0)
+ - abseil/status/status (~> 1.20240722.0)
+ - abseil/status/statusor (~> 1.20240722.0)
+ - abseil/strings/cord (~> 1.20240722.0)
+ - abseil/strings/str_format (~> 1.20240722.0)
+ - abseil/strings/strings (~> 1.20240722.0)
+ - abseil/synchronization/synchronization (~> 1.20240722.0)
+ - abseil/time/time (~> 1.20240722.0)
+ - abseil/types/optional (~> 1.20240722.0)
+ - abseil/types/span (~> 1.20240722.0)
+ - abseil/types/variant (~> 1.20240722.0)
+ - abseil/utility/utility (~> 1.20240722.0)
+ - BoringSSL-GRPC (= 0.0.37)
+ - gRPC-Core/Interface (= 1.69.0)
+ - gRPC-Core/Privacy (= 1.69.0)
+ - gRPC-Core/Interface (1.69.0)
+ - gRPC-Core/Privacy (1.69.0)
- GTMSessionFetcher/Core (4.4.0)
+ - image_picker_ios (0.0.1):
+ - Flutter
- kakao_flutter_sdk_common (1.9.7-3):
- Flutter
+ - leveldb-library (1.22.6)
+ - nanopb (3.30910.0):
+ - nanopb/decode (= 3.30910.0)
+ - nanopb/encode (= 3.30910.0)
+ - nanopb/decode (3.30910.0)
+ - nanopb/encode (3.30910.0)
+ - path_provider_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
- RecaptchaInterop (101.0.0)
- screen_protector (1.2.1):
- Flutter
@@ -65,18 +1393,27 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
+ - sign_in_with_apple (0.0.1):
+ - Flutter
DEPENDENCIES:
+ - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- Flutter (from `Flutter`)
+ - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
+ - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- kakao_flutter_sdk_common (from `.symlinks/plugins/kakao_flutter_sdk_common/ios`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- screen_protector (from `.symlinks/plugins/screen_protector/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
+ - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
SPEC REPOS:
trunk:
+ - abseil
+ - BoringSSL-GRPC
- Firebase
- FirebaseAppCheckInterop
- FirebaseAuth
@@ -84,28 +1421,48 @@ SPEC REPOS:
- FirebaseCore
- FirebaseCoreExtension
- FirebaseCoreInternal
+ - FirebaseFirestore
+ - FirebaseFirestoreInternal
+ - FirebaseSharedSwift
- GoogleUtilities
+ - "gRPC-C++"
+ - gRPC-Core
- GTMSessionFetcher
+ - leveldb-library
+ - nanopb
- RecaptchaInterop
- ScreenProtectorKit
EXTERNAL SOURCES:
+ cloud_firestore:
+ :path: ".symlinks/plugins/cloud_firestore/ios"
firebase_auth:
:path: ".symlinks/plugins/firebase_auth/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
Flutter:
:path: Flutter
+ flutter_secure_storage:
+ :path: ".symlinks/plugins/flutter_secure_storage/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
+ image_picker_ios:
+ :path: ".symlinks/plugins/image_picker_ios/ios"
kakao_flutter_sdk_common:
:path: ".symlinks/plugins/kakao_flutter_sdk_common/ios"
+ path_provider_foundation:
+ :path: ".symlinks/plugins/path_provider_foundation/darwin"
screen_protector:
:path: ".symlinks/plugins/screen_protector/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
+ sign_in_with_apple:
+ :path: ".symlinks/plugins/sign_in_with_apple/ios"
SPEC CHECKSUMS:
+ abseil: a05cc83bf02079535e17169a73c5be5ba47f714b
+ BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508
+ cloud_firestore: aef3217af294cd35afda47e63112d306f4c9a2e2
Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
firebase_auth: e37065f3f80ff90580c13ad0e5a48e3bb8d2ad77
firebase_core: 432718558359a8c08762151b5f49bb0f093eb6e0
@@ -115,15 +1472,26 @@ SPEC CHECKSUMS:
FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
FirebaseCoreExtension: 6f357679327f3614e995dc7cf3f2d600bdc774ac
FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
+ FirebaseFirestore: 3f1488ff7739cb3c5d10e572bc4e9fcd8e8cb4ac
+ FirebaseFirestoreInternal: 97a2bb5f16951c77753c860d3519379702ab6f8a
+ FirebaseSharedSwift: d2475748a2d2a36242ed13baa34b2acda846c925
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
+ "gRPC-C++": cc207623316fb041a7a3e774c252cf68a058b9e8
+ gRPC-Core: 860978b7db482de8b4f5e10677216309b5ff6330
GTMSessionFetcher: 75b671f9e551e4c49153d4c4f8659ef4f559b970
+ image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
kakao_flutter_sdk_common: 3dc8492c202af7853585d151490b1c5c6b7576cb
+ leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
+ nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
+ path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
screen_protector: 6f92086bd2f2f4b54f54913289b9d1310610140b
ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
+ sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
PODFILE CHECKSUM: f8c2dcdfb50bb67645580d28a6bf814fca30bdec
diff --git a/ios/Runner/RunnerDebug.entitlements b/ios/Runner/RunnerDebug.entitlements
index 903def2..80b5221 100644
--- a/ios/Runner/RunnerDebug.entitlements
+++ b/ios/Runner/RunnerDebug.entitlements
@@ -4,5 +4,9 @@
aps-environment
development
+ com.apple.developer.applesignin
+
+ Default
+
diff --git a/lib/auth/data/datasources/local/login_local_datasource.dart b/lib/auth/data/datasources/local/login_local_datasource.dart
new file mode 100644
index 0000000..19730b9
--- /dev/null
+++ b/lib/auth/data/datasources/local/login_local_datasource.dart
@@ -0,0 +1,26 @@
+import 'dart:developer';
+
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+
+class LoginLocalDataSource{
+ static final _storage = FlutterSecureStorage();
+ static const _jwtKey = 'jwt_token';
+
+ /// JWT 저장
+ static Future saveToken(String token) async {
+ await _storage.write(key: _jwtKey, value: token);
+ log(name: 'Dio Interceptor', '토큰 저장 : $token');
+ }
+
+ /// JWT 불러오기
+ static Future loadToken() async {
+ final token = await _storage.read(key: _jwtKey);
+ log(name: 'Dio Interceptor', '토큰 불러오기: $token');
+ return token;
+ }
+
+ /// JWT 삭제
+ static Future deleteToken() async {
+ await _storage.delete(key: _jwtKey);
+ }
+}
diff --git a/lib/auth/data/datasources/remote/auth_remote_datasource.dart b/lib/auth/data/datasources/remote/auth_remote_datasource.dart
index 8fe9a7a..5953b5e 100644
--- a/lib/auth/data/datasources/remote/auth_remote_datasource.dart
+++ b/lib/auth/data/datasources/remote/auth_remote_datasource.dart
@@ -1,4 +1,8 @@
+import 'dart:developer';
+
import '../../../../core/utills/network/auth_api_service.dart';
+import '../../../../main.dart';
+import '../../../domain/model/sign_up_state.dart';
import '../../models/request/login_request.dart';
class AuthRemoteDataSource {
@@ -9,11 +13,21 @@ class AuthRemoteDataSource {
Future loginWithOauth({
required String type,
required String id,
+ required String email,
}) async {
final response = await api.login(
- LoginRequest(oauthType: type, oauthId: id),
+ LoginRequest(oauthType: type, oauthId: id, email: email),
);
final jwt = response.headers.value('Authorization') ?? '';
+ final userStatus = response.data['memberStatus'] ?? '';
+
+ final state = SignUpState.fromString(userStatus);
+ await saveSignUpState(state);
+
+ log(
+ name: 'LoginViewModel::loginWithOauth',
+ 'success: $userStatus',
+ );
return jwt;
}
diff --git a/lib/auth/data/datasources/remote/login_remote_datasource.dart b/lib/auth/data/datasources/remote/login_remote_datasource.dart
index cd210f6..438cb4a 100644
--- a/lib/auth/data/datasources/remote/login_remote_datasource.dart
+++ b/lib/auth/data/datasources/remote/login_remote_datasource.dart
@@ -1,3 +1,5 @@
+import 'dart:developer';
+
import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
@@ -15,8 +17,7 @@ class LoginRemoteDataSource {
}
Future loginWithApple() async {
- final AuthorizationCredentialAppleID
- credential = await SignInWithApple.getAppleIDCredential(
+ final credential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
@@ -28,6 +29,11 @@ class LoginRemoteDataSource {
),
),
);
+
+ log(
+ name: 'LoginRemoteDataSource::loginWithApple',
+ 'success: ${credential.identityToken}',
+ );
return credential;
}
}
diff --git a/lib/auth/data/models/request/login_request.dart b/lib/auth/data/models/request/login_request.dart
index 31d9d88..4358de7 100644
--- a/lib/auth/data/models/request/login_request.dart
+++ b/lib/auth/data/models/request/login_request.dart
@@ -1,8 +1,9 @@
class LoginRequest {
final String oauthType;
final String oauthId;
+ final String email;
- LoginRequest({required this.oauthType, required this.oauthId});
+ LoginRequest({required this.oauthType, required this.oauthId, required this.email});
- Map toJson() => {'oauthType': oauthType, 'oauthId': oauthId};
+ Map toJson() => {'oauthType': oauthType, 'oauthId': oauthId, 'email': email};
}
diff --git a/lib/auth/data/models/response/login_response.dart b/lib/auth/data/models/response/login_response.dart
index 5ce88bf..51145e1 100644
--- a/lib/auth/data/models/response/login_response.dart
+++ b/lib/auth/data/models/response/login_response.dart
@@ -1,13 +1,13 @@
class LoginResponse {
- final String memberStatus;
+ final String userStatus;
final String jwt;
- LoginResponse({required this.memberStatus, required this.jwt});
+ LoginResponse({required this.userStatus, required this.jwt});
factory LoginResponse.fromJson(
Map json, {
required String jwt,
}) {
- return LoginResponse(memberStatus: json['memberStatus'], jwt: jwt);
+ return LoginResponse(userStatus: json['userStatus'], jwt: jwt);
}
}
diff --git a/lib/auth/data/repositories/default_login_repository.dart b/lib/auth/data/repositories/default_login_repository.dart
index b07e1cc..f007561 100644
--- a/lib/auth/data/repositories/default_login_repository.dart
+++ b/lib/auth/data/repositories/default_login_repository.dart
@@ -21,11 +21,11 @@ class DefaultLoginRepository implements LoginRepository {
@override
Future loginWithApple() {
- throw loginRemoteDataSource.loginWithApple();
+ return loginRemoteDataSource.loginWithApple();
}
@override
- Future loginOauth(String type, String id) {
- return authRemoteDataSource.loginWithOauth(type: type, id: id);
+ Future loginOauth(String type, String id, String email) {
+ return authRemoteDataSource.loginWithOauth(type: type, id: id,email: email);
}
}
diff --git a/lib/auth/domain/model/identity/phone_number.dart b/lib/auth/domain/model/identity/phone_number.dart
index f4a3117..fd51619 100644
--- a/lib/auth/domain/model/identity/phone_number.dart
+++ b/lib/auth/domain/model/identity/phone_number.dart
@@ -1,4 +1,6 @@
+import 'dart:developer';
+
class PhoneNumber {
final String value;
diff --git a/lib/auth/domain/model/sign_up_state.dart b/lib/auth/domain/model/sign_up_state.dart
new file mode 100644
index 0000000..b0072c6
--- /dev/null
+++ b/lib/auth/domain/model/sign_up_state.dart
@@ -0,0 +1,16 @@
+enum SignUpState {
+ NONE,
+ SIGNUP,
+ IDENTIFY,
+ CODE_SURVEY,
+ CODE_PROFILE_IMAGE,
+ PENDING,
+ DONE;
+
+ static SignUpState fromString(String? value) {
+ return SignUpState.values.firstWhere(
+ (e) => e.name == value,
+ orElse: () => SignUpState.NONE,
+ );
+ }
+}
diff --git a/lib/auth/domain/repositories/login_repository.dart b/lib/auth/domain/repositories/login_repository.dart
index fa76f39..6dcaa36 100644
--- a/lib/auth/domain/repositories/login_repository.dart
+++ b/lib/auth/domain/repositories/login_repository.dart
@@ -2,7 +2,7 @@ import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
abstract class LoginRepository {
- Future loginOauth(String type, String id);
+ Future loginOauth(String type, String id, String email);
Future loginWithKakao();
Future loginWithApple();
}
diff --git a/lib/auth/domain/usecases/login_usecase.dart b/lib/auth/domain/usecases/login_usecase.dart
index 3203eb9..31adfba 100644
--- a/lib/auth/domain/usecases/login_usecase.dart
+++ b/lib/auth/domain/usecases/login_usecase.dart
@@ -15,12 +15,12 @@ class LoginUseCase {
return await repository.loginWithApple();
}
- Future callOauth(LoginType type, String id) async {
+ Future callOauth(LoginType type, String id, String email) async {
switch (type) {
case LoginType.kakao:
- return await repository.loginOauth('KAKAO', id);
+ return await repository.loginOauth('KAKAO', id, email);
case LoginType.apple:
- return await repository.loginOauth('APPLE', id);
+ return await repository.loginOauth('APPLE', id, email);
}
}
}
diff --git a/lib/auth/domain/usecases/phone_number_verification_usecase.dart b/lib/auth/domain/usecases/phone_number_verification_usecase.dart
index c8c6c47..d171bb0 100644
--- a/lib/auth/domain/usecases/phone_number_verification_usecase.dart
+++ b/lib/auth/domain/usecases/phone_number_verification_usecase.dart
@@ -1,9 +1,11 @@
import 'dart:developer';
import 'package:cloud_firestore/cloud_firestore.dart';
+import 'package:code_l/main.dart';
import 'package:firebase_auth/firebase_auth.dart';
import '../model/identity/phone_number.dart';
+import '../model/sign_up_state.dart';
import '../repositories/phone_number_repository.dart';
class PhoneNumberVerificationUseCase {
@@ -15,6 +17,7 @@ class PhoneNumberVerificationUseCase {
PhoneNumber phoneNumber,
Function(String) onCodeSent,
) async {
+ log(name: 'PhoneNumberVerificationUseCase : sendCode', '핸드폰 번호 : ${phoneNumber.value}');
await _authRepository.verifyPhoneNumber(phoneNumber.value, onCodeSent);
}
@@ -36,6 +39,7 @@ class PhoneNumberVerificationUseCase {
Future saveUser() async {
final user = FirebaseAuth.instance.currentUser;
+ log(name: 'PhoneNumberVerificationUseCase : saveUser', 'user phone : ${user}' );
if (user != null) {
final uid = user.uid;
final phone = PhoneNumber.fromInternational(user.phoneNumber!);
@@ -44,10 +48,13 @@ class PhoneNumberVerificationUseCase {
.collection('users')
.doc(uid)
.set({
- 'phoneNumber': phone,
+ 'phoneNumber': phone.value,
'createdAt': FieldValue.serverTimestamp(),
});
log(name: 'PhoneNumberVerificationUseCase : saveUser', 'firestore에 사용자 정보 저장 완료');
+
+ saveSignUpState(SignUpState.IDENTIFY);
+ log(name: 'PhoneNumberVerificationUseCase : saveUser', '전화번호 인증 완료');
} else {
log(name: 'PhoneNumberVerificationUseCase : saveUser', 'firestore에 사용자 정보 저장 실패');
}
diff --git a/lib/auth/presentation/pages/congratulation/congratulation_page.dart b/lib/auth/presentation/pages/congratulation/congratulation_page.dart
index a31ea27..33d4955 100644
--- a/lib/auth/presentation/pages/congratulation/congratulation_page.dart
+++ b/lib/auth/presentation/pages/congratulation/congratulation_page.dart
@@ -1,4 +1,5 @@
import 'package:code_l/auth/presentation/pages/congratulation/widgets/congratulation_app_bar.dart';
+import 'package:code_l/sign_up/presentation/pages/profile_name/profile_name_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import '../../../../core/utills/design/app_colors.dart';
@@ -13,11 +14,11 @@ class CongratulationPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: const CongratulationAppBar(),
- body: _buildContentField(),
+ body: _buildContentField(context),
);
}
- Widget _buildContentField() {
+ Widget _buildContentField(BuildContext context) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: AppGaps.gap20),
@@ -105,7 +106,14 @@ class CongratulationPage extends StatelessWidget {
child: CongratulationConfirmButton(
enabled: true,
text: "코드 프로필 작성하기",
- onPressed: () {},
+ onPressed: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const ProfileNamePage(),
+ ),
+ );
+ },
),
),
],
diff --git a/lib/auth/presentation/pages/identity/identity_verification_page.dart b/lib/auth/presentation/pages/identity/identity_verification_page.dart
index 7e83b13..7b34cdf 100644
--- a/lib/auth/presentation/pages/identity/identity_verification_page.dart
+++ b/lib/auth/presentation/pages/identity/identity_verification_page.dart
@@ -3,10 +3,11 @@ import 'package:code_l/auth/presentation/pages/identity/widgets/identity_verific
import 'package:code_l/auth/presentation/widgets/auth_confirm_button.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 '../login/login_page.dart';
+import '../terms_and_conditions/terms_and_condition_page.dart';
class PhoneVerificationPage extends ConsumerWidget {
const PhoneVerificationPage({Key? key}) : super(key: key);
@@ -27,7 +28,7 @@ class PhoneVerificationPage extends ConsumerWidget {
viewModel.verifyCode(() {
Navigator.pushReplacement(
context,
- MaterialPageRoute(builder: (context) => const LoginPage()),
+ MaterialPageRoute(builder: (context) => const TermsAndConditionPage()),
);
});
}
diff --git a/lib/auth/presentation/pages/login/login_viewmodel.dart b/lib/auth/presentation/pages/login/login_viewmodel.dart
index 4ca3fa0..ca31f9e 100644
--- a/lib/auth/presentation/pages/login/login_viewmodel.dart
+++ b/lib/auth/presentation/pages/login/login_viewmodel.dart
@@ -1,9 +1,9 @@
import 'dart:developer';
+import 'package:code_l/auth/data/datasources/local/login_local_datasource.dart';
import 'package:code_l/auth/domain/model/login_type.dart';
import 'package:flutter/cupertino.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/usecases/login_usecase.dart';
@@ -14,55 +14,48 @@ class LoginViewModel extends ChangeNotifier {
Future loginWithKakao() async {
try {
- bool installed = await isKakaoTalkInstalled();
+ User user = await useCase.callKakaoLogin(LoginType.kakao);
- OAuthToken token =
- installed
- ? await UserApi.instance.loginWithKakaoTalk()
- : await UserApi.instance.loginWithKakaoAccount();
-
- final user = await UserApi.instance.me();
-
- log(name: 'LoginViewModel::login', 'success: $token');
- await loginOauth(LoginType.kakao, user.id.toString());
+ log(name: 'LoginViewModel::login', 'success: user id = ${user.id}, email = ${user.kakaoAccount?.email}');
+ await loginOauth(LoginType.kakao, user.id.toString(), user.kakaoAccount?.email ?? '');
} catch (e) {
log(name: 'LoginViewModel::login', 'error: $e');
}
}
- Future loginOauth(LoginType type, String id) async {
- try {
- final jwt = await useCase.callOauth(type, id);
-
- log(name: 'LoginViewModel::loginOauth', 'success: $jwt');
- } catch (e) {
- log(name: 'LoginViewModel::loginOauth', 'error: $e');
- }
- }
-
Future loginWithApple() async {
try {
// 애플 인증 정보 가져오기
- final credential = useCase.callAppleLogin(LoginType.apple);
+ final credential = await useCase.callAppleLogin(LoginType.apple);
// authorizationCode와 identityToken 확인
- final authorizationCode = credential.then(
- (value) => value.authorizationCode,
- );
- final identityToken = credential.then((value) => value.identityToken);
+ final authorizationCode = credential.authorizationCode;
+ final id = credential.userIdentifier;
+ final email = credential.email;
- if (authorizationCode == null || identityToken == null) {
+ if (authorizationCode == null || id == null) {
throw Exception("Authorization Code 또는 Identity Token을 가져오지 못했습니다.");
}
// 백엔드로 OAuth 인증 요청
- await loginOauth(LoginType.apple, identityToken.toString());
+ await loginOauth(LoginType.apple, id.toString(),email.toString());
log(
name: 'LoginViewModel::loginWithApple',
- 'success: ${identityToken.toString()}',
+ 'success: $id',
);
} catch (e) {
log(name: 'LoginViewModel::loginWithApple', 'error: $e');
}
}
+
+ Future loginOauth(LoginType type, String id, String email) async {
+ try {
+ final jwt = await useCase.callOauth(type, id, email);
+
+ await LoginLocalDataSource.saveToken(jwt);
+ log(name: 'LoginViewModel::loginOauth', 'success: $jwt');
+ } catch (e) {
+ log(name: 'LoginViewModel::loginOauth', 'error: $e');
+ }
+ }
}
diff --git a/lib/core/utills/network/dio_provider.dart b/lib/core/utills/network/dio_provider.dart
index 5c9a8b3..2c5cf33 100644
--- a/lib/core/utills/network/dio_provider.dart
+++ b/lib/core/utills/network/dio_provider.dart
@@ -1,9 +1,10 @@
+import 'package:code_l/auth/data/datasources/local/login_local_datasource.dart';
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final dioProvider = Provider((ref) {
- return Dio(
+ final dio = Dio(
BaseOptions(
baseUrl: dotenv.env['BASE_URL'] ?? '',
connectTimeout: const Duration(seconds: 5),
@@ -11,4 +12,21 @@ final dioProvider = Provider((ref) {
headers: {'Content-Type': 'application/json'},
),
);
+
+ dio.interceptors.add(InterceptorsWrapper(
+ onRequest: (options, handler) async {
+ final token = await LoginLocalDataSource.loadToken();
+
+ if (token != null && token.isNotEmpty) {
+ options.headers['Authorization'] = 'Bearer $token';
+ }
+
+ return handler.next(options);
+ },
+ onError: (e, handler) {
+ return handler.next(e);
+ },
+ ));
+
+ return dio;
});
diff --git a/lib/main.dart b/lib/main.dart
index 975646d..b2ec713 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,6 +1,8 @@
+import 'package:code_l/auth/presentation/pages/identity/identity_verification_page.dart';
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_image_page.dart';
import 'package:code_l/sign_up/presentation/pages/profile_interest/profile_intereset_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
@@ -8,6 +10,9 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:kakao_flutter_sdk_user/kakao_flutter_sdk_user.dart';
import 'package:screen_protector/screen_protector.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+import 'auth/domain/model/sign_up_state.dart';
main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -28,7 +33,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Kakao Login Demo',
- home: const PendingApprovalPage(),
+ home: const InitialRouteLoader(),
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
@@ -36,3 +41,43 @@ class MyApp extends StatelessWidget {
);
}
}
+
+// todo : 패키지,아키텍처 리펙토링
+Future saveSignUpState(SignUpState state) async {
+ final prefs = await SharedPreferences.getInstance();
+ await prefs.setString('sign_up_state', state.name);
+}
+
+Future loadSignUpState() async {
+ final prefs = await SharedPreferences.getInstance();
+ final value = prefs.getString('sign_up_state');
+ return SignUpState.fromString(value);
+}
+
+class InitialRouteLoader extends StatelessWidget {
+ const InitialRouteLoader({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: loadSignUpState(),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const Scaffold(
+ body: Center(child: CircularProgressIndicator()),
+ );
+ }
+
+ return switch (snapshot.data!) {
+ SignUpState.SIGNUP => const PhoneVerificationPage(),
+ SignUpState.IDENTIFY => const TermsAndConditionPage(),
+ SignUpState.CODE_SURVEY => const ProfileInterestPage(),
+ SignUpState.CODE_PROFILE_IMAGE => const ProfileImagePage(),
+ SignUpState.PENDING => const PendingApprovalPage(),
+ SignUpState.DONE => const LoginPage(), // todo home
+ SignUpState.NONE => const LoginPage(),
+ };
+ },
+ );
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index 656c2c0..6fda208 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -334,6 +334,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.6.1"
+ flutter_secure_storage:
+ dependency: "direct main"
+ description:
+ name: flutter_secure_storage
+ sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.2.4"
+ flutter_secure_storage_linux:
+ dependency: transitive
+ description:
+ name: flutter_secure_storage_linux
+ sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.3"
+ flutter_secure_storage_macos:
+ dependency: transitive
+ description:
+ name: flutter_secure_storage_macos
+ sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.3"
+ flutter_secure_storage_platform_interface:
+ dependency: transitive
+ description:
+ name: flutter_secure_storage_platform_interface
+ sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.2"
+ flutter_secure_storage_web:
+ dependency: transitive
+ description:
+ name: flutter_secure_storage_web
+ sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ flutter_secure_storage_windows:
+ dependency: transitive
+ description:
+ name: flutter_secure_storage_windows
+ sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
flutter_svg:
dependency: "direct main"
description:
@@ -460,10 +508,10 @@ packages:
dependency: transitive
description:
name: js
- sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
+ sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
- version: "0.7.2"
+ version: "0.6.7"
json_annotation:
dependency: transitive
description:
@@ -600,6 +648,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
+ path_provider:
+ dependency: transitive
+ description:
+ name: path_provider
+ sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.5"
+ path_provider_android:
+ dependency: transitive
+ description:
+ name: path_provider_android
+ sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.2.17"
+ path_provider_foundation:
+ dependency: transitive
+ description:
+ name: path_provider_foundation
+ sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@@ -689,7 +761,7 @@ packages:
source: hosted
version: "1.4.2+1"
shared_preferences:
- dependency: transitive
+ dependency: "direct main"
description:
name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
@@ -909,6 +981,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.12.0"
xdg_directories:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 43c4870..0d9d9be 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -49,6 +49,8 @@ dependencies:
image_picker: ^1.1.2
cloud_firestore: ^5.6.6
gif: ^2.3.0
+ shared_preferences: ^2.5.3
+ flutter_secure_storage: ^9.2.4
dev_dependencies:
flutter_test: