feat: add system theme toggle command

This commit is contained in:
2026-10-18 18:42:03 +02:00
parent cead6d9382
commit a68694e66b
8 changed files with 146 additions and 10 deletions
+33 -5
View File
@@ -38,6 +38,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
private var emojiPicker: EmojiPickerController?
private var notes: NotesController?
private let notesDirectory: URL?
private let toggleSystemTheme: @MainActor () async throws -> Void
private var isCommandOpen: Bool { activeCommand != nil }
private var activeCommand: Application.Command?
private var pendingPresentation: (() -> Void)?
@@ -59,12 +60,14 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
}
init(history: LaunchHistory = LaunchHistory(), uninstaller: ApplicationUninstaller = ApplicationUninstaller(),
defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general, notesDirectory: URL? = nil) {
defaults: UserDefaults = .standard, pasteboard: NSPasteboard = .general, notesDirectory: URL? = nil,
toggleSystemTheme: @escaping @MainActor () async throws -> Void = { try await SystemTheme.toggle() }) {
self.history = history
self.uninstaller = uninstaller
self.defaults = defaults
self.pasteboard = pasteboard
self.notesDirectory = notesDirectory
self.toggleSystemTheme = toggleSystemTheme
let window = LauncherPanel(
contentRect: NSRect(x: 0, y: 0, width: 750, height: 474),
styleMask: [.borderless],
@@ -145,7 +148,6 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
updateResults()
if let command {
showCommand(command)
history.recordLaunch(of: Application(command: command))
}
window?.deminiaturize(nil)
showWindow(nil)
@@ -558,11 +560,14 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
case .notes:
cell.imageView?.image = Self.notesIcon
cell.toolTip = "Write notes with Markdown and images"
case .toggleTheme:
cell.imageView?.image = NSImage(systemSymbolName: "circle.lefthalf.filled", accessibilityDescription: nil)
cell.toolTip = "Switch macOS between light and dark appearance"
default:
cell.imageView?.image = Self.translateIcon
cell.toolTip = "Translate English to Japanese"
}
cell.imageView?.contentTintColor = nil
cell.imageView?.contentTintColor = entry.command == .toggleTheme ? SunsetPalette.accent : nil
} else {
let application = results[row]
cell.textField?.stringValue = application.name
@@ -734,7 +739,6 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
guard !isLaunching, !isCommandOpen, launcherFrameBeforeReview == nil, window?.attachedSheet == nil else { return }
if let command = application.command {
showCommand(command)
history.recordLaunch(of: application)
return
}
(window as? LauncherPanel)?.resetNumberHints()
@@ -800,9 +804,28 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
return true
}
private func toggleTheme() {
actions.close(animated: false)
isLaunching = true
updateOpenButton()
Task {
do {
try await toggleSystemTheme()
history.recordLaunch(of: Application(command: .toggleTheme))
isLaunching = false
dismiss()
} catch {
isLaunching = false
let alert = NSAlert(error: error)
alert.messageText = "Couldn’t toggle system theme"
if let window { await alert.beginSheetModal(for: window) }
}
updateOpenButton()
}
}
private func showCommand(_ command: Application.Command) {
guard !isCommandOpen, let content = window?.contentView else { return }
activeCommand = command
let controller: NSViewController
let placeholder: String
let accessibilityLabel: String
@@ -841,7 +864,12 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe
controller = tool
placeholder = "Conjure Notes"
accessibilityLabel = "Conjure Notes"
case .toggleTheme:
toggleTheme()
return
}
activeCommand = command
history.recordLaunch(of: Application(command: command))
let previousQuery = searchField.stringValue
let previousPlaceholder = searchField.placeholderAttributedString
let close: () -> Void = { [weak self, weak controller] in
+28
View File
@@ -0,0 +1,28 @@
import Foundation
enum SystemTheme {
static func toggle() async throws {
try await Task.detached {
guard let script = NSAppleScript(source: """
tell application "System Events"
tell appearance preferences
set dark mode to not dark mode
end tell
end tell
""") else {
throw NSError(domain: "Conjure.SystemTheme", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Couldn’t create the system appearance script.",
])
}
var error: NSDictionary?
script.executeAndReturnError(&error)
if let error {
let code = error[NSAppleScript.errorNumber] as? Int ?? 1
let message = code == -1743
? "Allow Conjure to control System Events in System Settings → Privacy & Security → Automation, then try again."
: error[NSAppleScript.errorMessage] as? String ?? "macOS couldn’t change the system appearance."
throw NSError(domain: "Conjure.SystemTheme", code: code, userInfo: [NSLocalizedDescriptionKey: message])
}
}.value
}
}