Two SPM packages (VNCCore, VNCUI) + thin iOS app target wired via xcodegen. Builds for iPhone 17 simulator, unit tests pass. - VNCCore: SessionState, SessionController stub, Transport protocol with DirectTransport (NWConnection), DiscoveryService (Bonjour on _rfb._tcp and _workstation._tcp), SavedConnection @Model, ConnectionStore, KeychainService, ClipboardBridge - VNCUI: ConnectionListView, AddConnectionView, SessionView, FramebufferView/FramebufferUIView (UIKit CALayer), InputMapper, SettingsView; UIKit bits guarded with #if canImport(UIKit) so swift test runs on macOS - App: @main VNCApp, AppStateController state machine, RootView - RoyalVNCKit dependency pinned to main (transitive CryptoSwift constraint blocks tagged releases) - xcodegen Project.yml + README + .gitignore Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 lines
2.4 KiB
Swift
70 lines
2.4 KiB
Swift
import SwiftUI
|
|
import SwiftData
|
|
import VNCCore
|
|
|
|
public struct ConnectionListView: View {
|
|
@Environment(\.modelContext) private var modelContext
|
|
@Query(sort: \SavedConnection.displayName) private var connections: [SavedConnection]
|
|
@State private var discovery = DiscoveryService()
|
|
@State private var showingAdd = false
|
|
@State private var selectedConnection: SavedConnection?
|
|
|
|
public init() {}
|
|
|
|
public var body: some View {
|
|
NavigationStack {
|
|
List {
|
|
if !discovery.hosts.isEmpty {
|
|
Section("Discovered on this network") {
|
|
ForEach(discovery.hosts) { host in
|
|
Button {
|
|
// Phase 1: resolve host to SavedConnection draft
|
|
} label: {
|
|
Label(host.displayName, systemImage: "bonjour")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Section("Saved") {
|
|
if connections.isEmpty {
|
|
ContentUnavailableView(
|
|
"No saved connections",
|
|
systemImage: "display",
|
|
description: Text("Tap + to add a computer to connect to.")
|
|
)
|
|
} else {
|
|
ForEach(connections) { connection in
|
|
ConnectionCard(connection: connection)
|
|
.onTapGesture {
|
|
selectedConnection = connection
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.navigationTitle("Screens")
|
|
.toolbar {
|
|
ToolbarItem(placement: .primaryAction) {
|
|
Button {
|
|
showingAdd = true
|
|
} label: {
|
|
Image(systemName: "plus")
|
|
}
|
|
}
|
|
}
|
|
.sheet(isPresented: $showingAdd) {
|
|
AddConnectionView()
|
|
}
|
|
.navigationDestination(item: $selectedConnection) { connection in
|
|
SessionView(connection: connection)
|
|
}
|
|
.task {
|
|
discovery.start()
|
|
}
|
|
.onDisappear {
|
|
discovery.stop()
|
|
}
|
|
}
|
|
}
|
|
}
|