diff --git a/Mark-In/Sources/App/AuthUserManager.swift b/Mark-In/Sources/App/AuthUserManager.swift new file mode 100644 index 0000000..871285c --- /dev/null +++ b/Mark-In/Sources/App/AuthUserManager.swift @@ -0,0 +1,46 @@ +// +// AuthManager.swift +// Mark-In +// +// Created by 이정동 on 5/8/25. +// + +// TODO: Core 모듈로 이전 예정 + +import Foundation + +import FirebaseAuth + +struct AuthUser { + let id: String +} + +protocol AuthUserManager { + var user: AuthUser? { get } + + func save(_ user: AuthUser) + func load() + func clear() +} + +@Observable +final class AuthUserManagerImpl: AuthUserManager { + var user: AuthUser? + + init() { + self.load() + } + + func load() { + guard let currentUser = Auth.auth().currentUser else { return } + self.user = AuthUser(id: currentUser.uid) + } + + func save(_ user: AuthUser) { + self.user = user + } + + func clear() { + user = nil + } +} diff --git a/Mark-In/Sources/App/DIContainer.swift b/Mark-In/Sources/App/DIContainer.swift new file mode 100644 index 0000000..c6de151 --- /dev/null +++ b/Mark-In/Sources/App/DIContainer.swift @@ -0,0 +1,56 @@ +// +// DIContainer.swift +// Mark-In +// +// Created by 이정동 on 5/5/25. +// + +import Foundation + +import LinkMetadataKit +import LinkMetadataKitInterface + +// TODO: 코어 모듈로 이전 +final class DIContainer { + static let shared = DIContainer() + private var dependencies: [String: Any] = [:] + + private init() {} + + func register(_ dependency: T) { + let key = String(describing: T.self) + dependencies[key] = dependency + } + + func resolve() -> T { + let key = String(describing: T.self) + let dependency = dependencies[key] + + guard let dependency = dependency as? T else { + fatalError("\(key)는 register되지 않았어어요. resolve 부르기전에 register 해주세요") + } + + return dependency + } +} + +extension DIContainer { + func registerDependencies() { + + /// Core + let linkMetadataProvider: LinkMetadataProvider = LinkMetadataProviderImpl() + let authUserManager: AuthUserManager = AuthUserManagerImpl() + + register(linkMetadataProvider) + register(authUserManager) + + /// Repository + let folderRepository: FolderRepository = FolderRepositoryImpl() + let linkRepository: LinkRepository = LinkRepositoryImpl( + linkMetadataProvider: linkMetadataProvider + ) + + register(folderRepository) + register(linkRepository) + } +} diff --git a/Mark-In/Sources/App/Mark_InApp.swift b/Mark-In/Sources/App/Mark_InApp.swift index a945642..6bbcf17 100644 --- a/Mark-In/Sources/App/Mark_InApp.swift +++ b/Mark-In/Sources/App/Mark_InApp.swift @@ -20,11 +20,13 @@ struct Mark_InApp: App { configureFirebase() configureGoogleSignIn() + + DIContainer.shared.registerDependencies() } var body: some Scene { WindowGroup { - MainView() + RootView() .frame(minWidth: 500, minHeight: 500) .onOpenURL { url in GIDSignIn.sharedInstance.handle(url) diff --git a/Mark-In/Sources/App/RootView.swift b/Mark-In/Sources/App/RootView.swift new file mode 100644 index 0000000..9c758de --- /dev/null +++ b/Mark-In/Sources/App/RootView.swift @@ -0,0 +1,29 @@ +// +// RootView.swift +// Mark-In +// +// Created by 이정동 on 5/5/25. +// + +import SwiftUI + +import DesignSystem + +struct RootView: View { + + @State private var authUserManager: AuthUserManager = DIContainer.shared.resolve() + + var body: some View { + ZStack { + if authUserManager.user != nil { + MainView() + } else { + LoginView() + } + } + } +} + +#Preview { + RootView() +} diff --git a/Mark-In/Sources/Feature/Common/Reducer.swift b/Mark-In/Sources/Feature/Common/Reducer.swift index 0df23a5..0f30140 100644 --- a/Mark-In/Sources/Feature/Common/Reducer.swift +++ b/Mark-In/Sources/Feature/Common/Reducer.swift @@ -7,14 +7,13 @@ import Foundation +@MainActor protocol Reducer { associatedtype State associatedtype Action - @MainActor func send(_ action: Action) - @MainActor func reduce(state: inout State, action: Action) -> Effect } diff --git a/Mark-In/Sources/Feature/Login/LoginView.swift b/Mark-In/Sources/Feature/Login/LoginView.swift index e413a96..5d39f4e 100644 --- a/Mark-In/Sources/Feature/Login/LoginView.swift +++ b/Mark-In/Sources/Feature/Login/LoginView.swift @@ -117,7 +117,7 @@ private struct SignInButtonList: View { } private struct SignInButton: View { - let provider: OAuthProvider + let provider: SocialSignInProvider let action: () -> Void diff --git a/Mark-In/Sources/Feature/Login/LoginViewModel.swift b/Mark-In/Sources/Feature/Login/LoginViewModel.swift index cdd764c..9a2c7d4 100644 --- a/Mark-In/Sources/Feature/Login/LoginViewModel.swift +++ b/Mark-In/Sources/Feature/Login/LoginViewModel.swift @@ -17,7 +17,7 @@ import Util @Observable final class LoginViewModel: Reducer { struct State { - var isSignInSuccess: Bool = false + // TODO: 로그인 실패 시 알림 화면을 보여줄 상태 구현 생각 중 } enum Action { @@ -27,12 +27,17 @@ final class LoginViewModel: Reducer { case signInError(SignInError) case firebaseAuthRequest(AuthCredential) - case firebaseAuthResponse(Result) + case firebaseAuthResponse(Result) case empty } private(set) var state: State = .init() + private let authUserManager: AuthUserManager + + init() { + self.authUserManager = DIContainer.shared.resolve() + } func send(_ action: Action) { let effect = reduce(state: &state, action: action) @@ -108,9 +113,9 @@ final class LoginViewModel: Reducer { return .run { do { /// Firebase 인증 요청 - let _ = try await Auth.auth().signIn(with: credential) + let response = try await Auth.auth().signIn(with: credential) - return .firebaseAuthResponse(.success(())) + return .firebaseAuthResponse(.success(response.user.uid)) } catch { return .firebaseAuthResponse(.failure(error)) } @@ -118,8 +123,9 @@ final class LoginViewModel: Reducer { case .firebaseAuthResponse(let result): switch result { - case .success(_): - state.isSignInSuccess = true + case .success(let id): + let user = AuthUser(id: id) + authUserManager.save(user) case .failure(let error): // TODO: 에러 처리 필요 let _ = error as? AuthErrorCode @@ -137,9 +143,9 @@ final class LoginViewModel: Reducer { case .none: break case .run(let action): - Task { + Task.detached { [weak self] in let newAction = await action() - await send(newAction) + await self?.send(newAction) } } } diff --git a/Mark-In/Sources/Feature/Main/MainViewModel.swift b/Mark-In/Sources/Feature/Main/MainViewModel.swift index 6aaed15..136f4c3 100644 --- a/Mark-In/Sources/Feature/Main/MainViewModel.swift +++ b/Mark-In/Sources/Feature/Main/MainViewModel.swift @@ -7,7 +7,7 @@ import Foundation -@MainActor @Observable +@Observable final class MainViewModel: Reducer { struct State { var isLoading: Bool = true diff --git a/Shared/Util/Sources/OAuthProvider.swift b/Shared/Util/Sources/OAuthProvider.swift index be1629f..c5cb681 100644 --- a/Shared/Util/Sources/OAuthProvider.swift +++ b/Shared/Util/Sources/OAuthProvider.swift @@ -7,7 +7,7 @@ import Foundation -public enum OAuthProvider { +public enum SocialSignInProvider { case apple case google }