import SwiftUI struct TerminalSettingsView: View { @ObservedObject private var settingsController = AppSettingsController.shared private var sizePresetsBinding: Binding<[TerminalSizePreset]> { Binding( get: { TerminalSizePresetStore.decodePresets( from: settingsController.settings.terminal.sizePresetsJSON ) ?? TerminalSizePresetStore.loadDefaults() }, set: { newValue in settingsController.update { $0.terminal.sizePresetsJSON = TerminalSizePresetStore.encodePresets(newValue) } } ) } 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(sizePresetsBinding) { $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") { var presets = sizePresetsBinding.wrappedValue presets.append( TerminalSizePreset( name: "Preset \(presets.count + 1)", width: settingsController.settings.display.openWidth, height: settingsController.settings.display.openHeight, hotkey: TerminalSizePresetStore.suggestedHotkey(for: presets) ) ) sizePresetsBinding.wrappedValue = presets } Button("Reset Presets") { sizePresetsBinding.wrappedValue = 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) } private func deletePreset(id: UUID) { sizePresetsBinding.wrappedValue.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 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) } }