From cfbbf91068053f753b537ee1b2c2e55f36074b76 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Thu, 13 Aug 2026 13:47:17 +0200 Subject: [PATCH] Mixer kann beim Start von Onyx mitlaufen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ein Häkchen im Mixer selbst. Standardmäßig aus: der Mixer greift in den Tonweg der geregelten Programme ein, und das soll niemandem ungefragt passieren — beim ersten Start soll nichts umgeleitet werden, was der Nutzer nicht angeschaltet hat. Das Häkchen steht in beiden Zuständen: eingeschaltet, um es wieder abzuwählen, ausgeschaltet, um es gleich mit zu setzen. Sonst müsste man den Mixer erst einschalten, um sagen zu können, dass er von selbst einschalten soll. Co-Authored-By: Claude Opus 5 --- Onyx/OnyxApp.swift | 4 ++++ .../Sources/AudioProvider/AudioMixer.swift | 20 +++++++++++++++++++ .../AudioProvider/Localizable.xcstrings | 16 +++++++++++++++ .../Sources/AudioProvider/MixerView.swift | 19 ++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/Onyx/OnyxApp.swift b/Onyx/OnyxApp.swift index f42e556..b5085dc 100644 --- a/Onyx/OnyxApp.swift +++ b/Onyx/OnyxApp.swift @@ -116,6 +116,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate { self.menuBar = menuBar model.menuBar = menuBar + // Der Mixer läuft nur an, wenn das Häkchen gesetzt ist — er greift in + // den Tonweg ein, und das soll niemandem ungefragt passieren. + audioMixer.enableIfWanted() + installOnyxStatusItem() observeMenuBarPreference() requestPermissions() diff --git a/Packages/OnyxKit/Sources/AudioProvider/AudioMixer.swift b/Packages/OnyxKit/Sources/AudioProvider/AudioMixer.swift index d55cf77..200c561 100644 --- a/Packages/OnyxKit/Sources/AudioProvider/AudioMixer.swift +++ b/Packages/OnyxKit/Sources/AudioProvider/AudioMixer.swift @@ -38,10 +38,23 @@ public final class AudioMixer { /// verschwindet ein pausiertes Programm sofort aus der Liste. private var lastHeard: [String: Date] = [:] + /// Ob der Mixer beim Programmstart von selbst anläuft. + /// + /// Standardmäßig aus: der Mixer greift in den Tonweg ein, und das soll + /// niemandem ungefragt passieren. Wer ihn täglich benutzt, spart sich mit + /// dem Häkchen den Klick. + public var startsAutomatically: Bool { + didSet { + guard startsAutomatically != oldValue else { return } + defaults.set(startsAutomatically, forKey: Keys.autostart) + } + } + private enum Keys { static let volumes = "onyx.audio.volumes" static let muted = "onyx.audio.muted" static let managed = "onyx.audio.managed" + static let autostart = "onyx.audio.autostart" } public init(defaults: UserDefaults = .standard) { @@ -50,6 +63,13 @@ public final class AudioMixer { let muted = defaults.stringArray(forKey: Keys.muted) ?? [] store = VolumeStore(volumes: volumes, muted: muted) managed = Set(defaults.stringArray(forKey: Keys.managed) ?? []) + startsAutomatically = defaults.bool(forKey: Keys.autostart) + } + + /// Beim Programmstart aufrufen. Läuft nur an, wenn das Häkchen gesetzt ist. + public func enableIfWanted() { + guard startsAutomatically else { return } + enable() } // MARK: - Ein und aus diff --git a/Packages/OnyxKit/Sources/AudioProvider/Localizable.xcstrings b/Packages/OnyxKit/Sources/AudioProvider/Localizable.xcstrings index e1458a7..30cb733 100644 --- a/Packages/OnyxKit/Sources/AudioProvider/Localizable.xcstrings +++ b/Packages/OnyxKit/Sources/AudioProvider/Localizable.xcstrings @@ -20,6 +20,22 @@ } } }, + "mixer.autostart": { + "localizations": { + "de": { + "stringUnit": { + "state": "translated", + "value": "Beim Start von Onyx einschalten" + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "Turn on when Onyx starts" + } + } + } + }, "mixer.input": { "localizations": { "de": { diff --git a/Packages/OnyxKit/Sources/AudioProvider/MixerView.swift b/Packages/OnyxKit/Sources/AudioProvider/MixerView.swift index 69b7f68..51a6058 100644 --- a/Packages/OnyxKit/Sources/AudioProvider/MixerView.swift +++ b/Packages/OnyxKit/Sources/AudioProvider/MixerView.swift @@ -68,6 +68,8 @@ public struct MixerView: View { .fixedSize(horizontal: false, vertical: true) } + autostartToggle + // Der Notausschalter gehört sichtbar dazu, nicht in ein Menü: // wenn der Ton weg ist, ist das der Knopf, den man sucht. Button { mixer.disable() } label: { @@ -79,6 +81,7 @@ public struct MixerView: View { .padding(.top, 2) } else { OffState(mixer: mixer, compact: compact) + autostartToggle } } .frame(maxWidth: .infinity, alignment: .leading) @@ -86,6 +89,22 @@ public struct MixerView: View { } } +extension MixerView { + /// Das Häkchen steht in **beiden** Zuständen: eingeschaltet, um es wieder + /// abzuwählen, ausgeschaltet, um es gleich mit zu setzen. + @ViewBuilder + var autostartToggle: some View { + Toggle(isOn: Binding(get: { mixer.startsAutomatically }, + set: { mixer.startsAutomatically = $0 })) { + Text("mixer.autostart", bundle: .module) + .font(Onyx.Font.caption) + .foregroundStyle(Onyx.Color.textSecondary) + } + .toggleStyle(.checkbox) + .controlSize(.small) + } +} + /// Der ausgeschaltete Zustand erklärt, worauf man sich einlässt — in zwei /// Sätzen, nicht in einem Absatz. Wer vier Zeilen lesen muss, bevor er einen /// Regler sieht, liest sie nicht.