diff --git a/apps/macos/Sources/Clawdbot/ChannelConfigForm.swift b/apps/macos/Sources/Clawdbot/ChannelConfigForm.swift index 56fdae1be..d00725be7 100644 --- a/apps/macos/Sources/Clawdbot/ChannelConfigForm.swift +++ b/apps/macos/Sources/Clawdbot/ChannelConfigForm.swift @@ -6,11 +6,11 @@ struct ConfigSchemaForm: View { let path: ConfigPath var body: some View { - self.renderNode(schema, path: path) + self.renderNode(self.schema, path: self.path) } private func renderNode(_ schema: ConfigSchemaNode, path: ConfigPath) -> AnyView { - let storedValue = store.configValue(at: path) + let storedValue = self.store.configValue(at: path) let value = storedValue ?? schema.explicitDefault let label = hintForPath(path, hints: store.configUiHints)?.label ?? schema.title let help = hintForPath(path, hints: store.configUiHints)?.help ?? schema.description @@ -21,7 +21,7 @@ struct ConfigSchemaForm: View { if nonNull.count == 1, let only = nonNull.first { return self.renderNode(only, path: path) } - let literals = nonNull.compactMap { $0.literalValue } + let literals = nonNull.compactMap(\.literalValue) if !literals.isEmpty, literals.count == nonNull.count { return AnyView( VStack(alignment: .leading, spacing: 6) { @@ -31,15 +31,20 @@ struct ConfigSchemaForm: View { .font(.caption) .foregroundStyle(.secondary) } - Picker("", selection: self.enumBinding(path, options: literals, defaultValue: schema.explicitDefault)) { + Picker( + "", + selection: self.enumBinding( + path, + options: literals, + defaultValue: schema.explicitDefault)) + { Text("Select…").tag(-1) ForEach(literals.indices, id: \ .self) { index in Text(String(describing: literals[index])).tag(index) } } .pickerStyle(.menu) - } - ) + }) } } @@ -71,8 +76,7 @@ struct ConfigSchemaForm: View { if schema.allowsAdditionalProperties { self.renderAdditionalProperties(schema, path: path, value: value) } - } - ) + }) case "array": return AnyView(self.renderArray(schema, path: path, value: value, label: label, help: help)) case "boolean": @@ -80,8 +84,7 @@ struct ConfigSchemaForm: View { Toggle(isOn: self.boolBinding(path, defaultValue: schema.explicitDefault as? Bool)) { if let label { Text(label) } else { Text("Enabled") } } - .help(help ?? "") - ) + .help(help ?? "")) case "number", "integer": return AnyView(self.renderNumberField(schema, path: path, label: label, help: help)) case "string": @@ -93,8 +96,7 @@ struct ConfigSchemaForm: View { Text("Unsupported field type.") .font(.caption) .foregroundStyle(.secondary) - } - ) + }) } } @@ -155,9 +157,7 @@ struct ConfigSchemaForm: View { text: self.numberBinding( path, isInteger: schema.schemaType == "integer", - defaultValue: defaultValue - ) - ) + defaultValue: defaultValue)) .textFieldStyle(.roundedBorder) } } @@ -189,7 +189,7 @@ struct ConfigSchemaForm: View { Button("Remove") { var next = items next.remove(at: index) - store.updateConfigValue(path: path, value: next) + self.store.updateConfigValue(path: path, value: next) } .buttonStyle(.bordered) .controlSize(.small) @@ -202,7 +202,7 @@ struct ConfigSchemaForm: View { } else { next.append("") } - store.updateConfigValue(path: path, value: next) + self.store.updateConfigValue(path: path, value: next) } .buttonStyle(.bordered) .controlSize(.small) @@ -238,7 +238,7 @@ struct ConfigSchemaForm: View { Button("Remove") { var next = dict next.removeValue(forKey: key) - store.updateConfigValue(path: path, value: next) + self.store.updateConfigValue(path: path, value: next) } .buttonStyle(.bordered) .controlSize(.small) @@ -254,7 +254,7 @@ struct ConfigSchemaForm: View { key = "new-\(index)" } next[key] = additionalSchema.defaultValue - store.updateConfigValue(path: path, value: next) + self.store.updateConfigValue(path: path, value: next) } .buttonStyle(.bordered) .controlSize(.small) @@ -270,9 +270,8 @@ struct ConfigSchemaForm: View { }, set: { newValue in let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines) - store.updateConfigValue(path: path, value: trimmed.isEmpty ? nil : trimmed) - } - ) + self.store.updateConfigValue(path: path, value: trimmed.isEmpty ? nil : trimmed) + }) } private func boolBinding(_ path: ConfigPath, defaultValue: Bool?) -> Binding { @@ -282,16 +281,15 @@ struct ConfigSchemaForm: View { return defaultValue ?? false }, set: { newValue in - store.updateConfigValue(path: path, value: newValue) - } - ) + self.store.updateConfigValue(path: path, value: newValue) + }) } private func numberBinding( _ path: ConfigPath, isInteger: Bool, - defaultValue: Double? - ) -> Binding { + defaultValue: Double?) -> Binding + { Binding( get: { if let value = store.configValue(at: path) { return String(describing: value) } @@ -301,22 +299,21 @@ struct ConfigSchemaForm: View { set: { newValue in let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines) if trimmed.isEmpty { - store.updateConfigValue(path: path, value: nil) + self.store.updateConfigValue(path: path, value: nil) } else if let value = Double(trimmed) { - store.updateConfigValue(path: path, value: isInteger ? Int(value) : value) + self.store.updateConfigValue(path: path, value: isInteger ? Int(value) : value) } - } - ) + }) } private func enumBinding( _ path: ConfigPath, options: [Any], - defaultValue: Any? - ) -> Binding { + defaultValue: Any?) -> Binding + { Binding( get: { - let value = store.configValue(at: path) ?? defaultValue + let value = self.store.configValue(at: path) ?? defaultValue guard let value else { return -1 } return options.firstIndex { option in String(describing: option) == String(describing: value) @@ -324,12 +321,11 @@ struct ConfigSchemaForm: View { }, set: { index in guard index >= 0, index < options.count else { - store.updateConfigValue(path: path, value: nil) + self.store.updateConfigValue(path: path, value: nil) return } - store.updateConfigValue(path: path, value: options[index]) - } - ) + self.store.updateConfigValue(path: path, value: options[index]) + }) } private func mapKeyBinding(path: ConfigPath, key: String) -> Binding { @@ -339,14 +335,13 @@ struct ConfigSchemaForm: View { let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return } guard trimmed != key else { return } - let current = store.configValue(at: path) as? [String: Any] ?? [:] + let current = self.store.configValue(at: path) as? [String: Any] ?? [:] guard current[trimmed] == nil else { return } var next = current next[trimmed] = current[key] next.removeValue(forKey: key) - store.updateConfigValue(path: path, value: next) - } - ) + self.store.updateConfigValue(path: path, value: next) + }) } } @@ -355,10 +350,10 @@ struct ChannelConfigForm: View { let channelId: String var body: some View { - if store.configSchemaLoading { + if self.store.configSchemaLoading { ProgressView().controlSize(.small) } else if let schema = store.channelConfigSchema(for: channelId) { - ConfigSchemaForm(store: store, schema: schema, path: [.key("channels"), .key(channelId)]) + ConfigSchemaForm(store: self.store, schema: schema, path: [.key("channels"), .key(self.channelId)]) } else { Text("Schema unavailable for this channel.") .font(.caption) diff --git a/apps/macos/Sources/Clawdbot/ChannelsSettings+ChannelState.swift b/apps/macos/Sources/Clawdbot/ChannelsSettings+ChannelState.swift index 2b1976a19..e4def6116 100644 --- a/apps/macos/Sources/Clawdbot/ChannelsSettings+ChannelState.swift +++ b/apps/macos/Sources/Clawdbot/ChannelsSettings+ChannelState.swift @@ -434,25 +434,25 @@ extension ChannelsSettings { private func resolveChannelDetailTitle(_ id: String) -> String { switch id { - case "whatsapp": return "WhatsApp Web" - case "telegram": return "Telegram Bot" - case "discord": return "Discord Bot" - case "slack": return "Slack Bot" - case "signal": return "Signal REST" - case "imessage": return "iMessage" - default: return self.resolveChannelTitle(id) + case "whatsapp": "WhatsApp Web" + case "telegram": "Telegram Bot" + case "discord": "Discord Bot" + case "slack": "Slack Bot" + case "signal": "Signal REST" + case "imessage": "iMessage" + default: self.resolveChannelTitle(id) } } private func resolveChannelSystemImage(_ id: String) -> String { switch id { - case "whatsapp": return "message" - case "telegram": return "paperplane" - case "discord": return "bubble.left.and.bubble.right" - case "slack": return "number" - case "signal": return "antenna.radiowaves.left.and.right" - case "imessage": return "message.fill" - default: return "message" + case "whatsapp": "message" + case "telegram": "paperplane" + case "discord": "bubble.left.and.bubble.right" + case "slack": "number" + case "signal": "antenna.radiowaves.left.and.right" + case "imessage": "message.fill" + default: "message" } } diff --git a/apps/macos/Sources/Clawdbot/ChannelsStore+Config.swift b/apps/macos/Sources/Clawdbot/ChannelsStore+Config.swift index 0dad50c5b..c4c73b769 100644 --- a/apps/macos/Sources/Clawdbot/ChannelsStore+Config.swift +++ b/apps/macos/Sources/Clawdbot/ChannelsStore+Config.swift @@ -57,7 +57,7 @@ extension ChannelsStore { return value } guard path.count >= 2 else { return nil } - if case .key("channels") = path[0], case .key(_) = path[1] { + if case .key("channels") = path[0], case .key = path[1] { let fallbackPath = Array(path.dropFirst()) return valueAtPath(self.configDraft, path: fallbackPath) } @@ -93,10 +93,10 @@ private func valueAtPath(_ root: Any, path: ConfigPath) -> Any? { var current: Any? = root for segment in path { switch segment { - case .key(let key): + case let .key(key): guard let dict = current as? [String: Any] else { return nil } current = dict[key] - case .index(let index): + case let .index(index): guard let array = current as? [Any], array.indices.contains(index) else { return nil } current = array[index] } @@ -107,7 +107,7 @@ private func valueAtPath(_ root: Any, path: ConfigPath) -> Any? { private func setValue(_ root: inout Any, path: ConfigPath, value: Any?) { guard let segment = path.first else { return } switch segment { - case .key(let key): + case let .key(key): var dict = root as? [String: Any] ?? [:] if path.count == 1 { if let value { @@ -122,7 +122,7 @@ private func setValue(_ root: inout Any, path: ConfigPath, value: Any?) { setValue(&child, path: Array(path.dropFirst()), value: value) dict[key] = child root = dict - case .index(let index): + case let .index(index): var array = root as? [Any] ?? [] if index >= array.count { array.append(contentsOf: repeatElement(NSNull() as Any, count: index - array.count + 1)) diff --git a/apps/macos/Sources/Clawdbot/ConfigSchemaSupport.swift b/apps/macos/Sources/Clawdbot/ConfigSchemaSupport.swift index 0f1d09545..4a7d4e0a4 100644 --- a/apps/macos/Sources/Clawdbot/ConfigSchemaSupport.swift +++ b/apps/macos/Sources/Clawdbot/ConfigSchemaSupport.swift @@ -133,7 +133,7 @@ struct ConfigSchemaNode { for segment in path { guard let node = current else { return nil } switch segment { - case .key(let key): + case let .key(key): if node.schemaType == "object" { if let next = node.properties[key] { current = next @@ -174,7 +174,7 @@ func hintForPath(_ path: ConfigPath, hints: [String: ConfigUiHint]) -> ConfigUiH var match = true for (index, seg) in segments.enumerated() { let hintSegment = hintSegments[index] - if hintSegment != "*" && hintSegment != seg { + if hintSegment != "*", hintSegment != seg { match = false break } @@ -196,7 +196,7 @@ func isSensitivePath(_ path: ConfigPath) -> Bool { func pathKey(_ path: ConfigPath) -> String { path.compactMap { segment -> String? in switch segment { - case .key(let key): return key + case let .key(key): return key case .index: return nil } } diff --git a/apps/macos/Sources/Clawdbot/ConfigSettings.swift b/apps/macos/Sources/Clawdbot/ConfigSettings.swift index 288032e5e..d6962a324 100644 --- a/apps/macos/Sources/Clawdbot/ConfigSettings.swift +++ b/apps/macos/Sources/Clawdbot/ConfigSettings.swift @@ -47,7 +47,7 @@ extension ConfigSettings { .foregroundStyle(.secondary) } } - if self.store.configDirty && !self.isNixMode { + if self.store.configDirty, !self.isNixMode { Text("Unsaved changes") .font(.caption) .foregroundStyle(.secondary)