import Foundation enum ConnectField { case host, username, password, folder } enum FieldState { case idle, valid, invalid } @MainActor final class ConnectViewModel: ObservableObject { @Published var host: String @Published var username: String @Published var password: String @Published var remotePath: String @Published var selectedProtocol: NASProtocol @Published var isVerifying = false @Published var isConnected: Bool @Published var verifyError: String? = nil @Published var showFolderBrowser = false init() { if let conn = ConnectionStore.shared.savedConnection { host = conn.host username = conn.username password = conn.password remotePath = conn.remotePath selectedProtocol = conn.nasProtocol isConnected = true } else { host = "" username = "" password = "" remotePath = "/" selectedProtocol = .smb isConnected = false } } var fieldState: FieldState { isConnected ? .valid : (verifyError != nil ? .invalid : .idle) } var canConnect: Bool { !host.isEmpty && !username.isEmpty && !password.isEmpty && !isVerifying } func verify() async { let service: any NASTransferProtocol = selectedProtocol == .smb ? SMBService() : SFTPService() await verifyWith(transfer: service) } func verifyWith(transfer: any NASTransferProtocol) async { isVerifying = true isConnected = false verifyError = nil let connection = NASConnection( host: host, nasProtocol: selectedProtocol, username: username, password: password, remotePath: remotePath ) do { try await transfer.connect(to: connection.host, port: connection.port, username: connection.username, password: connection.password) transfer.disconnect() isConnected = true ConnectionStore.shared.savedConnection = connection } catch let e as BackupError { verifyError = e.errorDescription } catch { verifyError = error.localizedDescription } isVerifying = false } }