mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-26 15:07:39 +00:00
Shuffle settings around
This commit is contained in:
parent
31f1d625b1
commit
c16ccacf30
4 changed files with 151 additions and 171 deletions
|
|
@ -6,6 +6,8 @@ struct AdvancedSettingsView: View {
|
|||
private var debugMode = false
|
||||
@AppStorage("cleanupOnStartup")
|
||||
private var cleanupOnStartup = true
|
||||
@AppStorage("showInDock")
|
||||
private var showInDock = false
|
||||
@State private var cliInstaller = CLIInstaller()
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -70,13 +72,21 @@ struct AdvancedSettingsView: View {
|
|||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
} header: {
|
||||
Text("Advanced")
|
||||
.font(.headline)
|
||||
}
|
||||
|
||||
// Debug section
|
||||
Section {
|
||||
|
||||
// Show in Dock
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Toggle("Show in Dock", isOn: showInDockBinding)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Show VibeTunnel icon in the Dock.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("The dock icon is always displayed when the Settings dialog is visible.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
// Debug mode toggle
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Toggle("Debug mode", isOn: $debugMode)
|
||||
Text("Enable additional logging and debugging features.")
|
||||
|
|
@ -84,7 +94,7 @@ struct AdvancedSettingsView: View {
|
|||
.foregroundStyle(.secondary)
|
||||
}
|
||||
} header: {
|
||||
Text("Debug")
|
||||
Text("Advanced")
|
||||
.font(.headline)
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +106,17 @@ struct AdvancedSettingsView: View {
|
|||
cliInstaller.checkInstallationStatus()
|
||||
}
|
||||
}
|
||||
|
||||
private var showInDockBinding: Binding<Bool> {
|
||||
Binding(
|
||||
get: { showInDock },
|
||||
set: { newValue in
|
||||
showInDock = newValue
|
||||
// Don't change activation policy while settings window is open
|
||||
// The change will be applied when the settings window closes
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Terminal Preference Section
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ struct DashboardSettingsView: View {
|
|||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
PermissionsSection()
|
||||
|
||||
SecuritySection(
|
||||
passwordEnabled: $passwordEnabled,
|
||||
password: $password,
|
||||
|
|
@ -825,102 +823,3 @@ private struct NgrokErrorView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Permissions Section
|
||||
|
||||
private struct PermissionsSection: View {
|
||||
@StateObject private var appleScriptManager = AppleScriptPermissionManager.shared
|
||||
@State private var accessibilityUpdateTrigger = 0
|
||||
|
||||
private var hasAccessibilityPermission: Bool {
|
||||
// This will cause a re-read whenever accessibilityUpdateTrigger changes
|
||||
_ = accessibilityUpdateTrigger
|
||||
return AccessibilityPermissionManager.shared.hasPermission()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
// Automation permission
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Terminal Automation")
|
||||
.font(.body)
|
||||
Text("Required to launch and control terminal applications")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if appleScriptManager.hasPermission {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Granted")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.font(.caption)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 2)
|
||||
.frame(height: 22) // Match small button height
|
||||
} else {
|
||||
Button("Grant Permission") {
|
||||
appleScriptManager.requestPermission()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.controlSize(.small)
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
// Accessibility permission
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Accessibility")
|
||||
.font(.body)
|
||||
Text("Required for terminals that need keystroke input (Ghostty, Warp, Hyper)")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if hasAccessibilityPermission {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Granted")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.font(.caption)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 2)
|
||||
.frame(height: 22) // Match small button height
|
||||
} else {
|
||||
Button("Grant Permission") {
|
||||
AccessibilityPermissionManager.shared.requestPermission()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.controlSize(.small)
|
||||
}
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Permissions")
|
||||
.font(.headline)
|
||||
} footer: {
|
||||
Text("Terminal automation is required for all terminals. Accessibility is only needed for terminals that simulate keyboard input.")
|
||||
.font(.caption)
|
||||
.frame(maxWidth: .infinity)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.task {
|
||||
_ = await appleScriptManager.checkPermission()
|
||||
}
|
||||
.onReceive(Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()) { _ in
|
||||
// Force a re-render to check accessibility permission
|
||||
accessibilityUpdateTrigger += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,15 +32,12 @@ struct DebugSettingsView: View {
|
|||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
HTTPServerSection(
|
||||
ServerSection(
|
||||
isServerHealthy: isServerHealthy,
|
||||
isServerRunning: isServerRunning,
|
||||
serverPort: serverPort,
|
||||
lastError: lastError,
|
||||
toggleServer: toggleServer
|
||||
)
|
||||
|
||||
ServerConfigurationSection(
|
||||
toggleServer: toggleServer,
|
||||
serverModeString: $serverModeString,
|
||||
serverManager: serverManager
|
||||
)
|
||||
|
|
@ -269,18 +266,21 @@ struct DebugSettingsView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - HTTP Server Section
|
||||
// MARK: - Server Section
|
||||
|
||||
private struct HTTPServerSection: View {
|
||||
private struct ServerSection: View {
|
||||
let isServerHealthy: Bool
|
||||
let isServerRunning: Bool
|
||||
let serverPort: Int
|
||||
let lastError: String?
|
||||
let toggleServer: (Bool) async -> Void
|
||||
@Binding var serverModeString: String
|
||||
let serverManager: ServerManager
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
// Server Status
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
|
|
@ -323,29 +323,10 @@ private struct HTTPServerSection: View {
|
|||
.font(.caption)
|
||||
.foregroundStyle(.red)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
} header: {
|
||||
Text("HTTP Server")
|
||||
.font(.headline)
|
||||
} footer: {
|
||||
Text("The HTTP server provides REST API endpoints for terminal session management.")
|
||||
.font(.caption)
|
||||
.frame(maxWidth: .infinity)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Server Configuration Section
|
||||
|
||||
private struct ServerConfigurationSection: View {
|
||||
@Binding var serverModeString: String
|
||||
let serverManager: ServerManager
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
|
||||
Divider()
|
||||
|
||||
// Server Mode Configuration
|
||||
HStack {
|
||||
Text("Server Mode")
|
||||
Spacer()
|
||||
|
|
@ -383,11 +364,12 @@ private struct ServerConfigurationSection: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
} header: {
|
||||
Text("Server Configuration")
|
||||
Text("HTTP Server")
|
||||
.font(.headline)
|
||||
} footer: {
|
||||
Text("Choose between the built-in Swift Hummingbird server or the Rust tty-fwd binary.")
|
||||
Text("The HTTP server provides REST API endpoints for terminal session management. Choose between the built-in Swift Hummingbird server or the Rust tty-fwd binary.")
|
||||
.font(.caption)
|
||||
.frame(maxWidth: .infinity)
|
||||
.multilineTextAlignment(.center)
|
||||
|
|
@ -559,6 +541,7 @@ private struct DeveloperToolsSection: View {
|
|||
showServerConsole()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.frame(width: 120)
|
||||
}
|
||||
Text("View real-time server logs from both Hummingbird and Rust servers")
|
||||
.font(.caption)
|
||||
|
|
@ -573,6 +556,7 @@ private struct DeveloperToolsSection: View {
|
|||
openConsole()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.frame(width: 120)
|
||||
}
|
||||
Text("View all application logs in Console.app")
|
||||
.font(.caption)
|
||||
|
|
@ -587,6 +571,7 @@ private struct DeveloperToolsSection: View {
|
|||
showApplicationSupport()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.frame(width: 120)
|
||||
}
|
||||
Text("Open the application support directory")
|
||||
.font(.caption)
|
||||
|
|
@ -601,6 +586,7 @@ private struct DeveloperToolsSection: View {
|
|||
AppDelegate.showWelcomeScreen()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.frame(width: 120)
|
||||
}
|
||||
Text("Display the welcome screen again")
|
||||
.font(.caption)
|
||||
|
|
@ -616,6 +602,7 @@ private struct DeveloperToolsSection: View {
|
|||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.red)
|
||||
.frame(width: 120)
|
||||
}
|
||||
Text("Remove all stored preferences and reset to defaults")
|
||||
.font(.caption)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
/// General settings tab for basic app preferences
|
||||
struct GeneralSettingsView: View {
|
||||
|
|
@ -6,8 +7,6 @@ struct GeneralSettingsView: View {
|
|||
private var autostart = false
|
||||
@AppStorage("showNotifications")
|
||||
private var showNotifications = true
|
||||
@AppStorage("showInDock")
|
||||
private var showInDock = false
|
||||
@AppStorage("updateChannel")
|
||||
private var updateChannelRaw = UpdateChannel.stable.rawValue
|
||||
|
||||
|
|
@ -76,23 +75,8 @@ struct GeneralSettingsView: View {
|
|||
.font(.headline)
|
||||
}
|
||||
|
||||
Section {
|
||||
// Show in Dock
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Toggle("Show in Dock", isOn: showInDockBinding)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Show VibeTunnel icon in the Dock.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("The dock icon is always displayed when the Settings dialog is visible.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Appearance")
|
||||
.font(.headline)
|
||||
}
|
||||
// Permissions Section
|
||||
PermissionsSection()
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
.scrollContentBackground(.hidden)
|
||||
|
|
@ -114,17 +98,6 @@ struct GeneralSettingsView: View {
|
|||
)
|
||||
}
|
||||
|
||||
private var showInDockBinding: Binding<Bool> {
|
||||
Binding(
|
||||
get: { showInDock },
|
||||
set: { newValue in
|
||||
showInDock = newValue
|
||||
// Don't change activation policy while settings window is open
|
||||
// The change will be applied when the settings window closes
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private var updateChannelBinding: Binding<UpdateChannel> {
|
||||
Binding(
|
||||
get: { updateChannel },
|
||||
|
|
@ -151,3 +124,103 @@ struct GeneralSettingsView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Permissions Section
|
||||
|
||||
private struct PermissionsSection: View {
|
||||
@StateObject private var appleScriptManager = AppleScriptPermissionManager.shared
|
||||
@State private var accessibilityUpdateTrigger = 0
|
||||
|
||||
private var hasAccessibilityPermission: Bool {
|
||||
// This will cause a re-read whenever accessibilityUpdateTrigger changes
|
||||
_ = accessibilityUpdateTrigger
|
||||
return AccessibilityPermissionManager.shared.hasPermission()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
// Automation permission
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Terminal Automation")
|
||||
.font(.body)
|
||||
Text("Required to launch and control terminal applications")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if appleScriptManager.hasPermission {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Granted")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.font(.caption)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 2)
|
||||
.frame(height: 22) // Match small button height
|
||||
} else {
|
||||
Button("Grant Permission") {
|
||||
appleScriptManager.requestPermission()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.controlSize(.small)
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
// Accessibility permission
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Accessibility")
|
||||
.font(.body)
|
||||
Text("Required for terminals that need keystroke input (Ghostty, Warp, Hyper)")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if hasAccessibilityPermission {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Granted")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.font(.caption)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 2)
|
||||
.frame(height: 22) // Match small button height
|
||||
} else {
|
||||
Button("Grant Permission") {
|
||||
AccessibilityPermissionManager.shared.requestPermission()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.controlSize(.small)
|
||||
}
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Permissions")
|
||||
.font(.headline)
|
||||
} footer: {
|
||||
Text("Terminal automation is required for all terminals. Accessibility is only needed for terminals that simulate keyboard input.")
|
||||
.font(.caption)
|
||||
.frame(maxWidth: .infinity)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.task {
|
||||
_ = await appleScriptManager.checkPermission()
|
||||
}
|
||||
.onReceive(Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()) { _ in
|
||||
// Force a re-render to check accessibility permission
|
||||
accessibilityUpdateTrigger += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue