From 8e4a76809ce4b164b507f844ae863f583a50e5f3 Mon Sep 17 00:00:00 2001 From: Dayeon Moon <0217dayun@naver.com> Date: Mon, 4 Mar 2024 14:55:16 +0900 Subject: [PATCH] =?UTF-8?q?[feat][#29]=20network=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=B0=8F=20=EC=83=81=ED=83=9C=EB=B3=84=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DontForget.xcodeproj/project.pbxproj | 4 ++ .../Sources/Data/Network/NetworkMonitor.swift | 24 ++++++++++++ .../Detail/View/AnniversaryDetailView.swift | 2 +- .../AnniversaryDetailViewModel.swift | 5 +-- .../Application/Home/View/HomeView.swift | 37 +++++++++++++++---- 5 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 DontForget/Sources/Data/Network/NetworkMonitor.swift diff --git a/DontForget.xcodeproj/project.pbxproj b/DontForget.xcodeproj/project.pbxproj index da8542d..965d358 100644 --- a/DontForget.xcodeproj/project.pbxproj +++ b/DontForget.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ AD147F322B57FFB500561846 /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD147F312B57FFB500561846 /* AppIntent.swift */; }; AD147F342B57FFB600561846 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AD147F332B57FFB600561846 /* Assets.xcassets */; }; AD147F382B57FFB600561846 /* DontForgetWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = AD147F262B57FFB500561846 /* DontForgetWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + AD1D31F92B9589A700ECCBFD /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD1D31F82B9589A700ECCBFD /* NetworkMonitor.swift */; }; AD36D44B2B8DD37D00250705 /* DeletionRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD36D44A2B8DD37D00250705 /* DeletionRepository.swift */; }; AD36D44D2B8DD39500250705 /* DeletionInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD36D44C2B8DD39500250705 /* DeletionInterface.swift */; }; AD3B45852B68B634009529DE /* AnniversaryDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3B45842B68B634009529DE /* AnniversaryDetailView.swift */; }; @@ -152,6 +153,7 @@ AD147F312B57FFB500561846 /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = ""; }; AD147F332B57FFB600561846 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; AD147F352B57FFB600561846 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AD1D31F82B9589A700ECCBFD /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = ""; }; AD36D44A2B8DD37D00250705 /* DeletionRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletionRepository.swift; sourceTree = ""; }; AD36D44C2B8DD39500250705 /* DeletionInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletionInterface.swift; sourceTree = ""; }; AD3B45842B68B634009529DE /* AnniversaryDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnniversaryDetailView.swift; sourceTree = ""; }; @@ -251,6 +253,7 @@ children = ( 09642C3A2B649B260015220E /* EndPoint.swift */, 09642C3C2B649B2D0015220E /* APIConstant.swift */, + AD1D31F82B9589A700ECCBFD /* NetworkMonitor.swift */, ); path = Network; sourceTree = ""; @@ -756,6 +759,7 @@ 09642C462B649FD00015220E /* DTO.swift in Sources */, AD0F99332B7C523200E2A915 /* AlarmView.swift in Sources */, 09642C582B67C8730015220E /* ViewModelType.swift in Sources */, + AD1D31F92B9589A700ECCBFD /* NetworkMonitor.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DontForget/Sources/Data/Network/NetworkMonitor.swift b/DontForget/Sources/Data/Network/NetworkMonitor.swift new file mode 100644 index 0000000..ad3089d --- /dev/null +++ b/DontForget/Sources/Data/Network/NetworkMonitor.swift @@ -0,0 +1,24 @@ +// +// NetworkMonitor.swift +// DontForget +// +// Created by 제나 on 3/4/24. +// + +import Foundation +import Network + +@Observable +final class NetworkMonitor: ObservableObject { + static let shared = NetworkMonitor() + private let networkMonitor = NWPathMonitor() + private let workerQueue = DispatchQueue(label: "Monitor") + var isConnected = false + + init() { + networkMonitor.pathUpdateHandler = { path in + self.isConnected = path.status == .satisfied + } + networkMonitor.start(queue: workerQueue) + } +} diff --git a/DontForget/Sources/Presentations/Application/Detail/View/AnniversaryDetailView.swift b/DontForget/Sources/Presentations/Application/Detail/View/AnniversaryDetailView.swift index 64bb230..44dc8a9 100644 --- a/DontForget/Sources/Presentations/Application/Detail/View/AnniversaryDetailView.swift +++ b/DontForget/Sources/Presentations/Application/Detail/View/AnniversaryDetailView.swift @@ -164,7 +164,7 @@ struct AnniversaryDetailView: View { coordinateSpace: .local ) .onEnded({ value in - if value.translation.width > 200 { + if value.translation.width > 100 { withAnimation { dismiss() } diff --git a/DontForget/Sources/Presentations/Application/Detail/ViewModel/AnniversaryDetailViewModel.swift b/DontForget/Sources/Presentations/Application/Detail/ViewModel/AnniversaryDetailViewModel.swift index caa4f99..f910755 100644 --- a/DontForget/Sources/Presentations/Application/Detail/ViewModel/AnniversaryDetailViewModel.swift +++ b/DontForget/Sources/Presentations/Application/Detail/ViewModel/AnniversaryDetailViewModel.swift @@ -13,7 +13,7 @@ final class DefaultAnniversaryDetailViewModel: ViewModelType { // MARK: - Properties let anniversaryId: Int private var cancellables = Set() - @Published var state: State + @Published var state: State = .idle @Published var anniversaryDetail: AnniversaryDetailDTO? private let anniversaryDetailRepository: AnniversaryDetailRepository private let deletionRepository: DeletionRepository @@ -44,7 +44,6 @@ final class DefaultAnniversaryDetailViewModel: ViewModelType { anniversaryDetailRepository: AnniversaryDetailRepository, deletionRepository: DeletionRepository ) { - self.state = .loading self.anniversaryId = anniversaryId self.anniversaryDetailRepository = anniversaryDetailRepository self.fetchAnniversaryDetailUseCase = DefaultFetchAnniversaryDetailUseCase( @@ -82,7 +81,6 @@ final class DefaultAnniversaryDetailViewModel: ViewModelType { } catch { print("=== DEBUG: \(error)") promise(.failure(error)) - self.state = .failed("failed fetchAnniversaryDetail()") } } } @@ -90,7 +88,6 @@ final class DefaultAnniversaryDetailViewModel: ViewModelType { .sink { _ in } receiveValue: { [weak self] response in if let response = response { self?.anniversaryDetail = response.anniversaryDetail - self?.state = .success } } .store(in: &cancellables) diff --git a/DontForget/Sources/Presentations/Application/Home/View/HomeView.swift b/DontForget/Sources/Presentations/Application/Home/View/HomeView.swift index 1e4aa1b..1a696e9 100644 --- a/DontForget/Sources/Presentations/Application/Home/View/HomeView.swift +++ b/DontForget/Sources/Presentations/Application/Home/View/HomeView.swift @@ -27,6 +27,7 @@ struct HomeView: View { @State private var navigateToCreationView = false @State private var isNavigate = false @State private var id = -1 + private var networkConnected: Bool { NetworkMonitor.shared.isConnected } var body: some View { NavigationView { @@ -81,7 +82,8 @@ struct HomeView: View { } .clipShape(RoundedRectangle(cornerRadius: 32)) .onTapGesture { - if let firstAnniversaryDetail = viewModel.firstAnniversaryDetail { + if let firstAnniversaryDetail = viewModel.firstAnniversaryDetail, + networkConnected { id = firstAnniversaryDetail.anniversaryId isNavigate = true } @@ -109,9 +111,11 @@ struct HomeView: View { .simultaneousGesture( TapGesture() .onEnded({ - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - id = anniversaries[index].anniversaryId - isNavigate = true + if networkConnected { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + id = anniversaries[index].anniversaryId + isNavigate = true + } } }) ) @@ -129,10 +133,7 @@ struct HomeView: View { #endif } .offset(y: anniversaries.isEmpty ? 0 : -140) - .onAppear { - viewModel.action(.readAnniversaries) - viewModel.action(.changePushState) - } + .onAppear(perform: actionOnAppear) .id(Self.scrollTopView) } .scrollDisabled(anniversaries.isEmpty) @@ -150,6 +151,20 @@ struct HomeView: View { } } } + .onChange(of: networkConnected) { _, status in + if status { + actionOnAppear() + } + } + .toolbar { + if !networkConnected { + ToolbarItem(placement: .status) { + Text("네트워크 연결이 없어요") + .font(.pretendard(size: 15)) + .foregroundStyle(.white) + } + } + } } } } @@ -204,5 +219,11 @@ extension HomeView { isActive: $navigateToCreationView, label: { AddNewAnniversaryView() } ) + .disabled(!networkConnected) + } + + private func actionOnAppear() { + viewModel.action(.readAnniversaries) + viewModel.action(.changePushState) } }