Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CAT-265] Home & Splash 오프라인 대응 #50

Merged
merged 7 commits into from
Aug 21, 2024
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
Binary file modified DependencyGraph/mohanyang_dev_graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified DependencyGraph/mohanyang_prod_graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public enum Core: String, Modulable {
case DatabaseClient
case UserDefaultsClient
case FeedbackGeneratorClient
case NetworkTracking
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ public enum Domain: String, Modulable {
case UserService
case CatService
case PomodoroService
case NetworkTracking
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import ProjectDescription
import ProjectDescriptionHelpers

@_spi(Domain)
@_spi(Core)
@_spi(Shared)
import DependencyPlugin

let project: Project = .makeTMABasedProject(
module: Domain.NetworkTracking,
module: Core.NetworkTracking,
scripts: [],
targets: [
.sources,
.interface
],
dependencies: [
.interface: [
.dependency(rootModule: Core.self)
.dependency(rootModule: Shared.self)
]
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ extension NetworkTracking: DependencyKey {
public static let liveValue: NetworkTracking = .live()

public static func live() -> NetworkTracking {
let networkMonitor = NWPathMonitor()
let globalQueue = DispatchQueue.global()

return NetworkTracking(
updateNetworkConnected: {
let networkMonitor = NWPathMonitor()
let globalQueue = DispatchQueue.global()

networkMonitor.start(queue: globalQueue)
return AsyncStream<Bool> { continuation in
let initialState = networkMonitor.currentPath.status == .satisfied ? true : false
Expand Down
23 changes: 20 additions & 3 deletions Projects/Feature/HomeFeature/Sources/Home/HomeCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import UserNotifications

import PomodoroFeature
import NetworkTrackingInterface
import PushService
import CatServiceInterface
import PomodoroServiceInterface
Expand All @@ -33,6 +34,8 @@ public struct HomeCore {
// 저장된 고양이 불러오고나서 이 state에 저장하면 될듯합니다
var selectedCat: AnyCat = CatFactory.makeCat(type: .threeColor, no: 0, name: "치즈냥")

var isNetworkConnected: Bool = false

var toast: DefaultToast?
var dialog: DefaultDialog?

Expand All @@ -48,6 +51,7 @@ public struct HomeCore {

public enum Action: BindableAction {
case binding(BindingAction<State>)
case task
case onLoad
case onAppear
case setHomeCatTooltip(HomeCatDialogueTooltip?)
Expand All @@ -58,7 +62,8 @@ public struct HomeCore {
case restTimeButtonTapped
case mypageButtonTappd
case playButtonTapped

case _fetchNetworkConnection(Bool)

case syncCategory

case categorySelect(PresentationAction<CategorySelectCore.Action>)
Expand All @@ -71,6 +76,7 @@ public struct HomeCore {
@Dependency(DatabaseClient.self) var databaseClient
@Dependency(APIClient.self) var apiClient
@Dependency(PomodoroService.self) var pomodoroService
@Dependency(NetworkTracking.self) var networkTracking
let isHomeGuideCompletedKey = "mohanyang_userdefaults_isHomeGuideCompleted"

public init() {}
Expand All @@ -96,7 +102,14 @@ public struct HomeCore {
switch action {
case .binding:
return .none


case .task:
return .run { send in
for await isConnected in networkTracking.updateNetworkConnected() {
await send(._fetchNetworkConnection(isConnected))
}
}

case .onLoad:
return .run { send in
await send(.setHomeCatTooltip(nil))
Expand Down Expand Up @@ -146,7 +159,11 @@ public struct HomeCore {
case .playButtonTapped:
state.focusPomodoro = .init()
return .none


case let ._fetchNetworkConnection(isConnected):
state.isNetworkConnected = isConnected
return .none

case .syncCategory:
return .run { send in
try await self.pomodoroService.syncCategoryList(
Expand Down
24 changes: 24 additions & 0 deletions Projects/Feature/HomeFeature/Sources/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,27 @@ public struct HomeView: View {
}
}
.background(Global.Color.gray50)
.overlay {
if !store.isNetworkConnected {
VStack {
HStack(spacing: Alias.Spacing.small) {
DesignSystemAsset.Image._16NullPrimary.swiftUIImage
Text("오프라인 모드")
.font(Typography.bodySB)
.foregroundStyle(Alias.Color.Text.secondary)
}
.padding(.horizontal, Alias.Spacing.large)
.padding(.vertical, Alias.Spacing.small)
.background {
RoundedRectangle(cornerRadius: Alias.BorderRadius.max)
.foregroundStyle(Global.Color.white)
.shadow(radius: Alias.BorderRadius.max, y: 4)
}
.padding(.top, Alias.Spacing.large)
Spacer()
}
}
}
.tooltipDestination(tooltip: $store.homeCatTooltip.sending(\.setHomeCatTooltip))
.tooltipDestination(tooltip: $store.homeCategoryGuideTooltip.sending(\.setHomeCategoryGuideTooltip))
.tooltipDestination(tooltip: $store.homeTimeGuideTooltip.sending(\.setHomeTimeGuideTooltip))
Expand Down Expand Up @@ -141,6 +162,9 @@ public struct HomeView: View {
) { store in
MyPageView(store: store)
}
.task {
await store.send(.task).finish()
}
.onLoad {
store.send(.onLoad)
}
Expand Down
49 changes: 41 additions & 8 deletions Projects/Feature/SplashFeature/Sources/SplashCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import DatabaseClientInterface
import KeychainClientInterface
import UserDefaultsClientInterface
import AppService
import NetworkTrackingInterface
import DesignSystem

import ComposableArchitecture

Expand All @@ -23,11 +25,16 @@ public struct SplashCore {
public init() { }
var width: CGFloat = .zero
var isLoggedIn: Bool = false

var dialog: DefaultDialog?
}

public enum Action: BindableAction {
case onAppear
case task
case didFinishInitializeDatabase
case _fetchNetworkConnection(Bool)
case _checkDeviceIDExist
case presentNetworkDialog
case moveToHome
case moveToOnboarding
case binding(BindingAction<State>)
Expand All @@ -43,6 +50,7 @@ public struct SplashCore {
@Dependency(DatabaseClient.self) var databaseClient
@Dependency(KeychainClient.self) var keychainClient
@Dependency(UserDefaultsClient.self) var userDefaultsClient
@Dependency(NetworkTracking.self) var networkTracking

public var body: some ReducerOf<Self> {
BindingReducer()
Expand All @@ -51,14 +59,44 @@ public struct SplashCore {

private func core(_ state: inout State, _ action: Action) -> EffectOf<Self> {
switch action {
case .onAppear:
case .task:
return .run { send in
try await initilizeDatabaseSystem(databaseClient: databaseClient)
await send(.didFinishInitializeDatabase)
}

case.didFinishInitializeDatabase:
return checkDeviceIDExist()
return .run { send in
for await isConnected in networkTracking.updateNetworkConnected() {
await send(._fetchNetworkConnection(isConnected))
}
}

case ._fetchNetworkConnection(let isConnected):
if isConnected {
return .run { send in
await send(._checkDeviceIDExist)
}
} else {
return .run { send in
if try await !databaseClient.checkHasTable() {
await send(.presentNetworkDialog)
} else {
await send(._checkDeviceIDExist)
}
}
}

case ._checkDeviceIDExist:
let deviceID = keychainClient.read(key: deviceIDKey) ?? getDeviceUUID()
return login(deviceID: deviceID)

case .presentNetworkDialog:
state.dialog = DefaultDialog(
title: "네트워크 연결을 확인해주세요",
firstButton: DialogButtonModel(title: "확인")
)
return .none

case .moveToHome:
return .none
Expand All @@ -73,11 +111,6 @@ public struct SplashCore {
}

extension SplashCore {
private func checkDeviceIDExist() -> Effect<Action> {
let deviceID = keychainClient.read(key: deviceIDKey) ?? getDeviceUUID()
return login(deviceID: deviceID)
}

private func login(deviceID: String) -> Effect<Action> {
return .run { send in
try await authService.login(
Expand Down
5 changes: 3 additions & 2 deletions Projects/Feature/SplashFeature/Sources/SplashView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ public struct SplashView: View {
guard let frame = value[backgroundFrameID] else { return }
store.width = frame.width
}
.onAppear {
store.send(.onAppear)
.dialog(dialog: $store.dialog)
.task {
await store.send(.task).finish()
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "16_null_primary.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading