Add option to disable Enhancemnent Shortcut Cmd + E
This commit is contained in:
parent
e3610c6db3
commit
4fb8bf361b
@ -49,6 +49,20 @@ class MiniRecorderShortcutManager: ObservableObject {
|
|||||||
setupEnhancementShortcut()
|
setupEnhancementShortcut()
|
||||||
setupEscapeHandlerOnce()
|
setupEscapeHandlerOnce()
|
||||||
setupCancelHandlerOnce()
|
setupCancelHandlerOnce()
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(settingsDidChange), name: .AppSettingsDidChange, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func settingsDidChange() {
|
||||||
|
Task {
|
||||||
|
if await whisperState.isMiniRecorderVisible {
|
||||||
|
if EnhancementShortcutSettings.shared.isToggleEnhancementShortcutEnabled {
|
||||||
|
KeyboardShortcuts.setShortcut(.init(.e, modifiers: .command), for: .toggleEnhancement)
|
||||||
|
} else {
|
||||||
|
removeEnhancementShortcut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupVisibilityObserver() {
|
private func setupVisibilityObserver() {
|
||||||
@ -57,7 +71,11 @@ class MiniRecorderShortcutManager: ObservableObject {
|
|||||||
if isVisible {
|
if isVisible {
|
||||||
activateEscapeShortcut()
|
activateEscapeShortcut()
|
||||||
activateCancelShortcut()
|
activateCancelShortcut()
|
||||||
|
if EnhancementShortcutSettings.shared.isToggleEnhancementShortcutEnabled {
|
||||||
KeyboardShortcuts.setShortcut(.init(.e, modifiers: .command), for: .toggleEnhancement)
|
KeyboardShortcuts.setShortcut(.init(.e, modifiers: .command), for: .toggleEnhancement)
|
||||||
|
} else {
|
||||||
|
removeEnhancementShortcut()
|
||||||
|
}
|
||||||
setupPromptShortcuts()
|
setupPromptShortcuts()
|
||||||
setupPowerModeShortcuts()
|
setupPowerModeShortcuts()
|
||||||
} else {
|
} else {
|
||||||
@ -278,6 +296,7 @@ class MiniRecorderShortcutManager: ObservableObject {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
visibilityTask?.cancel()
|
visibilityTask?.cancel()
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
deactivateEscapeShortcut()
|
deactivateEscapeShortcut()
|
||||||
deactivateCancelShortcut()
|
deactivateCancelShortcut()
|
||||||
|
|||||||
17
VoiceInk/Services/EnhancementShortcutSettings.swift
Normal file
17
VoiceInk/Services/EnhancementShortcutSettings.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class EnhancementShortcutSettings: ObservableObject {
|
||||||
|
static let shared = EnhancementShortcutSettings()
|
||||||
|
|
||||||
|
@Published var isToggleEnhancementShortcutEnabled: Bool {
|
||||||
|
didSet {
|
||||||
|
UserDefaults.standard.set(isToggleEnhancementShortcutEnabled, forKey: "isToggleEnhancementShortcutEnabled")
|
||||||
|
NotificationCenter.default.post(name: .AppSettingsDidChange, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
self.isToggleEnhancementShortcutEnabled = UserDefaults.standard.object(forKey: "isToggleEnhancementShortcutEnabled") as? Bool ?? true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,22 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import KeyboardShortcuts
|
||||||
|
|
||||||
struct EnhancementShortcutsView: View {
|
struct EnhancementShortcutsView: View {
|
||||||
private let shortcuts: [ShortcutRowData] = [
|
@ObservedObject private var shortcutSettings = EnhancementShortcutSettings.shared
|
||||||
.toggleEnhancement,
|
|
||||||
.switchPrompt
|
|
||||||
]
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
ForEach(shortcuts) { shortcut in
|
ShortcutRow(
|
||||||
ShortcutRow(data: shortcut)
|
title: "Toggle AI Enhancement",
|
||||||
}
|
description: "Quickly enable or disable enhancement while recording.",
|
||||||
|
keyDisplay: ["⌘", "E"],
|
||||||
|
isOn: $shortcutSettings.isToggleEnhancementShortcutEnabled
|
||||||
|
)
|
||||||
|
ShortcutRow(
|
||||||
|
title: "Switch Enhancement Prompt",
|
||||||
|
description: "Switch between your saved prompts without touching the UI. Use ⌘1–⌘0 to activate the corresponding prompt in the order they are saved.",
|
||||||
|
keyDisplay: ["⌘", "1 – 0"]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.background(Color.clear)
|
.background(Color.clear)
|
||||||
}
|
}
|
||||||
@ -80,54 +86,63 @@ struct EnhancementShortcutsSection: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Supporting Views
|
// MARK: - Supporting Views
|
||||||
private struct ShortcutRowData: Identifiable {
|
private struct ShortcutRow: View {
|
||||||
let id = UUID()
|
|
||||||
let title: String
|
let title: String
|
||||||
let description: String
|
let description: String
|
||||||
let keyDisplay: [String]
|
let keyDisplay: [String]
|
||||||
|
private var isOn: Binding<Bool>?
|
||||||
|
|
||||||
static let toggleEnhancement = ShortcutRowData(
|
init(title: String, description: String, keyDisplay: [String], isOn: Binding<Bool>? = nil) {
|
||||||
title: "Toggle AI Enhancement",
|
self.title = title
|
||||||
description: "Quickly enable or disable enhancement while recording.",
|
self.description = description
|
||||||
keyDisplay: ["⌘", "E"]
|
self.keyDisplay = keyDisplay
|
||||||
)
|
self.isOn = isOn
|
||||||
|
|
||||||
static let switchPrompt = ShortcutRowData(
|
|
||||||
title: "Switch Enhancement Prompt",
|
|
||||||
description: "Switch between your saved prompts without touching the UI. Use ⌘1–⌘0 to activate the corresponding prompt in the order they are saved.",
|
|
||||||
keyDisplay: ["⌘", "1 – 0"]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct ShortcutRow: View {
|
|
||||||
let data: ShortcutRowData
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 16) {
|
HStack(alignment: .center, spacing: 16) {
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
Text(data.title)
|
Text(title)
|
||||||
.font(.system(size: 14, weight: .semibold))
|
.font(.system(size: 14, weight: .semibold))
|
||||||
InfoTip(title: data.title, message: data.description, learnMoreURL: "https://tryvoiceink.com/docs/switching-enhancement-prompts")
|
InfoTip(title: title, message: description, learnMoreURL: "https://tryvoiceink.com/docs/switching-enhancement-prompts")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(minLength: 0)
|
Spacer(minLength: 0)
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
if let isOn = isOn {
|
||||||
ForEach(data.keyDisplay, id: \.self) { key in
|
keyDisplayView(isActive: isOn.wrappedValue)
|
||||||
KeyChip(label: key)
|
.onTapGesture {
|
||||||
|
withAnimation(.bouncy) {
|
||||||
|
isOn.wrappedValue.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
} else {
|
||||||
|
keyDisplayView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func keyDisplayView(isActive: Bool? = nil) -> some View {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
ForEach(keyDisplay, id: \.self) { key in
|
||||||
|
KeyChip(label: key, isActive: isActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct KeyChip: View {
|
private struct KeyChip: View {
|
||||||
let label: String
|
let label: String
|
||||||
|
var isActive: Bool? = nil
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
let active = isActive ?? true
|
||||||
|
|
||||||
Text(label)
|
Text(label)
|
||||||
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
@ -137,9 +152,11 @@ private struct KeyChip: View {
|
|||||||
.fill(Color(NSColor.controlBackgroundColor))
|
.fill(Color(NSColor.controlBackgroundColor))
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||||
.stroke(Color(NSColor.separatorColor).opacity(0.7), lineWidth: 0.8)
|
.stroke(Color(NSColor.separatorColor).opacity(active ? 0.7 : 0.3), lineWidth: 1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.shadow(color: Color(NSColor.shadowColor).opacity(0.1), radius: 4, x: 0, y: 2)
|
.foregroundColor(active ? .primary : .secondary)
|
||||||
|
.shadow(color: Color(NSColor.shadowColor).opacity(active ? 0.1 : 0), radius: 4, x: 0, y: 2)
|
||||||
|
.opacity(active ? 1.0 : 0.6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user