feat: Nix mode config, UX, onboarding, SwiftPM plist, docs
This commit is contained in:
@@ -8,6 +8,7 @@ struct SettingsRootView: View {
|
||||
@State private var selectedTab: SettingsTab = .general
|
||||
let updater: UpdaterProviding?
|
||||
private let isPreview = ProcessInfo.processInfo.isPreview
|
||||
private let isNixMode = ProcessInfo.processInfo.isNixMode
|
||||
|
||||
init(state: AppState, updater: UpdaterProviding?, initialTab: SettingsTab? = nil) {
|
||||
self.state = state
|
||||
@@ -16,55 +17,61 @@ struct SettingsRootView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: self.$selectedTab) {
|
||||
GeneralSettings(state: self.state)
|
||||
.tabItem { Label("General", systemImage: "gearshape") }
|
||||
.tag(SettingsTab.general)
|
||||
|
||||
ConnectionsSettings()
|
||||
.tabItem { Label("Connections", systemImage: "link") }
|
||||
.tag(SettingsTab.connections)
|
||||
|
||||
VoiceWakeSettings(state: self.state)
|
||||
.tabItem { Label("Voice Wake", systemImage: "waveform.circle") }
|
||||
.tag(SettingsTab.voiceWake)
|
||||
|
||||
ConfigSettings()
|
||||
.tabItem { Label("Config", systemImage: "slider.horizontal.3") }
|
||||
.tag(SettingsTab.config)
|
||||
|
||||
InstancesSettings()
|
||||
.tabItem { Label("Instances", systemImage: "network") }
|
||||
.tag(SettingsTab.instances)
|
||||
|
||||
SessionsSettings()
|
||||
.tabItem { Label("Sessions", systemImage: "clock.arrow.circlepath") }
|
||||
.tag(SettingsTab.sessions)
|
||||
|
||||
CronSettings()
|
||||
.tabItem { Label("Cron", systemImage: "calendar") }
|
||||
.tag(SettingsTab.cron)
|
||||
|
||||
SkillsSettings(state: self.state)
|
||||
.tabItem { Label("Skills", systemImage: "sparkles") }
|
||||
.tag(SettingsTab.skills)
|
||||
|
||||
PermissionsSettings(
|
||||
status: self.permissionMonitor.status,
|
||||
refresh: self.refreshPerms,
|
||||
showOnboarding: { OnboardingController.shared.show() })
|
||||
.tabItem { Label("Permissions", systemImage: "lock.shield") }
|
||||
.tag(SettingsTab.permissions)
|
||||
|
||||
if self.state.debugPaneEnabled {
|
||||
DebugSettings()
|
||||
.tabItem { Label("Debug", systemImage: "ant") }
|
||||
.tag(SettingsTab.debug)
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
if self.isNixMode {
|
||||
self.nixManagedBanner
|
||||
}
|
||||
|
||||
AboutSettings(updater: self.updater)
|
||||
.tabItem { Label("About", systemImage: "info.circle") }
|
||||
.tag(SettingsTab.about)
|
||||
TabView(selection: self.$selectedTab) {
|
||||
GeneralSettings(state: self.state)
|
||||
.tabItem { Label("General", systemImage: "gearshape") }
|
||||
.tag(SettingsTab.general)
|
||||
|
||||
ConnectionsSettings()
|
||||
.tabItem { Label("Connections", systemImage: "link") }
|
||||
.tag(SettingsTab.connections)
|
||||
|
||||
VoiceWakeSettings(state: self.state)
|
||||
.tabItem { Label("Voice Wake", systemImage: "waveform.circle") }
|
||||
.tag(SettingsTab.voiceWake)
|
||||
|
||||
ConfigSettings()
|
||||
.tabItem { Label("Config", systemImage: "slider.horizontal.3") }
|
||||
.tag(SettingsTab.config)
|
||||
|
||||
InstancesSettings()
|
||||
.tabItem { Label("Instances", systemImage: "network") }
|
||||
.tag(SettingsTab.instances)
|
||||
|
||||
SessionsSettings()
|
||||
.tabItem { Label("Sessions", systemImage: "clock.arrow.circlepath") }
|
||||
.tag(SettingsTab.sessions)
|
||||
|
||||
CronSettings()
|
||||
.tabItem { Label("Cron", systemImage: "calendar") }
|
||||
.tag(SettingsTab.cron)
|
||||
|
||||
SkillsSettings(state: self.state)
|
||||
.tabItem { Label("Skills", systemImage: "sparkles") }
|
||||
.tag(SettingsTab.skills)
|
||||
|
||||
PermissionsSettings(
|
||||
status: self.permissionMonitor.status,
|
||||
refresh: self.refreshPerms,
|
||||
showOnboarding: { OnboardingController.shared.show() })
|
||||
.tabItem { Label("Permissions", systemImage: "lock.shield") }
|
||||
.tag(SettingsTab.permissions)
|
||||
|
||||
if self.state.debugPaneEnabled {
|
||||
DebugSettings()
|
||||
.tabItem { Label("Debug", systemImage: "ant") }
|
||||
.tag(SettingsTab.debug)
|
||||
}
|
||||
|
||||
AboutSettings(updater: self.updater)
|
||||
.tabItem { Label("About", systemImage: "info.circle") }
|
||||
.tag(SettingsTab.about)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 28)
|
||||
.padding(.vertical, 22)
|
||||
@@ -98,6 +105,35 @@ struct SettingsRootView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var nixManagedBanner: some View {
|
||||
let configPath = ProcessInfo.processInfo.environment["CLAWDIS_CONFIG_PATH"] ?? "~/.clawdis/clawdis.json"
|
||||
let stateDir = ProcessInfo.processInfo.environment["CLAWDIS_STATE_DIR"] ?? "~/.clawdis"
|
||||
|
||||
return VStack(alignment: .leading, spacing: 6) {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "gearshape.2.fill")
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Managed by Nix")
|
||||
.font(.callout.weight(.semibold))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Config: \(configPath)")
|
||||
Text("State: \(stateDir)")
|
||||
}
|
||||
.font(.caption.monospaced())
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 10)
|
||||
.background(Color.gray.opacity(0.12))
|
||||
.cornerRadius(10)
|
||||
}
|
||||
|
||||
private func validTab(for requested: SettingsTab) -> SettingsTab {
|
||||
if requested == .debug, !self.state.debugPaneEnabled { return .general }
|
||||
return requested
|
||||
|
||||
Reference in New Issue
Block a user