fix: mic permission check, Fn keycode filter, longer clipboard restore, error icon, TCC hint
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,10 +25,17 @@ final class AppModel: ObservableObject {
|
|||||||
cleaner: PassthroughCleaner(),
|
cleaner: PassthroughCleaner(),
|
||||||
inserter: TextInserter(pasteboard: SystemPasteboard(), paster: CGEventPaster())
|
inserter: TextInserter(pasteboard: SystemPasteboard(), paster: CGEventPaster())
|
||||||
)
|
)
|
||||||
controller.onStateChange = { [weak self] in self?.state = $0 }
|
controller.onStateChange = { [weak self] in
|
||||||
|
self?.state = $0
|
||||||
|
if $0 == .recording { self?.lastError = nil }
|
||||||
|
}
|
||||||
controller.onError = { [weak self] in self?.lastError = $0 }
|
controller.onError = { [weak self] in self?.lastError = $0 }
|
||||||
hotkey.onEvent = { [weak self] event in
|
hotkey.onEvent = { [weak self] event in
|
||||||
guard let self, self.modelReady else { return }
|
guard let self, self.modelReady else { return }
|
||||||
|
if event == .pressed, AVCaptureDevice.authorizationStatus(for: .audio) != .authorized {
|
||||||
|
self.lastError = "Microfoon-toegang ontbreekt"
|
||||||
|
return
|
||||||
|
}
|
||||||
Task { await self.controller.handle(event) }
|
Task { await self.controller.handle(event) }
|
||||||
}
|
}
|
||||||
Task { await start() }
|
Task { await start() }
|
||||||
@@ -46,7 +53,9 @@ final class AppModel: ObservableObject {
|
|||||||
|
|
||||||
var iconName: String {
|
var iconName: String {
|
||||||
switch state {
|
switch state {
|
||||||
case .idle: return modelReady ? "mic" : "mic.slash"
|
case .idle:
|
||||||
|
if lastError != nil { return "exclamationmark.triangle" }
|
||||||
|
return modelReady ? "mic" : "mic.slash"
|
||||||
case .recording: return "mic.fill"
|
case .recording: return "mic.fill"
|
||||||
case .transcribing, .inserting: return "waveform"
|
case .transcribing, .inserting: return "waveform"
|
||||||
}
|
}
|
||||||
@@ -75,6 +84,13 @@ final class AppModel: ObservableObject {
|
|||||||
_ = AXIsProcessTrustedWithOptions(["AXTrustedCheckOptionPrompt": true] as CFDictionary)
|
_ = AXIsProcessTrustedWithOptions(["AXTrustedCheckOptionPrompt": true] as CFDictionary)
|
||||||
}
|
}
|
||||||
retryHotkey()
|
retryHotkey()
|
||||||
|
transcriber.onProgress = { [weak self] fraction in
|
||||||
|
Task { @MainActor in
|
||||||
|
self?.modelStatus = fraction < 1
|
||||||
|
? "Model downloaden… \(Int(fraction * 100))%"
|
||||||
|
: "Model laden…"
|
||||||
|
}
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
try await transcriber.load()
|
try await transcriber.load()
|
||||||
modelReady = true
|
modelReady = true
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ public final class HotkeyMonitor {
|
|||||||
case .tapDisabledByTimeout, .tapDisabledByUserInput:
|
case .tapDisabledByTimeout, .tapDisabledByUserInput:
|
||||||
if let tap { CGEvent.tapEnable(tap: tap, enable: true) }
|
if let tap { CGEvent.tapEnable(tap: tap, enable: true) }
|
||||||
case .flagsChanged:
|
case .flagsChanged:
|
||||||
|
// .maskSecondaryFn is also set while arrows/F-keys are held; only react to the Fn key itself.
|
||||||
|
guard event.getIntegerValueField(.keyboardEventKeycode) == 63 else { return }
|
||||||
let fnDown = event.flags.contains(.maskSecondaryFn)
|
let fnDown = event.flags.contains(.maskSecondaryFn)
|
||||||
if let hotkeyEvent = tracker.process(fnDown: fnDown) {
|
if let hotkeyEvent = tracker.process(fnDown: fnDown) {
|
||||||
onEvent?(hotkeyEvent)
|
onEvent?(hotkeyEvent)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public struct TextInserter: TextInserting {
|
|||||||
public init(
|
public init(
|
||||||
pasteboard: PasteboardProviding,
|
pasteboard: PasteboardProviding,
|
||||||
paster: KeystrokePosting,
|
paster: KeystrokePosting,
|
||||||
restoreDelay: Duration = .milliseconds(150)
|
restoreDelay: Duration = .milliseconds(400)
|
||||||
) {
|
) {
|
||||||
self.pasteboard = pasteboard
|
self.pasteboard = pasteboard
|
||||||
self.paster = paster
|
self.paster = paster
|
||||||
|
|||||||
@@ -35,3 +35,4 @@ PLIST
|
|||||||
|
|
||||||
codesign --force --sign - --identifier local.sst.app "$APP"
|
codesign --force --sign - --identifier local.sst.app "$APP"
|
||||||
echo "Gebouwd: $APP"
|
echo "Gebouwd: $APP"
|
||||||
|
echo "Na een herbouw: tccutil reset Accessibility local.sst.app; tccutil reset ListenEvent local.sst.app; tccutil reset Microphone local.sst.app (en geef de rechten opnieuw)."
|
||||||
|
|||||||
Reference in New Issue
Block a user