160 lines
5.8 KiB
Swift
160 lines
5.8 KiB
Swift
import SwiftUI
|
|
|
|
struct TerminalSettingsView: View {
|
|
@ObservedObject private var settingsController = AppSettingsController.shared
|
|
@State private var sizePresets: [TerminalSizePreset] = []
|
|
|
|
var body: some View {
|
|
Form {
|
|
Section("Font") {
|
|
HStack {
|
|
Text("Font size")
|
|
Slider(value: settingsController.binding(\.terminal.fontSize), in: 8...28, step: 1)
|
|
Text("\(Int(settingsController.settings.terminal.fontSize))pt")
|
|
.monospacedDigit()
|
|
.frame(width: 50)
|
|
}
|
|
}
|
|
|
|
Section("Colors") {
|
|
Picker("Theme", selection: settingsController.binding(\.terminal.themeRawValue)) {
|
|
ForEach(TerminalTheme.allCases) { terminalTheme in
|
|
Text(terminalTheme.label).tag(terminalTheme.rawValue)
|
|
}
|
|
}
|
|
|
|
Text(settingsController.settings.terminal.theme.detail)
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
|
|
Text("Applies to normal terminal text and the ANSI palette used by tools like `ls`.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
Section("Shell") {
|
|
TextField("Shell path (empty = $SHELL)", text: settingsController.binding(\.terminal.shellPath))
|
|
.textFieldStyle(.roundedBorder)
|
|
Text("Leave empty to use your default shell ($SHELL or /bin/zsh).")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
Section("Size Presets") {
|
|
ForEach($sizePresets) { $preset in
|
|
TerminalSizePresetEditor(
|
|
preset: $preset,
|
|
currentOpenWidth: settingsController.settings.display.openWidth,
|
|
currentOpenHeight: settingsController.settings.display.openHeight,
|
|
onDelete: { deletePreset(id: preset.id) },
|
|
onApply: { applyPreset(preset) }
|
|
)
|
|
}
|
|
|
|
HStack {
|
|
Button("Add Preset") {
|
|
sizePresets.append(
|
|
TerminalSizePreset(
|
|
name: "Preset \(sizePresets.count + 1)",
|
|
width: settingsController.settings.display.openWidth,
|
|
height: settingsController.settings.display.openHeight,
|
|
hotkey: TerminalSizePresetStore.suggestedHotkey(for: sizePresets)
|
|
)
|
|
)
|
|
}
|
|
|
|
Button("Reset Presets") {
|
|
sizePresets = TerminalSizePresetStore.loadDefaults()
|
|
}
|
|
}
|
|
|
|
Text("Size preset hotkeys are active when the notch is open. Default presets use ⌘⇧1, ⌘⇧2, and ⌘⇧3.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
.formStyle(.grouped)
|
|
.onAppear {
|
|
synchronizePresetsFromSettings()
|
|
}
|
|
.onChange(of: settingsController.settings.terminal.sizePresetsJSON) { _, _ in
|
|
synchronizePresetsFromSettings()
|
|
}
|
|
.onChange(of: sizePresets) { _, newValue in
|
|
let encoded = TerminalSizePresetStore.encodePresets(newValue)
|
|
guard encoded != settingsController.settings.terminal.sizePresetsJSON else { return }
|
|
|
|
settingsController.update {
|
|
$0.terminal.sizePresetsJSON = encoded
|
|
}
|
|
}
|
|
}
|
|
|
|
private func deletePreset(id: UUID) {
|
|
sizePresets.removeAll { $0.id == id }
|
|
}
|
|
|
|
private func applyPreset(_ preset: TerminalSizePreset) {
|
|
settingsController.update {
|
|
$0.display.openWidth = preset.width
|
|
$0.display.openHeight = preset.height
|
|
}
|
|
ScreenManager.shared.applySizePreset(preset)
|
|
}
|
|
|
|
private func synchronizePresetsFromSettings() {
|
|
let decoded = TerminalSizePresetStore.decodePresets(
|
|
from: settingsController.settings.terminal.sizePresetsJSON
|
|
) ?? TerminalSizePresetStore.loadDefaults()
|
|
|
|
guard decoded != sizePresets else { return }
|
|
sizePresets = decoded
|
|
}
|
|
}
|
|
|
|
private struct TerminalSizePresetEditor: View {
|
|
@Binding var preset: TerminalSizePreset
|
|
|
|
let currentOpenWidth: Double
|
|
let currentOpenHeight: Double
|
|
let onDelete: () -> Void
|
|
let onApply: () -> Void
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 10) {
|
|
HStack {
|
|
TextField("Preset name", text: $preset.name)
|
|
.textFieldStyle(.roundedBorder)
|
|
Button(role: .destructive, action: onDelete) {
|
|
Image(systemName: "trash")
|
|
}
|
|
.buttonStyle(.borderless)
|
|
}
|
|
|
|
HStack {
|
|
Text("Width")
|
|
TextField("Width", value: $preset.width, format: .number.precision(.fractionLength(0)))
|
|
.textFieldStyle(.roundedBorder)
|
|
.frame(width: 90)
|
|
|
|
Text("Height")
|
|
TextField("Height", value: $preset.height, format: .number.precision(.fractionLength(0)))
|
|
.textFieldStyle(.roundedBorder)
|
|
.frame(width: 90)
|
|
|
|
Spacer()
|
|
|
|
Button("Use Current Size") {
|
|
preset.width = currentOpenWidth
|
|
preset.height = currentOpenHeight
|
|
}
|
|
|
|
Button("Apply", action: onApply)
|
|
}
|
|
|
|
OptionalHotkeyRecorderView(label: "Hotkey", binding: $preset.hotkey)
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
}
|