Created
January 10, 2025 04:08
-
-
Save Aayush9029/1eed269a8d34873bb1e4398bdec9fb68 to your computer and use it in GitHub Desktop.
Network Monitor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // NetworkMonitorClient.swift | |
| // Notto | |
| // | |
| // Created by Aayush Pokharel on 2025-01-09. | |
| // | |
| import Dependencies | |
| import Foundation | |
| import Network | |
| public struct NetworkMonitorClient { | |
| public struct NetworkStatus: Equatable { | |
| public var isConnected: Bool | |
| public var connectionType: NWInterface.InterfaceType? | |
| public init(isConnected: Bool, connectionType: NWInterface.InterfaceType? = nil) { | |
| self.isConnected = isConnected | |
| self.connectionType = connectionType | |
| } | |
| } | |
| public var start: @Sendable () -> AsyncStream<NetworkStatus> | |
| public var stop: @Sendable () -> Void | |
| public init( | |
| start: @escaping @Sendable () -> AsyncStream<NetworkStatus>, | |
| stop: @escaping @Sendable () -> Void | |
| ) { | |
| self.start = start | |
| self.stop = stop | |
| } | |
| } | |
| // MARK: - Live Implementation | |
| extension NetworkMonitorClient: DependencyKey { | |
| public static let liveValue = NetworkMonitorClient( | |
| start: { | |
| AsyncStream { continuation in | |
| let monitor = NWPathMonitor() | |
| let queue = DispatchQueue(label: "NetworkMonitorClient") | |
| monitor.pathUpdateHandler = { path in | |
| let status = NetworkStatus( | |
| isConnected: path.status == .satisfied, | |
| connectionType: path.availableInterfaces.first?.type | |
| ) | |
| continuation.yield(status) | |
| } | |
| continuation.onTermination = { _ in | |
| monitor.cancel() | |
| } | |
| monitor.start(queue: queue) | |
| } | |
| }, | |
| stop: {} // Stop is handled by continuation.onTermination | |
| ) | |
| } | |
| // MARK: - Test Implementation | |
| extension NetworkMonitorClient: TestDependencyKey { | |
| public static let testValue = Self( | |
| start: { .finished }, | |
| stop: {} | |
| ) | |
| } | |
| // MARK: - Preview Implementation | |
| extension NetworkMonitorClient { | |
| static let previewOnline = Self( | |
| start: { | |
| AsyncStream { continuation in | |
| continuation.yield(.init(isConnected: true, connectionType: .wifi)) | |
| } | |
| }, | |
| stop: {} | |
| ) | |
| static let previewOffline = Self( | |
| start: { | |
| AsyncStream { continuation in | |
| continuation.yield(.init(isConnected: false)) | |
| } | |
| }, | |
| stop: {} | |
| ) | |
| } | |
| // MARK: - Dependency Registration | |
| public extension DependencyValues { | |
| var networkMonitor: NetworkMonitorClient { | |
| get { self[NetworkMonitorClient.self] } | |
| set { self[NetworkMonitorClient.self] = newValue } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import SwiftUI | |
| struct NetworkMonitorView: View { | |
| let viewModel: NetworkMonitorViewModel | |
| var body: some View { | |
| VStack { | |
| if let status = viewModel.networkStatus { | |
| HStack { | |
| Image(systemName: status.isConnected ? "wifi" : "wifi.slash") | |
| .foregroundColor(status.isConnected ? .green : .red) | |
| Text(status.isConnected ? "Connected" : "Offline") | |
| .foregroundColor(status.isConnected ? .primary : .red) | |
| if let connectionType = status.connectionType { | |
| Text("(\(String(describing: connectionType)))") | |
| .foregroundStyle(.secondary) | |
| } | |
| } | |
| .padding() | |
| .background(Color.gray.opacity(0.1)) | |
| .cornerRadius(8) | |
| } else { | |
| ProgressView() | |
| } | |
| } | |
| .onAppear { | |
| viewModel.startMonitoring() | |
| } | |
| .onDisappear { | |
| viewModel.stopMonitoring() | |
| } | |
| } | |
| } | |
| #Preview("WiFi Connected") { | |
| let viewModel = withDependencies { | |
| $0.networkMonitor = .previewOnline | |
| } operation: { | |
| NetworkMonitorViewModel() | |
| } | |
| NetworkMonitorView(viewModel: viewModel) | |
| } | |
| #Preview("WiFi Not Conencted") { | |
| let viewModel = withDependencies { | |
| $0.networkMonitor = .previewOffline | |
| } operation: { | |
| NetworkMonitorViewModel() | |
| } | |
| NetworkMonitorView(viewModel: viewModel) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Dependencies | |
| import SwiftUI | |
| @Observable | |
| class NetworkMonitorViewModel { | |
| @ObservationIgnored | |
| @Dependency(\.networkMonitor) var networkMonitor | |
| private var monitorTask: Task<Void, Never>? | |
| var networkStatus: NetworkMonitorClient.NetworkStatus? | |
| func startMonitoring() { | |
| monitorTask = Task { | |
| for await status in networkMonitor.start() { | |
| networkStatus = status | |
| } | |
| } | |
| } | |
| func stopMonitoring() { | |
| monitorTask?.cancel() | |
| monitorTask = nil | |
| } | |
| deinit { | |
| stopMonitoring() | |
| } | |
| } |
Author
Aayush9029
commented
Jan 10, 2025

Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment