Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions DevLog/App/Assembler/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ final class DataAssembler: Assembler {

container.register(AuthSessionRepository.self) {
AuthSessionRepositoryImpl(
authService: container.resolve(AuthService.self),
userDefaultsStore: container.resolve(UserDefaultsStore.self)
authService: container.resolve(AuthService.self)
)
}

Expand Down
8 changes: 0 additions & 8 deletions DevLog/App/Assembler/DomainAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,6 @@ private extension DomainAssembler {
UpdateSystemThemeUseCaseImpl(container.resolve(UserPreferencesRepository.self))
}

container.register(FetchFirstLaunchUseCase.self) {
FetchFirstLaunchUseCaseImpl(container.resolve(UserPreferencesRepository.self))
}

container.register(UpdateFirstLaunchUseCase.self) {
UpdateFirstLaunchUseCaseImpl(container.resolve(UserPreferencesRepository.self))
}

container.register(FetchRecentSearchQueriesUseCase.self) {
FetchRecentSearchQueriesUseCaseImpl(container.resolve(UserPreferencesRepository.self))
}
Expand Down
6 changes: 1 addition & 5 deletions DevLog/App/DevLogApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ struct DevLogApp: App {
WindowGroup {
RootView(viewModel: RootViewModel(
sessionUseCase: container.resolve(AuthSessionUseCase.self),
signOutUseCase: container.resolve(SignOutUseCase.self),
fetchFirstLaunchUseCase: container.resolve(FetchFirstLaunchUseCase.self),
updateFirstLaunchUseCase: container.resolve(UpdateFirstLaunchUseCase.self),
observeSystemThemeUseCase: container.resolve(ObserveSystemThemeUseCase.self),
updateSystemThemeUseCase: container.resolve(UpdateSystemThemeUseCase.self)
observeSystemThemeUseCase: container.resolve(ObserveSystemThemeUseCase.self)
))
.autocorrectionDisabled()
}
Expand Down
25 changes: 3 additions & 22 deletions DevLog/App/RootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,19 @@ struct RootView: View {
ZStack {
Color(UIColor.systemGroupedBackground).ignoresSafeArea()
if let signIn = viewModel.state.signIn {
if signIn && !viewModel.state.isFirstLaunch {
if signIn {
MainView(viewModel: MainViewModel(
observeUnreadPushCountUseCase: container.resolve(ObserveUnreadPushCountUseCase.self)
))
} else {
LoginView(viewModel: LoginViewModel(
signInUseCase: container.resolve(SignInUseCase.self),
signOutUseCase: container.resolve(SignOutUseCase.self),
sessionUseCase: container.resolve(AuthSessionUseCase.self))
signInUseCase: container.resolve(SignInUseCase.self))
)
.onAppear {
viewModel.send(.onAppear)
}
}
} else {
Color.clear.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
if viewModel.state.signIn == nil {
viewModel.send(.setFirstLaunch(true))
viewModel.send(.signOutAuto)
}
}
}
}
}
.preferredColorScheme(viewModel.state.theme.colorScheme)
.onAppear { viewModel.send(.onAppear) }
.alert(viewModel.state.alertTitle, isPresented: Binding(
get: { viewModel.state.showAlert },
set: { viewModel.send(.setAlert($0)) }
Expand All @@ -50,12 +37,6 @@ struct RootView: View {
} message: {
Text(viewModel.state.alertMessage)
}
.onChange(of: viewModel.state.isFirstLaunch) { _, newValue in
if newValue {
viewModel.send(.setFirstLaunch(false))
viewModel.send(.signOutAuto)
}
}
.sheet(item: $selectedRoute) { route in
switch route {
case .todoDetail(let todoId):
Expand Down
16 changes: 2 additions & 14 deletions DevLog/Data/Repository/AuthSessionRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,12 @@ import Combine

final class AuthSessionRepositoryImpl: AuthSessionRepository {
private let authService: AuthService
private let userDefaultsStore: UserDefaultsStore

init(authService: AuthService, userDefaultsStore: UserDefaultsStore) {
init(authService: AuthService) {
self.authService = authService
self.userDefaultsStore = userDefaultsStore
self.signIn = authService.uid != nil
}

@Published private var signIn: Bool = false

var signedInPublisher: AnyPublisher<Bool, Never> {
$signIn.eraseToAnyPublisher()
}

func setSession(_ signedIn: Bool) {
if !signedIn {
userDefaultsStore.removeAll()
}
self.signIn = signedIn
authService.signedInPublisher
}
}
21 changes: 13 additions & 8 deletions DevLog/Data/Repository/AuthenticationRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,21 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository {
let providerID = try await authService.getProviderID(),
let provider = AuthProvider(rawValue: providerID)
else {
throw AuthError.notAuthenticated
try await authService.clearCurrentSession()
return
}

switch provider {
case .apple:
try await appleAuthService.signOut(uid)
case .github:
try await githubAuthService.signOut(uid)
case .google:
try await googleAuthService.signOut(uid)
do {
switch provider {
case .apple:
try await appleAuthService.signOut(uid)
case .github:
try await githubAuthService.signOut(uid)
case .google:
try await googleAuthService.signOut(uid)
}
} catch AuthError.notAuthenticated {
try await authService.clearCurrentSession()
}
}

Expand Down
12 changes: 0 additions & 12 deletions DevLog/Data/Repository/UserPreferencesRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Combine
final class UserPreferencesRepositoryImpl: UserPreferencesRepository {
private enum Key {
static let theme = "theme"
static let firstLaunch = "isFirstLaunch"
static let recentQueries = "Search.recentQueries"
static let pushSortOrder = "PushNotification.sortOption"
static let pushTimeFilter = "PushNotification.timeFilter"
Expand Down Expand Up @@ -50,17 +49,6 @@ final class UserPreferencesRepositoryImpl: UserPreferencesRepository {
themeStore.send(theme)
}

func isFirstLaunch() -> Bool {
if store.string(forKey: Key.firstLaunch) == nil {
return true
}
return store.bool(forKey: Key.firstLaunch)
}

func setFirstLaunch(_ value: Bool) {
store.setBool(value, forKey: Key.firstLaunch)
}

func recentSearchQueries() -> [String] {
store.stringArray(forKey: Key.recentQueries)
}
Expand Down
1 change: 0 additions & 1 deletion DevLog/Domain/Protocol/AuthSessionRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ import Combine

protocol AuthSessionRepository {
var signedInPublisher: AnyPublisher<Bool, Never> { get }
func setSession(_ signedIn: Bool)
}
3 changes: 0 additions & 3 deletions DevLog/Domain/Protocol/UserPreferencesRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ protocol UserPreferencesRepository {
func systemTheme() -> SystemTheme
func setSystemTheme(_ theme: SystemTheme)

func isFirstLaunch() -> Bool
func setFirstLaunch(_ value: Bool)

func recentSearchQueries() -> [String]
func setRecentSearchQueries(_ queries: [String])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ import Combine

protocol AuthSessionUseCase {
var signedInPublisher: AnyPublisher<Bool, Never> { get }
func execute(_ signIn: Bool)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,4 @@ final class AuthSessionUseCaseImpl: AuthSessionUseCase {
init(_ repository: AuthSessionRepository) {
self.repository = repository
}

func execute(_ signIn: Bool) {
repository.setSession(signIn)
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

20 changes: 20 additions & 0 deletions DevLog/Infra/Service/AuthService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by 최윤진 on 11/29/25.
//

import Combine
import FirebaseAuth
import FirebaseFirestore
import FirebaseMessaging
Expand All @@ -13,15 +14,34 @@ final class AuthService {
private let store = Firestore.firestore()
private let messaging = Messaging.messaging()
private let logger = Logger(category: "AuthService")
private let subject = CurrentValueSubject<Bool, Never>(Auth.auth().currentUser != nil)
private var handler: AuthStateDidChangeListenerHandle?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

handler 속성은 init 초기화 시에만 값이 할당되고 이후에는 변경되지 않습니다. var 대신 let으로 선언하여 불변성(immutability)을 보장하는 것이 더 안전하고 명확한 코드가 될 것입니다.

Suggested change
private var handler: AuthStateDidChangeListenerHandle?
private let handler: AuthStateDidChangeListenerHandle?


var uid: String? {
Auth.auth().currentUser?.uid
}

var signedInPublisher: AnyPublisher<Bool, Never> {
subject.eraseToAnyPublisher()
}

var providerIDs: [String] {
Auth.auth().currentUser?.providerData.map { $0.providerID } ?? []
}

init() {
handler = Auth.auth().addStateDidChangeListener { [weak self] _, user in
let signedIn = user != nil
self?.logger.info("Firebase auth state changed. signedIn: \(signedIn)")
self?.subject.send(signedIn)
}
}

deinit {
guard let handler else { return }
Auth.auth().removeStateDidChangeListener(handler)
}

func getProviderID() async throws -> String? {
logger.info("Fetching current provider ID")

Expand Down
Loading