Files

129 lines
4.8 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import SwiftUI
import TermindDomain
import struct TermindDomain.Host
/// The same host metadata form inside a desktop work column or a mobile sheet.
public struct HostOrganizationSection<GroupField: View, TagsField: View>: View {
@Binding private var host: Host
private let detectedDistribution: DetectedDistribution?
private let groupField: GroupField
private let tagsField: TagsField
public init(
host: Binding<Host>,
detectedDistribution: DetectedDistribution?,
@ViewBuilder groupField: () -> GroupField,
@ViewBuilder tagsField: () -> TagsField
) {
_host = host
self.detectedDistribution = detectedDistribution
self.groupField = groupField()
self.tagsField = tagsField()
}
public var body: some View {
Section(AppStrings.Vault.host.swiftUIKey) {
VaultNameField(text: $host.name, prompt: Text(verbatim: host.defaultName))
.disabled(host.isTailscaleManaged)
groupField.disabled(host.isTailscaleManaged)
HostIconPicker(selection: $host.iconOverrideID, detectedDistribution: detectedDistribution)
tagsField
VaultColorField(selection: $host.colorTag)
}
}
}
/// Selects the protocol profile being edited.
public struct HostProtocolProfileControls: View {
@Binding private var connectionProtocol: HostTerminalProtocol
public init(protocol connectionProtocol: Binding<HostTerminalProtocol>) {
_connectionProtocol = connectionProtocol
}
public var body: some View {
VStack(alignment: .leading, spacing: 8) {
Picker("Protocol Profile", selection: $connectionProtocol) {
ForEach([HostTerminalProtocol.ssh, .telnet]) { connectionProtocol in
Text(connectionProtocol.displayName).tag(connectionProtocol)
}
}
.labelsHidden()
.pickerStyle(.segmented)
.frame(maxWidth: .infinity)
}
}
}
/// The protocol-specific connection form inside a desktop work column or a mobile sheet.
public struct HostConnectionFields: View {
@Binding private var host: Host
private let connectionProtocol: HostTerminalProtocol
private let discover: (() -> Void)?
public init(
host: Binding<Host>, protocol connectionProtocol: HostTerminalProtocol = .ssh,
discover: (() -> Void)? = nil
) {
_host = host
self.connectionProtocol = connectionProtocol
self.discover = discover
}
public var body: some View {
Section(AppStrings.Settings.connection.swiftUIKey) {
LabeledContent(AppStrings.Vault.host.swiftUIKey) {
TextField(
AppStrings.Vault.host.swiftUIKey, text: $host.host.singleLineText,
prompt: Text("IP address or hostname"), axis: .horizontal
).singleLinePaste().lineLimit(1)
.labelsHidden().multilineTextAlignment(.trailing)
#if os(iOS)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.keyboardType(.URL)
#endif
}
Toggle(AppStrings.Common.enabled.swiftUIKey, isOn: enabled)
.toggleStyle(.switch)
if host.isEnabled(connectionProtocol) {
LabeledContent(AppStrings.Common.port.swiftUIKey) {
TextField(AppStrings.Common.port.swiftUIKey, value: port, format: .number.grouping(.never))
.lineLimit(1)
.labelsHidden().multilineTextAlignment(.trailing)
#if os(iOS)
.keyboardType(.numberPad)
#endif
}
}
if let discover, !host.isTailscaleManaged,
LocalDiscoveryProtocol(terminalProtocol: connectionProtocol) != nil
{
Button(
AppStrings.LocalNetwork.discovery.swiftUIKey, systemImage: "dot.radiowaves.left.and.right",
action: discover)
}
}
}
private var enabled: Binding<Bool> {
Binding(
get: { connectionProtocol == .ssh ? host.sshEnabled : host.telnetEnabled },
set: {
if connectionProtocol == .ssh { host.sshEnabled = $0 } else { host.telnetEnabled = $0 }
})
}
private var port: Binding<Int> {
Binding(
get: { connectionProtocol == .ssh ? host.sshPort : host.telnetPort },
set: {
if connectionProtocol == .ssh { host.sshPort = $0 } else { host.telnetPort = $0 }
})
}
}