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.
114 lines
3.9 KiB
Swift
114 lines
3.9 KiB
Swift
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)]
|
|
)
|
|
])
|
|
}
|
|
}
|