Add Konverter: a local-only menu bar file converter
Drag files in Finder, hold a modifier, and drop on a wheel of outputs. Conversions run entirely on-device through ImageIO, PDFKit, AVFoundation, the bundled CLI tools, and optional ffmpeg/LibreOffice. Includes a --self-test suite (41 checks) and a --convert CLI mode so the conversion matrix can be verified without the UI.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import AppKit
|
||||
import Foundation
|
||||
|
||||
/// The menu bar item: the app's only permanent UI, and the place to turn the
|
||||
/// wheel off or fall back to picking files by hand.
|
||||
final class MenuBarController: NSObject, NSMenuDelegate {
|
||||
private var statusItem: NSStatusItem?
|
||||
|
||||
func install() {
|
||||
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
if let button = item.button {
|
||||
let image = NSImage(systemSymbolName: "arrow.triangle.2.circlepath", accessibilityDescription: "Konverter")
|
||||
image?.isTemplate = true
|
||||
button.image = image
|
||||
button.setAccessibilityLabel("Konverter")
|
||||
}
|
||||
let menu = NSMenu()
|
||||
menu.delegate = self
|
||||
item.menu = menu
|
||||
statusItem = item
|
||||
rebuild(menu)
|
||||
}
|
||||
|
||||
func menuNeedsUpdate(_ menu: NSMenu) {
|
||||
rebuild(menu)
|
||||
}
|
||||
|
||||
private func rebuild(_ menu: NSMenu) {
|
||||
menu.removeAllItems()
|
||||
|
||||
let enabled = Settings.shared.enabled
|
||||
let toggle = NSMenuItem(
|
||||
title: enabled ? "Konverter Active" : "Konverter Paused",
|
||||
action: #selector(toggleEnabled),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
toggle.target = self
|
||||
toggle.state = enabled ? .on : .off
|
||||
menu.addItem(toggle)
|
||||
|
||||
menu.addItem(.separator())
|
||||
|
||||
let convert = NSMenuItem(title: "Konvert Files…", action: #selector(convertFiles), keyEquivalent: "o")
|
||||
convert.target = self
|
||||
menu.addItem(convert)
|
||||
|
||||
let jobs = NSMenuItem(title: "Show Jobs", action: #selector(showJobs), keyEquivalent: "j")
|
||||
jobs.target = self
|
||||
menu.addItem(jobs)
|
||||
|
||||
menu.addItem(.separator())
|
||||
|
||||
let settings = NSMenuItem(title: "Settings…", action: #selector(showSettings), keyEquivalent: ",")
|
||||
settings.target = self
|
||||
menu.addItem(settings)
|
||||
|
||||
let about = NSMenuItem(title: "About Konverter", action: #selector(showAbout), keyEquivalent: "")
|
||||
about.target = self
|
||||
menu.addItem(about)
|
||||
|
||||
menu.addItem(.separator())
|
||||
|
||||
let quit = NSMenuItem(title: "Quit Konverter", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
|
||||
quit.target = NSApp
|
||||
menu.addItem(quit)
|
||||
}
|
||||
|
||||
@objc private func toggleEnabled() {
|
||||
Settings.shared.enabled.toggle()
|
||||
if !Settings.shared.enabled {
|
||||
WheelController.shared.cancel()
|
||||
}
|
||||
if let menu = statusItem?.menu {
|
||||
rebuild(menu)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func convertFiles() {
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseFiles = true
|
||||
panel.canChooseDirectories = true
|
||||
panel.allowsMultipleSelection = true
|
||||
panel.prompt = "Choose"
|
||||
panel.message = "Pick files to convert, then choose an output format"
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
guard panel.runModal() == .OK, !panel.urls.isEmpty else { return }
|
||||
// Let the panel close before the menu opens over it.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
QuickMenu.show(urls: panel.urls, at: NSEvent.mouseLocation)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func showJobs() {
|
||||
JobStore.shared.panelVisible = true
|
||||
JobPanelController.shared.show()
|
||||
}
|
||||
|
||||
@objc private func showSettings() {
|
||||
PreferencesWindowController.shared.show()
|
||||
}
|
||||
|
||||
@objc private func showAbout() {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
NSApp.orderFrontStandardAboutPanel(options: [
|
||||
.applicationName: "Konverter",
|
||||
.applicationVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0",
|
||||
.credits: NSAttributedString(
|
||||
string: "Drag a file in Finder, then hold a key.\nShift converts · Command shows tools · Control shows file actions.\nEverything runs on this Mac.",
|
||||
attributes: [.font: NSFont.systemFont(ofSize: 11)]
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user