import SwiftUI /// 设置面板:未连接时显示,用于查看本机设备 ID、配置信令服务器与连接目标。 struct SetupPanelView: View { @ObservedObject var viewModel: ControllerViewModel var body: some View { NavigationView { Form { Section("本机信息") { HStack { Text("本机设备 ID") Spacer() Text(viewModel.myDeviceId) .font(.system(.body, design: .monospaced)) .foregroundColor(.secondary) .textSelection(.enabled) } } Section("连接设置") { TextField("信令服务器地址 (wss://...)", text: $viewModel.serverUrl) .keyboardType(.URL) .autocapitalization(.none) .disableAutocorrection(true) TextField("目标设备 ID", text: $viewModel.targetDeviceId) .autocapitalization(.allCharacters) .disableAutocorrection(true) Button { viewModel.loadOnlineDevices() } label: { HStack { Text("刷新在线设备") Spacer() if viewModel.isLoadingOnlineDevices { ProgressView() } } } } if !viewModel.onlineDevices.isEmpty { Section("在线设备(点击填入目标 ID)") { ForEach(viewModel.onlineDevices) { device in Button { viewModel.targetDeviceId = device.deviceId } label: { HStack { VStack(alignment: .leading, spacing: 2) { Text(device.nickname) Text(device.deviceId) .font(.system(.caption, design: .monospaced)) .foregroundColor(.secondary) } Spacer() if viewModel.targetDeviceId == device.deviceId { Image(systemName: "checkmark") .foregroundColor(.accentColor) } } } } } } Section("配对码兑换(建立新绑定)") { HStack { TextField("输入被控端显示的配对码", text: $viewModel.pairingCode) .textInputAutocapitalization(.never) .autocorrectionDisabled() Button { viewModel.redeemPairingCode() } label: { if viewModel.isRedeemingPairing { ProgressView() } else { Text("兑换") } } .disabled(viewModel.isRedeemingPairing || viewModel.pairingCode.trimmingCharacters(in: .whitespaces).isEmpty) } Text("在被控端生成配对码后填入此处即可建立绑定,绑定成功后会出现在上方在线设备列表中。") .font(.caption) .foregroundColor(.secondary) } Section { Button { viewModel.requestConnect() } label: { HStack { Spacer() if viewModel.isConnecting { ProgressView() .padding(.trailing, 8) } Text(viewModel.isConnecting ? "连接中..." : "连接") .font(.system(size: 15, weight: .semibold)) Spacer() } } .disabled(viewModel.isConnecting) if viewModel.isConnecting { Button(role: .destructive) { viewModel.disconnect() } label: { HStack { Spacer() Text("取消") Spacer() } } } } footer: { Text(viewModel.statusText) } } .navigationTitle("WebRTC 控制端") } .navigationViewStyle(.stack) } }