From 4ee0325d2f31ee62f66f6d0af5ff20d9dc611347 Mon Sep 17 00:00:00 2001 From: Laurent Date: Tue, 26 May 2026 21:42:50 +0200 Subject: [PATCH] feat(remote): add ConnectionSheet for discovering and connecting to hosts --- Music/Views/ConnectionSheet.swift | 65 +++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Music/Views/ConnectionSheet.swift diff --git a/Music/Views/ConnectionSheet.swift b/Music/Views/ConnectionSheet.swift new file mode 100644 index 0000000..e2c7af6 --- /dev/null +++ b/Music/Views/ConnectionSheet.swift @@ -0,0 +1,65 @@ +import SwiftUI +import Network + +struct ConnectionSheet: View { + var remoteClient: RemoteClient + @Binding var isPresented: Bool + + var body: some View { + VStack(spacing: 16) { + Text("Connect to Host") + .font(.headline) + + if let message = remoteClient.connectionState.userMessage { + HStack(spacing: 8) { + if !remoteClient.connectionState.isConnected && + remoteClient.connectionState != .disconnected { + ProgressView().controlSize(.small) + } + Text(message) + .font(.subheadline) + .foregroundStyle(.secondary) + } + } + + if case .connectionLost(let reason) = remoteClient.connectionState { + VStack(spacing: 8) { + Text(reason).font(.caption).foregroundStyle(.red) + Button("Retry") { remoteClient.startDiscovery() } + } + } + + if remoteClient.discoveredHosts.isEmpty && remoteClient.connectionState == .discovering { + VStack(spacing: 8) { + ProgressView() + Text("Looking for hosts on your network...") + .font(.caption).foregroundStyle(.secondary) + } + .frame(height: 100) + } else { + List(remoteClient.discoveredHosts, id: \.name) { host in + HStack { + Image(systemName: "desktopcomputer").foregroundStyle(.secondary) + Text(host.name) + Spacer() + Button("Connect") { remoteClient.connect(to: host) } + .buttonStyle(.borderedProminent).controlSize(.small) + } + .padding(.vertical, 4) + } + .frame(minHeight: 100, maxHeight: 200) + } + + Button("Cancel") { + remoteClient.stopDiscovery() + isPresented = false + } + .keyboardShortcut(.cancelAction) + } + .padding(20) + .frame(width: 380) + .onChange(of: remoteClient.connectionState) { _, newState in + if case .connected = newState { isPresented = false } + } + } +}