Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions DevLog/App/Assembler/AppLayerAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ final class AppLayerAssembler: Assembler {
func assemble(_ container: any DIContainer) {
container.register(FCMTokenSyncHandler.self) {
FCMTokenSyncHandler(
repository: container.resolve(UserDataRepository.self)
userService: container.resolve(UserService.self)
)
}
container.register(UserTimeZoneSyncHandler.self) {
UserTimeZoneSyncHandler(
repository: container.resolve(UserDataRepository.self)
userService: container.resolve(UserService.self)
)
}
}
Expand Down
6 changes: 6 additions & 0 deletions DevLog/App/Assembler/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ final class DataAssembler: Assembler {
)
}

container.register(NetworkConnectivityRepository.self) {
NetworkConnectivityRepositoryImpl(
connectivityProvider: container.resolve(NWPathConnectivityProvider.self)
)
}

container.register(AuthDataRepository.self) {
AuthDataRepositoryImpl(
authService: container.resolve(AuthService.self),
Expand Down
9 changes: 9 additions & 0 deletions DevLog/App/Assembler/DomainAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
final class DomainAssembler: Assembler {
func assemble(_ container: DIContainer) {
registerAuthUseCases(container)
registerConnectivityUseCases(container)
registerAuthProviderUseCases(container)
registerTodoUseCases(container)
registerUserDataUseCases(container)
Expand Down Expand Up @@ -36,6 +37,14 @@ private extension DomainAssembler {
}
}

func registerConnectivityUseCases(_ container: DIContainer) {
container.register(ObserveNetworkConnectivityUseCase.self) {
ObserveNetworkConnectivityUseCaseImpl(
container.resolve(NetworkConnectivityRepository.self)
)
Comment thread
opficdev marked this conversation as resolved.
}
}

func registerAuthProviderUseCases(_ container: DIContainer) {
container.register(FetchAuthProvidersUseCase.self) {
FetchAuthProvidersUseCaseImpl(container.resolve(AuthDataRepository.self))
Expand Down
3 changes: 3 additions & 0 deletions DevLog/App/Assembler/InfraAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@ final class InfraAssembler: Assembler {
WebPageMetadataService()
}

container.register(NWPathConnectivityProvider.self) {
NWPathConnectivityProvider()
}
}
}
1 change: 1 addition & 0 deletions DevLog/App/DevLogApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct DevLogApp: App {
WindowGroup {
RootView(viewModel: RootViewModel(
sessionUseCase: container.resolve(AuthSessionUseCase.self),
observeNetworkConnectivityUseCase: container.resolve(ObserveNetworkConnectivityUseCase.self),
observeSystemThemeUseCase: container.resolve(ObserveSystemThemeUseCase.self)
))
.autocorrectionDisabled()
Expand Down
8 changes: 4 additions & 4 deletions DevLog/App/Handler/FCMTokenSyncHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ import Combine
import Foundation

final class FCMTokenSyncHandler {
private let repository: UserDataRepository
private let userService: UserService
private let logger = Logger(category: "FCMTokenSyncHandler")
private var cancellables = Set<AnyCancellable>()

init(
repository: UserDataRepository,
userService: UserService,
notificationCenter: NotificationCenter = .default
) {
self.repository = repository
self.userService = userService

notificationCenter.publisher(for: .didRefreshFCMToken)
.compactMap { $0.userInfo?["fcmToken"] as? String }
.sink { [weak self] fcmToken in
Task {
do {
try await self?.repository.updateFCMToken(fcmToken)
try await self?.userService.updateFCMToken(fcmToken)
} catch {
self?.logger.error("Failed to sync refreshed FCM token", error: error)
}
Expand Down
8 changes: 4 additions & 4 deletions DevLog/App/Handler/UserTimeZoneSyncHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ import Combine
import UIKit

final class UserTimeZoneSyncHandler {
private let repository: UserDataRepository
private let userService: UserService
private let logger = Logger(category: "UserTimeZoneSyncHandler")
private var cancellables = Set<AnyCancellable>()

init(
repository: UserDataRepository,
userService: UserService,
notificationCenter: NotificationCenter = .default
) {
self.repository = repository
self.userService = userService

notificationCenter.publisher(for: .didRequestUserTimeZoneSync)
.merge(with: notificationCenter.publisher(for: UIApplication.willEnterForegroundNotification))
.sink { [weak self] _ in
Task {
do {
try await self?.repository.updateUserTimeZone()
try await self?.userService.updateUserTimeZone()
} catch {
self?.logger.error("Failed to sync user timeZone", error: error)
}
Expand Down
20 changes: 20 additions & 0 deletions DevLog/Data/Repository/NetworkConnectivityRepositoryImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// NetworkConnectivityRepositoryImpl.swift
// DevLog
//
// Created by opfic on 3/26/26.
//

import Combine

final class NetworkConnectivityRepositoryImpl: NetworkConnectivityRepository {
private let connectivityProvider: NWPathConnectivityProvider

init(connectivityProvider: NWPathConnectivityProvider) {
self.connectivityProvider = connectivityProvider
}

var publisher: AnyPublisher<Bool, Never> {
connectivityProvider.isConnectedPublisher
}
}
8 changes: 0 additions & 8 deletions DevLog/Data/Repository/UserDataRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,4 @@ final class UserDataRepositoryImpl: UserDataRepository {
func upsertStatusMessage(_ message: String) async throws {
try await userService.upsertStatusMessage(message)
}

func updateFCMToken(_ fcmToken: String) async throws {
try await userService.updateFCMToken(fcmToken)
}

func updateUserTimeZone() async throws {
try await userService.updateUserTimeZone()
}
}
12 changes: 12 additions & 0 deletions DevLog/Domain/Protocol/NetworkConnectivityRepository.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// NetworkConnectivityRepository.swift
// DevLog
//
// Created by opfic on 3/26/26.
//

import Combine

protocol NetworkConnectivityRepository {
var publisher: AnyPublisher<Bool, Never> { get }
}
2 changes: 0 additions & 2 deletions DevLog/Domain/Protocol/UserDataRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@
protocol UserDataRepository {
func fetch() async throws -> UserProfile
func upsertStatusMessage(_ message: String) async throws
func updateFCMToken(_ fcmToken: String) async throws
func updateUserTimeZone() async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// ObserveNetworkConnectivityUseCase.swift
// DevLog
//
// Created by opfic on 3/26/26.
//

import Combine

protocol ObserveNetworkConnectivityUseCase {
var publisher: AnyPublisher<Bool, Never> { get }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// ObserveNetworkConnectivityUseCaseImpl.swift
// DevLog
//
// Created by opfic on 3/26/26.
//

import Combine

final class ObserveNetworkConnectivityUseCaseImpl: ObserveNetworkConnectivityUseCase {
private let repository: NetworkConnectivityRepository

init(_ repository: NetworkConnectivityRepository) {
self.repository = repository
}
Comment thread
opficdev marked this conversation as resolved.

var publisher: AnyPublisher<Bool, Never> {
repository.publisher
}
}
6 changes: 4 additions & 2 deletions DevLog/Presentation/ViewModel/RootViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@ final class RootViewModel: Store {
}

private(set) var state: State
private let connectivityProvider = NWPathConnectivityProvider()
private var cancellables = Set<AnyCancellable>()
private let sessionUseCase: AuthSessionUseCase
private let observeNetworkConnectivityUseCase: ObserveNetworkConnectivityUseCase
private let observeSystemThemeUseCase: ObserveSystemThemeUseCase

init(
sessionUseCase: AuthSessionUseCase,
observeNetworkConnectivityUseCase: ObserveNetworkConnectivityUseCase,
observeSystemThemeUseCase: ObserveSystemThemeUseCase
) {
self.sessionUseCase = sessionUseCase
self.observeNetworkConnectivityUseCase = observeNetworkConnectivityUseCase
self.observeSystemThemeUseCase = observeSystemThemeUseCase
self.state = State()

Expand Down Expand Up @@ -96,7 +98,7 @@ private extension RootViewModel {
}

func setupNetworkMonitoring() {
connectivityProvider.isConnectedPublisher
observeNetworkConnectivityUseCase.publisher
.dropFirst()
.removeDuplicates()
.receive(on: DispatchQueue.main)
Expand Down
3 changes: 1 addition & 2 deletions docs/architecture.d2
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ data -> storage: "Store call"

infra -> external: "Firebase SDK, social login, metadata fetch"

app -> domain: "exception, Handler -> UserDataRepository"
presentation -> infra: "exception, NWPathConnectivityProvider"
app -> infra: "Handler -> UserService"
Binary file modified docs/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.