From 6e1fb9bfafb972e2dcc30e832ed7e717d232cfa9 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 13:37:24 +0800 Subject: [PATCH 01/26] feat: add shortcut --- Easydict.xcodeproj/project.pbxproj | 28 ++ .../xcshareddata/swiftpm/Package.resolved | 257 ++++++++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 27 ++ Easydict/App/Localizable.xcstrings | 16 ++ .../NewApp/Configuration/Configuration.swift | 8 + .../View/SettingView/Tabs/GeneralTab.swift | 1 + .../Genearl/GeneralKeyHolderWrapper.swift | 115 ++++++++ .../View/Genearl/GeneralOtherSetting.swift | 50 ++++ .../View/Genearl/GeneralShortcutSetting.swift | 115 ++++++++ 9 files changed, 617 insertions(+) create mode 100644 Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift create mode 100644 Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift create mode 100644 Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 9bb89217d..c395f9b12 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -254,6 +254,9 @@ 62E2BF4B2B4082BA00E42D38 /* AliResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF482B4082BA00E42D38 /* AliResponse.swift */; }; 62E2BF4C2B4082BA00E42D38 /* AliTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF492B4082BA00E42D38 /* AliTranslateType.swift */; }; 62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ED29A12B15F1F500901F51 /* EZWrapView.m */; }; + 9627F9382B59956800B1E999 /* GeneralShortcutSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */; }; + 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */; }; + 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */; }; 9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; }; A0B65CA0F31AC8ECFB8347CC /* Pods_EasydictTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 378E73A7EA8FC8FB9C975A63 /* Pods_EasydictTests.framework */; }; B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */; }; @@ -743,6 +746,9 @@ 62ED29A12B15F1F500901F51 /* EZWrapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZWrapView.m; sourceTree = ""; }; 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Easydict.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 91E3E579C6DB88658B4BB102 /* Pods-Easydict.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.release.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.release.xcconfig"; sourceTree = ""; }; + 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralShortcutSetting.swift; sourceTree = ""; }; + 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralKeyHolderWrapper.swift; sourceTree = ""; }; + 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralOtherSetting.swift; sourceTree = ""; }; 9672D7D02B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASShortcutBinder+EZMASShortcutBinder.h"; sourceTree = ""; }; 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MASShortcutBinder+EZMASShortcutBinder.m"; sourceTree = ""; }; A230E9A2358C7FBC7FB26189 /* Pods-EasydictTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EasydictTests.debug.xcconfig"; path = "Target Support Files/Pods-EasydictTests/Pods-EasydictTests.debug.xcconfig"; sourceTree = ""; }; @@ -2074,6 +2080,7 @@ 27FE980C2B3DD749000AD654 /* Tabs */ = { isa = PBXGroup; children = ( + 9627F9332B59956800B1E999 /* View */, EAED41EA2B54A4900005FE0A /* ServiceConfiguration */, 278540332B3DE04F004E9488 /* GeneralTab.swift */, 0A057D6C2B499A000025C51D /* ServiceTab.swift */, @@ -2130,6 +2137,24 @@ name = Frameworks; sourceTree = ""; }; + 9627F9332B59956800B1E999 /* View */ = { + isa = PBXGroup; + children = ( + 9627F9342B59956800B1E999 /* Genearl */, + ); + path = View; + sourceTree = ""; + }; + 9627F9342B59956800B1E999 /* Genearl */ = { + isa = PBXGroup; + children = ( + 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */, + 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */, + 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */, + ); + path = Genearl; + sourceTree = ""; + }; 9CB57B9B45EC322A11ED8865 /* Pods */ = { isa = PBXGroup; children = ( @@ -2622,6 +2647,7 @@ 62E2BF4A2B4082BA00E42D38 /* AliService.swift in Sources */, 03B0233729231FA6001C7E63 /* MMMake.m in Sources */, 03B0232E29231FA6001C7E63 /* MMCrashSignalExceptionHandler.m in Sources */, + 9627F9382B59956800B1E999 /* GeneralShortcutSetting.swift in Sources */, 03BDA7C42A26DA280079D04F /* NSDictionary+RubyDescription.m in Sources */, 62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */, C4DD01EB2B12BA250025EE8E /* TencentResponse.swift in Sources */, @@ -2772,6 +2798,7 @@ 03B0233129231FA6001C7E63 /* MMCrash.m in Sources */, 03B0232629231FA6001C7E63 /* NSAttributedString+MM.m in Sources */, 03542A402937B3C900C34C33 /* EZOCRResult.m in Sources */, + 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */, C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */, 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */, EA9943E32B534C3300EE7B97 /* TTSServiceType.swift in Sources */, @@ -2806,6 +2833,7 @@ 03D8A6592A42A1A300D9A968 /* EZAppModel.m in Sources */, 036E7D7B293F4FC8002675DF /* EZOpenLinkButton.m in Sources */, EAED41EC2B54AA920005FE0A /* ServiceConfigurationSection.swift in Sources */, + 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */, 276742092B3DC230002A2C75 /* AboutTab.swift in Sources */, 03008B2E2941956D0062B821 /* EZURLSchemeHandler.m in Sources */, DC6D9C872B352EBC0055EFFC /* FontSizeHintView.swift in Sources */, diff --git a/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..4adaef040 --- /dev/null +++ b/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,257 @@ +{ + "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", + "version" : "1.2022062300.0" + } + }, + { + "identity" : "alamofire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Alamofire/Alamofire.git", + "state" : { + "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad", + "version" : "5.8.1" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2", + "version" : "10.18.1" + } + }, + { + "identity" : "appcenter-sdk-apple", + "kind" : "remoteSourceControl", + "location" : "https://github.com/microsoft/appcenter-sdk-apple.git", + "state" : { + "revision" : "1120c26835925f8314d035127c580bc71689c620", + "version" : "5.0.4" + } + }, + { + "identity" : "cocoalumberjack", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CocoaLumberjack/CocoaLumberjack.git", + "state" : { + "revision" : "80ada1f753b0d53d9b57c465936a7c4169375002", + "version" : "3.7.4" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift", + "state" : { + "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", + "version" : "1.8.1" + } + }, + { + "identity" : "defaults", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sindresorhus/Defaults.git", + "state" : { + "revision" : "3efef5a28ebdbbe922d4a2049493733ed14475a6", + "version" : "7.3.1" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "b880ec8ec927a838c51c12862c6222c30d7097d7", + "version" : "10.20.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "ceec9f28dea12b7cf3dabf18b5ed7621c88fd4aa", + "version" : "10.20.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117", + "version" : "9.3.0" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3", + "version" : "7.12.1" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", + "version" : "1.49.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "115f75e43851774934d695449a4836123c3246e1", + "version" : "3.2.0" + } + }, + { + "identity" : "hue", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zenangst/Hue", + "state" : { + "revision" : "b9d920cee4ba795fefb828d130744eee1e3d2feb", + "version" : "5.0.1" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", + "version" : "100.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", + "version" : "1.22.3" + } + }, + { + "identity" : "mjextension", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CoderMJLee/MJExtension", + "state" : { + "revision" : "43dce6be9c91a7034d37ed171b3e60a7bb760857", + "version" : "3.4.1" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version" : "2.30909.0" + } + }, + { + "identity" : "plcrashreporter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/microsoft/PLCrashReporter.git", + "state" : { + "revision" : "1aed8f7dc79ce8e674c61e430ef51ca3db18cea9", + "version" : "1.11.1" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", + "version" : "2.3.1" + } + }, + { + "identity" : "realm-core", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/realm-core.git", + "state" : { + "revision" : "7227d6a447821c28895daa099b6c7cd4c99d461b", + "version" : "13.25.1" + } + }, + { + "identity" : "realm-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/realm-swift.git", + "state" : { + "revision" : "836cc4b8619886f979f8961c3f592a82b0741591", + "version" : "10.45.3" + } + }, + { + "identity" : "snapkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SnapKit/SnapKit", + "state" : { + "revision" : "e74fe2a978d1216c3602b129447c7301573cc2d8", + "version" : "5.7.0" + } + }, + { + "identity" : "sparkle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sparkle-project/Sparkle", + "state" : { + "revision" : "47d3d90aee3c52b6f61d04ceae426e607df62347", + "version" : "2.5.2" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", + "version" : "1.5.3" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", + "version" : "1.25.2" + } + }, + { + "identity" : "swiftshell", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kareman/SwiftShell", + "state" : { + "revision" : "99680b2efc7c7dbcace1da0b3979d266f02e213c", + "version" : "5.1.0" + } + }, + { + "identity" : "ziparchive", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ZipArchive/ZipArchive.git", + "state" : { + "revision" : "79d4dc9729096c6ad83dd3cee2b9f354d1b4ab7b", + "version" : "2.5.5" + } + } + ], + "version" : 2 +} diff --git a/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved index 38cf97c19..ceda26fa4 100644 --- a/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Easydict.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -135,6 +135,15 @@ "version" : "100.0.0" } }, + { + "identity" : "keyholder", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Clipy/KeyHolder.git", + "state" : { + "revision" : "5da0ee06fd8709f7d812504bff1555462a3f6956", + "version" : "4.2.0" + } + }, { "identity" : "leveldb", "kind" : "remoteSourceControl", @@ -144,6 +153,15 @@ "version" : "1.22.3" } }, + { + "identity" : "magnet", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Clipy/Magnet", + "state" : { + "revision" : "26d672a031fd33eac94887b4e19aca0ab4761f45", + "version" : "3.4.0" + } + }, { "identity" : "mjextension", "kind" : "remoteSourceControl", @@ -198,6 +216,15 @@ "version" : "10.45.2" } }, + { + "identity" : "sauce", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Clipy/Sauce", + "state" : { + "revision" : "8f8fabaa8509c1a653d6c2c3c87396a4c493d876", + "version" : "2.4.0" + } + }, { "identity" : "snapkit", "kind" : "remoteSourceControl", diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 2114e3a63..c7c39dfae 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3001,6 +3001,22 @@ } } }, + "shortcut_setting" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Shortcut" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "快捷键" + } + } + } + }, "show" : { "localizations" : { "en" : { diff --git a/Easydict/NewApp/Configuration/Configuration.swift b/Easydict/NewApp/Configuration/Configuration.swift index 5777aa144..884ba7b0b 100644 --- a/Easydict/NewApp/Configuration/Configuration.swift +++ b/Easydict/NewApp/Configuration/Configuration.swift @@ -87,3 +87,11 @@ extension Defaults.Keys { static let aliAccessKeyId = Key("EZAliAccessKeyId") static let aliAccessKeySecret = Key("EZAliAccessKeySecret") } + +/// shortcut +extension Defaults.Keys { + static let selectionShortcutKey = Key("EZSelectionShortcutKey", default: Data()) + static let snipShortcutKey = Key("EZSnipShortcutKey", default: Data()) + static let inputShortcutKey = Key("EZInputShortcutKey", default: Data()) + static let screenshotOCRShortcutKey = Key("EZScreenshotOCRShortcutKey", default: Data()) +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift index 852631707..15a990542 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift @@ -13,6 +13,7 @@ import SwiftUI struct GeneralTab: View { var body: some View { Form { + ShortcutSettingView() Section { Picker("setting.general.appearance.light_dark_appearance", selection: $appearanceType) { ForEach(AppearenceType.allCases, id: \.rawValue) { option in diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift new file mode 100644 index 000000000..67431da57 --- /dev/null +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift @@ -0,0 +1,115 @@ +// +// GeneralKeyHolderWrapper.swift +// Easydict +// +// Created by Sharker on 2024/1/2. +// Copyright © 2024 izual. All rights reserved. +// + +import AppKit +import Defaults +import KeyHolder +import Magnet +import SwiftUI + +enum ShortcutType { + case inputTranslate + case snipTranslate + case selectTranslate + case silentScreenshotOcr +} + +struct GeneralKeyHolderWrapper: NSViewRepresentable { + func makeCoordinator() -> Coordinator { + .init(shortcutType: type) + } + + private var type: ShortcutType + init(shortcutType: ShortcutType) { + type = shortcutType + } + + func makeNSView(context: Context) -> some NSView { + let recordView = RecordView(frame: CGRect.zero) + recordView.tintColor = NSColor(red: 0.164, green: 0.517, blue: 0.823, alpha: 1) + recordView.delegate = context.coordinator + recordView.layer?.cornerRadius = 6.0 + recordView.layer?.masksToBounds = true + recordView.clearButtonMode = .whenRecorded + + restoreKeyCombo(context, recordView) + return recordView + } + + func updateNSView(_: NSViewType, context _: Context) {} + + private func restoreKeyCombo(_ context: Context, _ recordView: RecordView) { + var data: Data + switch type { + case .inputTranslate: + data = Defaults[.inputShortcutKey] + case .snipTranslate: + data = Defaults[.snipShortcutKey] + case .selectTranslate: + data = Defaults[.selectionShortcutKey] + case .silentScreenshotOcr: + data = Defaults[.screenshotOCRShortcutKey] + } + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } + recordView.keyCombo = keyCombo + let hotKey = HotKey(identifier: "KeyHolderExample", + keyCombo: keyCombo, + target: context.coordinator, + action: #selector(context.coordinator.hotkeyCalled)) + hotKey.register() + } +} + +extension GeneralKeyHolderWrapper { + class Coordinator: NSObject, RecordViewDelegate { + private var type: ShortcutType + init(shortcutType: ShortcutType) { + type = shortcutType + } + + func recordViewShouldBeginRecording(_: KeyHolder.RecordView) -> Bool { + true + } + + func recordView(_: KeyHolder.RecordView, canRecordKeyCombo _: Magnet.KeyCombo) -> Bool { + true + } + + func recordViewDidEndRecording(_: RecordView) {} + + func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { + storeKeyCombo(with: keyCombo) + HotKeyCenter.shared.unregisterAll() + guard let keyCombo else { return } + let hotKey = HotKey(identifier: "KeyHolderExample", + keyCombo: keyCombo, + target: self, + action: #selector(hotkeyCalled)) + hotKey.register() + } + + // shortcut + func storeKeyCombo(with keyCombo: KeyCombo?) { + let data = try? JSONEncoder().encode(keyCombo) + switch type { + case .inputTranslate: + Defaults[.inputShortcutKey] = data ?? Data() + case .snipTranslate: + Defaults[.snipShortcutKey] = data ?? Data() + case .selectTranslate: + Defaults[.selectionShortcutKey] = data ?? Data() + case .silentScreenshotOcr: + Defaults[.screenshotOCRShortcutKey] = data ?? Data() + } + } + + @objc func hotkeyCalled() { + print("HotKey called!!!!") + } + } +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift new file mode 100644 index 000000000..c3abe9498 --- /dev/null +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift @@ -0,0 +1,50 @@ +// +// GeneralOtherSetting.swift +// Easydict +// +// Created by Sharker on 2024/1/1. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +@available(macOS 13.0, *) +extension GeneralTab { + struct OtherSettingView: View { + var body: some View { + Section { + HStack { + Text("show_main_window") + Toggle(isOn: $hideMainWindow) { + Text("hide_main_window") + } + } + HStack { + Text("launch") + Toggle(isOn: $launchAtStartup) { + Text("launch_at_startup") + } + } + HStack { + Text("menu_bar_icon") + Toggle(isOn: $hideMenuBarIcon) { + Text("hide_menu_bar_icon") + } + } + HStack { + Text("beta_new_app") + Toggle(isOn: $enableBetaNewApp) { + Text("enable_beta_new_app") + } + } + } header: { + Text("other") + } + } + + @AppStorage(kHideMainWindowKey) private var hideMainWindow = false + @AppStorage(kLaunchAtStartupKey) private var launchAtStartup = false + @AppStorage(kHideMenuBarIconKey) private var hideMenuBarIcon = false + @AppStorage(kEnableBetaNewAppKey) private var enableBetaNewApp = false + } +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift new file mode 100644 index 000000000..67431da57 --- /dev/null +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift @@ -0,0 +1,115 @@ +// +// GeneralKeyHolderWrapper.swift +// Easydict +// +// Created by Sharker on 2024/1/2. +// Copyright © 2024 izual. All rights reserved. +// + +import AppKit +import Defaults +import KeyHolder +import Magnet +import SwiftUI + +enum ShortcutType { + case inputTranslate + case snipTranslate + case selectTranslate + case silentScreenshotOcr +} + +struct GeneralKeyHolderWrapper: NSViewRepresentable { + func makeCoordinator() -> Coordinator { + .init(shortcutType: type) + } + + private var type: ShortcutType + init(shortcutType: ShortcutType) { + type = shortcutType + } + + func makeNSView(context: Context) -> some NSView { + let recordView = RecordView(frame: CGRect.zero) + recordView.tintColor = NSColor(red: 0.164, green: 0.517, blue: 0.823, alpha: 1) + recordView.delegate = context.coordinator + recordView.layer?.cornerRadius = 6.0 + recordView.layer?.masksToBounds = true + recordView.clearButtonMode = .whenRecorded + + restoreKeyCombo(context, recordView) + return recordView + } + + func updateNSView(_: NSViewType, context _: Context) {} + + private func restoreKeyCombo(_ context: Context, _ recordView: RecordView) { + var data: Data + switch type { + case .inputTranslate: + data = Defaults[.inputShortcutKey] + case .snipTranslate: + data = Defaults[.snipShortcutKey] + case .selectTranslate: + data = Defaults[.selectionShortcutKey] + case .silentScreenshotOcr: + data = Defaults[.screenshotOCRShortcutKey] + } + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } + recordView.keyCombo = keyCombo + let hotKey = HotKey(identifier: "KeyHolderExample", + keyCombo: keyCombo, + target: context.coordinator, + action: #selector(context.coordinator.hotkeyCalled)) + hotKey.register() + } +} + +extension GeneralKeyHolderWrapper { + class Coordinator: NSObject, RecordViewDelegate { + private var type: ShortcutType + init(shortcutType: ShortcutType) { + type = shortcutType + } + + func recordViewShouldBeginRecording(_: KeyHolder.RecordView) -> Bool { + true + } + + func recordView(_: KeyHolder.RecordView, canRecordKeyCombo _: Magnet.KeyCombo) -> Bool { + true + } + + func recordViewDidEndRecording(_: RecordView) {} + + func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { + storeKeyCombo(with: keyCombo) + HotKeyCenter.shared.unregisterAll() + guard let keyCombo else { return } + let hotKey = HotKey(identifier: "KeyHolderExample", + keyCombo: keyCombo, + target: self, + action: #selector(hotkeyCalled)) + hotKey.register() + } + + // shortcut + func storeKeyCombo(with keyCombo: KeyCombo?) { + let data = try? JSONEncoder().encode(keyCombo) + switch type { + case .inputTranslate: + Defaults[.inputShortcutKey] = data ?? Data() + case .snipTranslate: + Defaults[.snipShortcutKey] = data ?? Data() + case .selectTranslate: + Defaults[.selectionShortcutKey] = data ?? Data() + case .silentScreenshotOcr: + Defaults[.screenshotOCRShortcutKey] = data ?? Data() + } + } + + @objc func hotkeyCalled() { + print("HotKey called!!!!") + } + } +} From 89b0144188548c9c178810b0bd0302ebd32b4995 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 13:37:40 +0800 Subject: [PATCH 02/26] feat: add shortcut --- Easydict.xcodeproj/project.pbxproj | 17 +++ .../View/Genearl/GeneralShortcutSetting.swift | 128 ++++-------------- 2 files changed, 42 insertions(+), 103 deletions(-) diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index c395f9b12..4cbd3bcbd 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -258,6 +258,7 @@ 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */; }; 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */; }; 9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; }; + 967712EA2B5B913600105E0F /* KeyHolder in Frameworks */ = {isa = PBXBuildFile; productRef = 967712E92B5B913600105E0F /* KeyHolder */; }; A0B65CA0F31AC8ECFB8347CC /* Pods_EasydictTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 378E73A7EA8FC8FB9C975A63 /* Pods_EasydictTests.framework */; }; B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */; }; C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01E82B12B3C80025EE8E /* TencentService.swift */; }; @@ -815,6 +816,7 @@ EA3B81FC2B52555C004C0E8B /* Defaults in Frameworks */, 03CF27FE2B3DA7D500E19B57 /* Realm in Frameworks */, 03A830902B4073E700112834 /* AppCenterAnalytics in Frameworks */, + 967712EA2B5B913600105E0F /* KeyHolder in Frameworks */, 03B63ABF2A86967800E155ED /* CoreServices.framework in Frameworks */, 038030972B4106800009230C /* CocoaLumberjackSwift in Frameworks */, 038EA1AA2B41169C008A6DD1 /* ZipArchive in Frameworks */, @@ -2374,6 +2376,7 @@ 038EA1A92B41169C008A6DD1 /* ZipArchive */, 038EA1AC2B41282F008A6DD1 /* MJExtension */, EA3B81FB2B52555C004C0E8B /* Defaults */, + 967712E92B5B913600105E0F /* KeyHolder */, ); productName = Bob; productReference = C99EEB182385796700FEE666 /* Easydict-debug.app */; @@ -2433,6 +2436,7 @@ 038EA1A82B41169C008A6DD1 /* XCRemoteSwiftPackageReference "ZipArchive" */, 038EA1AB2B41282F008A6DD1 /* XCRemoteSwiftPackageReference "MJExtension" */, EA3B81FA2B52555C004C0E8B /* XCRemoteSwiftPackageReference "Defaults" */, + 967712E82B5B913600105E0F /* XCRemoteSwiftPackageReference "KeyHolder" */, ); productRefGroup = C99EEB192385796700FEE666 /* Products */; projectDirPath = ""; @@ -3409,6 +3413,14 @@ minimumVersion = 5.8.1; }; }; + 967712E82B5B913600105E0F /* XCRemoteSwiftPackageReference "KeyHolder" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Clipy/KeyHolder.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.2.0; + }; + }; EA3B81FA2B52555C004C0E8B /* XCRemoteSwiftPackageReference "Defaults" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/sindresorhus/Defaults.git"; @@ -3495,6 +3507,11 @@ package = 2721E4CE2AFE920700A059AC /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; + 967712E92B5B913600105E0F /* KeyHolder */ = { + isa = XCSwiftPackageProductDependency; + package = 967712E82B5B913600105E0F /* XCRemoteSwiftPackageReference "KeyHolder" */; + productName = KeyHolder; + }; EA3B81FB2B52555C004C0E8B /* Defaults */ = { isa = XCSwiftPackageProductDependency; package = EA3B81FA2B52555C004C0E8B /* XCRemoteSwiftPackageReference "Defaults" */; diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift index 67431da57..cae4fb98b 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift @@ -1,115 +1,37 @@ // -// GeneralKeyHolderWrapper.swift +// GeneralShortcutSetting.swift // Easydict // -// Created by Sharker on 2024/1/2. +// Created by Sharker on 2024/1/1. // Copyright © 2024 izual. All rights reserved. // -import AppKit -import Defaults -import KeyHolder -import Magnet import SwiftUI -enum ShortcutType { - case inputTranslate - case snipTranslate - case selectTranslate - case silentScreenshotOcr -} - -struct GeneralKeyHolderWrapper: NSViewRepresentable { - func makeCoordinator() -> Coordinator { - .init(shortcutType: type) - } - - private var type: ShortcutType - init(shortcutType: ShortcutType) { - type = shortcutType - } - - func makeNSView(context: Context) -> some NSView { - let recordView = RecordView(frame: CGRect.zero) - recordView.tintColor = NSColor(red: 0.164, green: 0.517, blue: 0.823, alpha: 1) - recordView.delegate = context.coordinator - recordView.layer?.cornerRadius = 6.0 - recordView.layer?.masksToBounds = true - recordView.clearButtonMode = .whenRecorded - - restoreKeyCombo(context, recordView) - return recordView - } - - func updateNSView(_: NSViewType, context _: Context) {} - - private func restoreKeyCombo(_ context: Context, _ recordView: RecordView) { - var data: Data - switch type { - case .inputTranslate: - data = Defaults[.inputShortcutKey] - case .snipTranslate: - data = Defaults[.snipShortcutKey] - case .selectTranslate: - data = Defaults[.selectionShortcutKey] - case .silentScreenshotOcr: - data = Defaults[.screenshotOCRShortcutKey] - } - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } - recordView.keyCombo = keyCombo - let hotKey = HotKey(identifier: "KeyHolderExample", - keyCombo: keyCombo, - target: context.coordinator, - action: #selector(context.coordinator.hotkeyCalled)) - hotKey.register() - } -} - -extension GeneralKeyHolderWrapper { - class Coordinator: NSObject, RecordViewDelegate { - private var type: ShortcutType - init(shortcutType: ShortcutType) { - type = shortcutType - } - - func recordViewShouldBeginRecording(_: KeyHolder.RecordView) -> Bool { - true - } - - func recordView(_: KeyHolder.RecordView, canRecordKeyCombo _: Magnet.KeyCombo) -> Bool { - true - } - - func recordViewDidEndRecording(_: RecordView) {} - - func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { - storeKeyCombo(with: keyCombo) - HotKeyCenter.shared.unregisterAll() - guard let keyCombo else { return } - let hotKey = HotKey(identifier: "KeyHolderExample", - keyCombo: keyCombo, - target: self, - action: #selector(hotkeyCalled)) - hotKey.register() - } - - // shortcut - func storeKeyCombo(with keyCombo: KeyCombo?) { - let data = try? JSONEncoder().encode(keyCombo) - switch type { - case .inputTranslate: - Defaults[.inputShortcutKey] = data ?? Data() - case .snipTranslate: - Defaults[.snipShortcutKey] = data ?? Data() - case .selectTranslate: - Defaults[.selectionShortcutKey] = data ?? Data() - case .silentScreenshotOcr: - Defaults[.screenshotOCRShortcutKey] = data ?? Data() +@available(macOS 13, *) +extension GeneralTab { + struct ShortcutSettingView: View { + var body: some View { + Section { + HStack { + Text("input_translate") + GeneralKeyHolderWrapper(shortcutType: .inputTranslate).frame(width: 180, height: 24) + } + HStack { + Text("snip_translate") + GeneralKeyHolderWrapper(shortcutType: .snipTranslate).frame(width: 180, height: 24) + } + HStack { + Text("select_translate") + GeneralKeyHolderWrapper(shortcutType: .selectTranslate).frame(width: 180, height: 24) + } + HStack { + Text("silent_screenshot_ocr") + GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr).frame(width: 180, height: 24) + } + } header: { + Text("shortcut_setting") } } - - @objc func hotkeyCalled() { - print("HotKey called!!!!") - } } } From c7a524d4a82f071b855a28f1e4929399e8f1fc8d Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 16:51:53 +0800 Subject: [PATCH 03/26] feat: binding shortcut --- Easydict.xcodeproj/project.pbxproj | 20 +++ Easydict/NewApp/EasydictApp.swift | 2 + .../NewApp/Feature/Shortcut/Shortcut.swift | 140 ++++++++++++++++++ .../Genearl/GeneralKeyHolderWrapper.swift | 58 +++----- 4 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 Easydict/NewApp/Feature/Shortcut/Shortcut.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 4cbd3bcbd..41df57344 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -259,6 +259,7 @@ 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */; }; 9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; }; 967712EA2B5B913600105E0F /* KeyHolder in Frameworks */ = {isa = PBXBuildFile; productRef = 967712E92B5B913600105E0F /* KeyHolder */; }; + 967712EE2B5B943400105E0F /* Shortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967712ED2B5B943400105E0F /* Shortcut.swift */; }; A0B65CA0F31AC8ECFB8347CC /* Pods_EasydictTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 378E73A7EA8FC8FB9C975A63 /* Pods_EasydictTests.framework */; }; B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */; }; C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01E82B12B3C80025EE8E /* TencentService.swift */; }; @@ -752,6 +753,7 @@ 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralOtherSetting.swift; sourceTree = ""; }; 9672D7D02B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASShortcutBinder+EZMASShortcutBinder.h"; sourceTree = ""; }; 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MASShortcutBinder+EZMASShortcutBinder.m"; sourceTree = ""; }; + 967712ED2B5B943400105E0F /* Shortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shortcut.swift; sourceTree = ""; }; A230E9A2358C7FBC7FB26189 /* Pods-EasydictTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EasydictTests.debug.xcconfig"; path = "Target Support Files/Pods-EasydictTests/Pods-EasydictTests.debug.xcconfig"; sourceTree = ""; }; C4DD01E82B12B3C80025EE8E /* TencentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentService.swift; sourceTree = ""; }; C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentResponse.swift; sourceTree = ""; }; @@ -2049,6 +2051,7 @@ 27FE98032B3DCA9F000AD654 /* NewApp */ = { isa = PBXGroup; children = ( + 967712EB2B5B93E200105E0F /* Feature */, EA9943E12B534C2900EE7B97 /* Model */, EA9943DD2B534BAE00EE7B97 /* Utility */, EA3B81F72B52549B004C0E8B /* Configuration */, @@ -2157,6 +2160,22 @@ path = Genearl; sourceTree = ""; }; + 967712EB2B5B93E200105E0F /* Feature */ = { + isa = PBXGroup; + children = ( + 967712EC2B5B941600105E0F /* Shortcut */, + ); + path = Feature; + sourceTree = ""; + }; + 967712EC2B5B941600105E0F /* Shortcut */ = { + isa = PBXGroup; + children = ( + 967712ED2B5B943400105E0F /* Shortcut.swift */, + ); + path = Shortcut; + sourceTree = ""; + }; 9CB57B9B45EC322A11ED8865 /* Pods */ = { isa = PBXGroup; children = ( @@ -2747,6 +2766,7 @@ 03542A342936F70F00C34C33 /* EZLanguageManager.m in Sources */, 6295DE312A84D82E006145F4 /* EZBingTranslateModel.m in Sources */, 0361967B2A0037F700806370 /* NSData+EZMD5.m in Sources */, + 967712EE2B5B943400105E0F /* Shortcut.swift in Sources */, 03BFFC68295F4B87004E033E /* EZYoudaoDictModel.m in Sources */, 03247E3A296AE8EC00AFCD67 /* EZLoadingAnimationView.m in Sources */, 0396D615292CC4C3006A11D9 /* EZLocalStorage.m in Sources */, diff --git a/Easydict/NewApp/EasydictApp.swift b/Easydict/NewApp/EasydictApp.swift index c81ba83f4..1a13d67c7 100644 --- a/Easydict/NewApp/EasydictApp.swift +++ b/Easydict/NewApp/EasydictApp.swift @@ -62,6 +62,8 @@ struct EasydictApp: App { // If you want to start the updater manually, pass false to startingUpdater and call .startUpdater() later // This is where you can also pass an updater delegate if you need one updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: upadterHelper, userDriverDelegate: userDriverHelper) + + Shortcut.setupShortcut() } var body: some Scene { diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift new file mode 100644 index 000000000..d7b0b2c1f --- /dev/null +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -0,0 +1,140 @@ +// +// Shortcut.swift +// Easydict +// +// Created by Sharker on 2024/1/20. +// Copyright © 2024 izual. All rights reserved. + +import Defaults +import Foundation +import KeyHolder +import Magnet + +/// Shortcut Service +enum ShortcutType: String { + case inputTranslate = "EZInputShortcutKey" + case snipTranslate = "EZSnipShortcutKey" + case selectTranslate = "EZSelectionShortcutKey" + case silentScreenshotOcr = "EZScreenshotOCRShortcutKey" +} + +class Shortcut: NSObject { + static let shared = Shortcut() + + static func setupShortcut() { + let shortcut = Shortcut.shared + shortcut.restoreShortcut() + } + + // Make sure the class has only one instance + // Should not init or copy outside + override private init() {} + + override func copy() -> Any { + self // SingletonClass.shared + } + + override func mutableCopy() -> Any { + self // SingletonClass.shared + } + + // Optional + func reset() { + // Reset all properties to default value + } +} + +// restore shortcut +extension Shortcut { + func restoreShortcut() { + if let inputTranslateKeyCombo = restoreInputTranslate() { + bindingShortCut(keyCombo: inputTranslateKeyCombo, type: .inputTranslate) + } + if let snipShortcutKeyKeyCombo = restoreSnipShortcutKey() { + bindingShortCut(keyCombo: snipShortcutKeyKeyCombo, type: .snipTranslate) + } + if let selectionShortcutKeyCombo = restoreSelectionShortcutKey() { + bindingShortCut(keyCombo: selectionShortcutKeyCombo, type: .selectTranslate) + } + if let screenshotOCRShortcutKeyCombo = restoreScreenshotOCRShortcutKey() { + bindingShortCut(keyCombo: screenshotOCRShortcutKeyCombo, type: .silentScreenshotOcr) + } + } + + private func restoreInputTranslate() -> KeyCombo? { + let data = Defaults[.inputShortcutKey] + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } + return keyCombo + } + + private func restoreSnipShortcutKey() -> KeyCombo? { + let data = Defaults[.snipShortcutKey] + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } + return keyCombo + } + + private func restoreSelectionShortcutKey() -> KeyCombo? { + let data = Defaults[.selectionShortcutKey] + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } + return keyCombo + } + + private func restoreScreenshotOCRShortcutKey() -> KeyCombo? { + let data = Defaults[.screenshotOCRShortcutKey] + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } + return keyCombo + } +} + +// binding shortcut +extension Shortcut { + func bindingShortCut(keyCombo: KeyCombo, type: ShortcutType) { + var hotKey: HotKey + switch type { + case .inputTranslate: + hotKey = HotKey(identifier: type.rawValue, + keyCombo: keyCombo, + target: Shortcut.shared, + action: #selector(Shortcut.inputTranslate)) + case .snipTranslate: + hotKey = HotKey(identifier: type.rawValue, + keyCombo: keyCombo, + target: Shortcut.shared, + action: #selector(Shortcut.snipTranslate)) + case .selectTranslate: + hotKey = HotKey(identifier: type.rawValue, + keyCombo: keyCombo, + target: Shortcut.shared, + action: #selector(Shortcut.selectTextTranslate)) + case .silentScreenshotOcr: + hotKey = HotKey(identifier: type.rawValue, + keyCombo: keyCombo, + target: Shortcut.shared, + action: #selector(Shortcut.screenshotOCR)) + } + hotKey.register() + } +} + +// shortcut binding func +extension Shortcut { + @objc func selectTextTranslate() { + print("1") + } + + @objc func snipTranslate() { + print("2") + } + + @objc func inputTranslate() { + print("3") + } + + @objc func showMiniFloatingWindow() { + print("4") + } + + @objc func screenshotOCR() { + print("5") + } +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift index 67431da57..b6ecfa11d 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift @@ -12,13 +12,6 @@ import KeyHolder import Magnet import SwiftUI -enum ShortcutType { - case inputTranslate - case snipTranslate - case selectTranslate - case silentScreenshotOcr -} - struct GeneralKeyHolderWrapper: NSViewRepresentable { func makeCoordinator() -> Coordinator { .init(shortcutType: type) @@ -37,32 +30,11 @@ struct GeneralKeyHolderWrapper: NSViewRepresentable { recordView.layer?.masksToBounds = true recordView.clearButtonMode = .whenRecorded - restoreKeyCombo(context, recordView) + context.coordinator.restoreKeyCombo(recordView) return recordView } func updateNSView(_: NSViewType, context _: Context) {} - - private func restoreKeyCombo(_ context: Context, _ recordView: RecordView) { - var data: Data - switch type { - case .inputTranslate: - data = Defaults[.inputShortcutKey] - case .snipTranslate: - data = Defaults[.snipShortcutKey] - case .selectTranslate: - data = Defaults[.selectionShortcutKey] - case .silentScreenshotOcr: - data = Defaults[.screenshotOCRShortcutKey] - } - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } - recordView.keyCombo = keyCombo - let hotKey = HotKey(identifier: "KeyHolderExample", - keyCombo: keyCombo, - target: context.coordinator, - action: #selector(context.coordinator.hotkeyCalled)) - hotKey.register() - } } extension GeneralKeyHolderWrapper { @@ -84,13 +56,25 @@ extension GeneralKeyHolderWrapper { func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { storeKeyCombo(with: keyCombo) - HotKeyCenter.shared.unregisterAll() guard let keyCombo else { return } - let hotKey = HotKey(identifier: "KeyHolderExample", - keyCombo: keyCombo, - target: self, - action: #selector(hotkeyCalled)) - hotKey.register() + Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) + } + + func restoreKeyCombo(_ recordView: RecordView) { + var data: Data + switch type { + case .inputTranslate: + data = Defaults[.inputShortcutKey] + case .snipTranslate: + data = Defaults[.snipShortcutKey] + case .selectTranslate: + data = Defaults[.selectionShortcutKey] + case .silentScreenshotOcr: + data = Defaults[.screenshotOCRShortcutKey] + } + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } + recordView.keyCombo = keyCombo + Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) } // shortcut @@ -107,9 +91,5 @@ extension GeneralKeyHolderWrapper { Defaults[.screenshotOCRShortcutKey] = data ?? Data() } } - - @objc func hotkeyCalled() { - print("HotKey called!!!!") - } } } From ab7b30b41009b2c9a537ce3e2d871772596848ed Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 17:48:03 +0800 Subject: [PATCH 04/26] feat: shortcut in setting page --- Easydict.xcodeproj/project.pbxproj | 4 -- Easydict/App/Easydict-Bridging-Header.h | 2 + .../NewApp/Feature/Shortcut/Shortcut.swift | 12 ++--- .../View/Genearl/GeneralOtherSetting.swift | 50 ------------------- 4 files changed, 8 insertions(+), 60 deletions(-) delete mode 100644 Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 41df57344..d9f4d8bb9 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -256,7 +256,6 @@ 62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ED29A12B15F1F500901F51 /* EZWrapView.m */; }; 9627F9382B59956800B1E999 /* GeneralShortcutSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */; }; 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */; }; - 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */; }; 9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; }; 967712EA2B5B913600105E0F /* KeyHolder in Frameworks */ = {isa = PBXBuildFile; productRef = 967712E92B5B913600105E0F /* KeyHolder */; }; 967712EE2B5B943400105E0F /* Shortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967712ED2B5B943400105E0F /* Shortcut.swift */; }; @@ -750,7 +749,6 @@ 91E3E579C6DB88658B4BB102 /* Pods-Easydict.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.release.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.release.xcconfig"; sourceTree = ""; }; 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralShortcutSetting.swift; sourceTree = ""; }; 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralKeyHolderWrapper.swift; sourceTree = ""; }; - 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralOtherSetting.swift; sourceTree = ""; }; 9672D7D02B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASShortcutBinder+EZMASShortcutBinder.h"; sourceTree = ""; }; 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MASShortcutBinder+EZMASShortcutBinder.m"; sourceTree = ""; }; 967712ED2B5B943400105E0F /* Shortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shortcut.swift; sourceTree = ""; }; @@ -2155,7 +2153,6 @@ children = ( 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */, 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */, - 9627F9372B59956800B1E999 /* GeneralOtherSetting.swift */, ); path = Genearl; sourceTree = ""; @@ -2857,7 +2854,6 @@ 03D8A6592A42A1A300D9A968 /* EZAppModel.m in Sources */, 036E7D7B293F4FC8002675DF /* EZOpenLinkButton.m in Sources */, EAED41EC2B54AA920005FE0A /* ServiceConfigurationSection.swift in Sources */, - 9627F93A2B59956800B1E999 /* GeneralOtherSetting.swift in Sources */, 276742092B3DC230002A2C75 /* AboutTab.swift in Sources */, 03008B2E2941956D0062B821 /* EZURLSchemeHandler.m in Sources */, DC6D9C872B352EBC0055EFFC /* FontSizeHintView.swift in Sources */, diff --git a/Easydict/App/Easydict-Bridging-Header.h b/Easydict/App/Easydict-Bridging-Header.h index f98fcafec..67f5eec5a 100644 --- a/Easydict/App/Easydict-Bridging-Header.h +++ b/Easydict/App/Easydict-Bridging-Header.h @@ -28,3 +28,5 @@ #import "NSViewController+EZWindow.h" #import "EZOpenAIService.h" + + diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index d7b0b2c1f..1ee5df752 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -25,7 +25,7 @@ class Shortcut: NSObject { let shortcut = Shortcut.shared shortcut.restoreShortcut() } - + // Make sure the class has only one instance // Should not init or copy outside override private init() {} @@ -119,22 +119,22 @@ extension Shortcut { // shortcut binding func extension Shortcut { @objc func selectTextTranslate() { - print("1") + EZWindowManager.shared().selectTextTranslate() } @objc func snipTranslate() { - print("2") + EZWindowManager.shared().snipTranslate() } @objc func inputTranslate() { - print("3") + EZWindowManager.shared().inputTranslate() } @objc func showMiniFloatingWindow() { - print("4") + EZWindowManager.shared().showMiniFloatingWindow() } @objc func screenshotOCR() { - print("5") + EZWindowManager.shared().screenshotOCR() } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift deleted file mode 100644 index c3abe9498..000000000 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralOtherSetting.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// GeneralOtherSetting.swift -// Easydict -// -// Created by Sharker on 2024/1/1. -// Copyright © 2024 izual. All rights reserved. -// - -import SwiftUI - -@available(macOS 13.0, *) -extension GeneralTab { - struct OtherSettingView: View { - var body: some View { - Section { - HStack { - Text("show_main_window") - Toggle(isOn: $hideMainWindow) { - Text("hide_main_window") - } - } - HStack { - Text("launch") - Toggle(isOn: $launchAtStartup) { - Text("launch_at_startup") - } - } - HStack { - Text("menu_bar_icon") - Toggle(isOn: $hideMenuBarIcon) { - Text("hide_menu_bar_icon") - } - } - HStack { - Text("beta_new_app") - Toggle(isOn: $enableBetaNewApp) { - Text("enable_beta_new_app") - } - } - } header: { - Text("other") - } - } - - @AppStorage(kHideMainWindowKey) private var hideMainWindow = false - @AppStorage(kLaunchAtStartupKey) private var launchAtStartup = false - @AppStorage(kHideMenuBarIconKey) private var hideMenuBarIcon = false - @AppStorage(kEnableBetaNewAppKey) private var enableBetaNewApp = false - } -} From 6e36970b5edc1b06d336ee4697339fc36824dd7e Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 20:44:30 +0800 Subject: [PATCH 05/26] fix: move shortcut setup into appdelegate --- Easydict/App/AppDelegate.m | 1 + Easydict/NewApp/EasydictApp.swift | 2 -- Easydict/NewApp/Feature/Shortcut/Shortcut.swift | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Easydict/App/AppDelegate.m b/Easydict/App/AppDelegate.m index 8aa9e5f27..c1b5bb03b 100644 --- a/Easydict/App/AppDelegate.m +++ b/Easydict/App/AppDelegate.m @@ -39,6 +39,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { } [EZShortcut setup]; + [Shortcut setupShortcut]; [EZWindowManager.shared showMainWindowIfNedded]; diff --git a/Easydict/NewApp/EasydictApp.swift b/Easydict/NewApp/EasydictApp.swift index 1a13d67c7..c81ba83f4 100644 --- a/Easydict/NewApp/EasydictApp.swift +++ b/Easydict/NewApp/EasydictApp.swift @@ -62,8 +62,6 @@ struct EasydictApp: App { // If you want to start the updater manually, pass false to startingUpdater and call .startUpdater() later // This is where you can also pass an updater delegate if you need one updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: upadterHelper, userDriverDelegate: userDriverHelper) - - Shortcut.setupShortcut() } var body: some Scene { diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index 1ee5df752..e7230441b 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -21,7 +21,7 @@ enum ShortcutType: String { class Shortcut: NSObject { static let shared = Shortcut() - static func setupShortcut() { + @objc static func setupShortcut() { let shortcut = Shortcut.shared shortcut.restoreShortcut() } From 7a802e6db5a7ecff0cb5f52066a0ec599f98ad7f Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 20 Jan 2024 21:27:41 +0800 Subject: [PATCH 06/26] feat: add show mini window --- Easydict/NewApp/Configuration/Configuration.swift | 9 +++++---- Easydict/NewApp/Feature/Shortcut/Shortcut.swift | 6 ++++++ .../Tabs/View/Genearl/GeneralKeyHolderWrapper.swift | 4 ++++ .../Tabs/View/Genearl/GeneralShortcutSetting.swift | 4 ++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Easydict/NewApp/Configuration/Configuration.swift b/Easydict/NewApp/Configuration/Configuration.swift index 884ba7b0b..dfc6b9b2c 100644 --- a/Easydict/NewApp/Configuration/Configuration.swift +++ b/Easydict/NewApp/Configuration/Configuration.swift @@ -90,8 +90,9 @@ extension Defaults.Keys { /// shortcut extension Defaults.Keys { - static let selectionShortcutKey = Key("EZSelectionShortcutKey", default: Data()) - static let snipShortcutKey = Key("EZSnipShortcutKey", default: Data()) - static let inputShortcutKey = Key("EZInputShortcutKey", default: Data()) - static let screenshotOCRShortcutKey = Key("EZScreenshotOCRShortcutKey", default: Data()) + static let selectionShortcutKey = Key("EZSelectionShortcutKey_keyHolder", default: Data()) + static let snipShortcutKey = Key("EZSnipShortcutKey_keyHolder", default: Data()) + static let inputShortcutKey = Key("EZInputShortcutKey_keyHolder", default: Data()) + static let screenshotOCRShortcutKey = Key("EZScreenshotOCRShortcutKey_keyHolder", default: Data()) + static let showMiniWindowShortcutKey = Key("EZShowMiniShortcutKey_keyHolder", default: Data()) } diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index e7230441b..c863712af 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -16,6 +16,7 @@ enum ShortcutType: String { case snipTranslate = "EZSnipShortcutKey" case selectTranslate = "EZSelectionShortcutKey" case silentScreenshotOcr = "EZScreenshotOCRShortcutKey" + case showMiniWindow = "EZShowMiniShortcutKey" } class Shortcut: NSObject { @@ -111,6 +112,11 @@ extension Shortcut { keyCombo: keyCombo, target: Shortcut.shared, action: #selector(Shortcut.screenshotOCR)) + case .showMiniWindow: + hotKey = HotKey(identifier: type.rawValue, + keyCombo: keyCombo, + target: Shortcut.shared, + action: #selector(Shortcut.showMiniFloatingWindow)) } hotKey.register() } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift index b6ecfa11d..9774d9e4f 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift @@ -71,6 +71,8 @@ extension GeneralKeyHolderWrapper { data = Defaults[.selectionShortcutKey] case .silentScreenshotOcr: data = Defaults[.screenshotOCRShortcutKey] + case .showMiniWindow: + data = Defaults[.showMiniWindowShortcutKey] } guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } recordView.keyCombo = keyCombo @@ -89,6 +91,8 @@ extension GeneralKeyHolderWrapper { Defaults[.selectionShortcutKey] = data ?? Data() case .silentScreenshotOcr: Defaults[.screenshotOCRShortcutKey] = data ?? Data() + case .showMiniWindow: + Defaults[.showMiniWindowShortcutKey] = data ?? Data() } } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift index cae4fb98b..99f627849 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift @@ -25,6 +25,10 @@ extension GeneralTab { Text("select_translate") GeneralKeyHolderWrapper(shortcutType: .selectTranslate).frame(width: 180, height: 24) } + HStack { + Text("show_mini_window") + GeneralKeyHolderWrapper(shortcutType: .showMiniWindow).frame(width: 180, height: 24) + } HStack { Text("silent_screenshot_ocr") GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr).frame(width: 180, height: 24) From 4afb37f1156743628c1470ba81f997439c48936a Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sun, 21 Jan 2024 00:31:15 +0800 Subject: [PATCH 07/26] chore: try add shortcut in menu item --- .../NewApp/Feature/Shortcut/Shortcut.swift | 60 +++++++++++++++++++ Easydict/NewApp/View/MenuItemView.swift | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index c863712af..bea6d7d30 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -60,6 +60,9 @@ extension Shortcut { if let screenshotOCRShortcutKeyCombo = restoreScreenshotOCRShortcutKey() { bindingShortCut(keyCombo: screenshotOCRShortcutKeyCombo, type: .silentScreenshotOcr) } + if let showMiniWindowShortcutKeyCombo = restoreShowMiniWindow() { + bindingShortCut(keyCombo: showMiniWindowShortcutKeyCombo, type: .showMiniWindow) + } } private func restoreInputTranslate() -> KeyCombo? { @@ -85,6 +88,12 @@ extension Shortcut { guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } return keyCombo } + + private func restoreShowMiniWindow() -> KeyCombo? { + let data = Defaults[.showMiniWindowShortcutKey] + guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } + return keyCombo + } } // binding shortcut @@ -144,3 +153,54 @@ extension Shortcut { EZWindowManager.shared().screenshotOCR() } } + +// fetch shortcut string +extension Shortcut { + // can't using keyEquivalent and EventModifiers in SwiftUI MenuItemView direct, because item + // keyboardShortcut not support double modifier key + +// func fetchShortcutKeyEquivalent(_ type: ShortcutType) -> String { +// guard let keyCombo = fetchShortcutKeyCombo(type) else { return "" } +// return keyCombo.keyEquivalent +// } +// +// func fetchShortcutKeyEventModifiers(_ type: ShortcutType) -> EventModifiers { +// guard let keyCombo = fetchShortcutKeyCombo(type) else { return [] } +// return [.command, .command] +// } + + func fetchShortcutKeyStr(_: ShortcutType) -> String { + guard let keyCombo = restoreInputTranslate() else { return "" } + return shortcutKeyStr(keyCombo) + } + + private func shortcutKeyCombo(_ type: ShortcutType) -> KeyCombo? { + switch type { + case .inputTranslate: + guard let keyCombo = restoreInputTranslate() else { return nil } + return keyCombo + case .snipTranslate: + guard let keyCombo = restoreSnipShortcutKey() else { return nil } + return keyCombo + case .selectTranslate: + guard let keyCombo = restoreSelectionShortcutKey() else { return nil } + return keyCombo + case .silentScreenshotOcr: + guard let keyCombo = restoreScreenshotOCRShortcutKey() else { return nil } + return keyCombo + case .showMiniWindow: + guard let keyCombo = restoreShowMiniWindow() else { return nil } + return keyCombo + } + } + + private func shortcutKeyStr(_ keyCombo: KeyCombo) -> String { + var shortcut = "" + if keyCombo.doubledModifiers { + shortcut = keyCombo.keyEquivalentModifierMaskString + keyCombo.keyEquivalentModifierMaskString + } else { + shortcut = keyCombo.keyEquivalentModifierMaskString + keyCombo.keyEquivalent + } + return shortcut + } +} diff --git a/Easydict/NewApp/View/MenuItemView.swift b/Easydict/NewApp/View/MenuItemView.swift index 5f25919b1..7730b5438 100644 --- a/Easydict/NewApp/View/MenuItemView.swift +++ b/Easydict/NewApp/View/MenuItemView.swift @@ -35,7 +35,7 @@ struct MenuItemView: View { Group { versionItem Divider() - inputItem + inputItem.keyboardShortcut(/*@START_MENU_TOKEN@*/ .defaultAction/*@END_MENU_TOKEN@*/) screenshotItem selectWordItem miniWindowItem From 8fe2167a871fcd3d18b79cc5c26ddc3d95723e36 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sun, 21 Jan 2024 00:36:51 +0800 Subject: [PATCH 08/26] chore: remove unuse code --- Easydict/NewApp/View/MenuItemView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Easydict/NewApp/View/MenuItemView.swift b/Easydict/NewApp/View/MenuItemView.swift index 7730b5438..5f25919b1 100644 --- a/Easydict/NewApp/View/MenuItemView.swift +++ b/Easydict/NewApp/View/MenuItemView.swift @@ -35,7 +35,7 @@ struct MenuItemView: View { Group { versionItem Divider() - inputItem.keyboardShortcut(/*@START_MENU_TOKEN@*/ .defaultAction/*@END_MENU_TOKEN@*/) + inputItem screenshotItem selectWordItem miniWindowItem From 72f8ed385fd32cf1d2d4c6b1e928e8d5dcb5a891 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sun, 21 Jan 2024 16:55:11 +0800 Subject: [PATCH 09/26] chore: add menu shortcut --- Easydict/NewApp/View/MenuItemView.swift | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Easydict/NewApp/View/MenuItemView.swift b/Easydict/NewApp/View/MenuItemView.swift index 5f25919b1..b98485b9f 100644 --- a/Easydict/NewApp/View/MenuItemView.swift +++ b/Easydict/NewApp/View/MenuItemView.swift @@ -104,14 +104,17 @@ struct MenuItemView: View { @ViewBuilder private var inputItem: some View { - Button { - NSLog("输入翻译") - EZWindowManager.shared().inputTranslate() - } label: { - HStack { - Image(systemName: "keyboard") - Text("menu_input_translate") + HStack { + Button { + NSLog("输入翻译") + EZWindowManager.shared().inputTranslate() + } label: { + HStack { + Image(systemName: "keyboard") + Text("menu_input_translate") + } } + Text(Shortcut.shared.fetchShortcutKeyStr(.inputTranslate)) } } From 3540c79d6a8b8d563d3aa184115fa0b5ff279a2a Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 21 Jan 2024 17:55:27 +0800 Subject: [PATCH 10/26] fix: use old shortcut key cuase crash in new settings --- Easydict/App/AppDelegate.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Easydict/App/AppDelegate.m b/Easydict/App/AppDelegate.m index c1b5bb03b..25f88cc8f 100644 --- a/Easydict/App/AppDelegate.m +++ b/Easydict/App/AppDelegate.m @@ -36,10 +36,10 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { if (!EasydictNewAppManager.shared.enable) { [EZMenuItemManager.shared setup]; + [EZShortcut setup]; + } else { + [Shortcut setupShortcut]; } - - [EZShortcut setup]; - [Shortcut setupShortcut]; [EZWindowManager.shared showMainWindowIfNedded]; From c9a4cd58250d6da067ecfcaadd9f864914bcc3a2 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sun, 21 Jan 2024 20:20:33 +0800 Subject: [PATCH 11/26] feat: add shortcut tab page --- Easydict.xcodeproj/project.pbxproj | 4 ++++ .../View/SettingView/Tabs/ShortcutTab.swift | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index fcf9e51f1..d63cc2771 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -256,6 +256,7 @@ 62E2BF4B2B4082BA00E42D38 /* AliResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF482B4082BA00E42D38 /* AliResponse.swift */; }; 62E2BF4C2B4082BA00E42D38 /* AliTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF492B4082BA00E42D38 /* AliTranslateType.swift */; }; 62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ED29A12B15F1F500901F51 /* EZWrapView.m */; }; + 96099AE22B5D40330055C4DD /* ShortcutTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96099AE12B5D40330055C4DD /* ShortcutTab.swift */; }; 9627F9382B59956800B1E999 /* GeneralShortcutSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */; }; 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */; }; 9672D7D22B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9672D7D12B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.m */; }; @@ -751,6 +752,7 @@ 62ED29A12B15F1F500901F51 /* EZWrapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZWrapView.m; sourceTree = ""; }; 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Easydict.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 91E3E579C6DB88658B4BB102 /* Pods-Easydict.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.release.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.release.xcconfig"; sourceTree = ""; }; + 96099AE12B5D40330055C4DD /* ShortcutTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutTab.swift; sourceTree = ""; }; 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralShortcutSetting.swift; sourceTree = ""; }; 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralKeyHolderWrapper.swift; sourceTree = ""; }; 9672D7D02B4008B40023B8FB /* MASShortcutBinder+EZMASShortcutBinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MASShortcutBinder+EZMASShortcutBinder.h"; sourceTree = ""; }; @@ -2103,6 +2105,7 @@ 0A8685C72B552A590022534F /* DisabledAppTab.swift */, 276742042B3DC230002A2C75 /* PrivacyTab.swift */, 276742052B3DC230002A2C75 /* AboutTab.swift */, + 96099AE12B5D40330055C4DD /* ShortcutTab.swift */, ); path = Tabs; sourceTree = ""; @@ -2736,6 +2739,7 @@ 03882F8F29D95044005B5A52 /* CTScreen.m in Sources */, 27FE980B2B3DD5D1000AD654 /* MenuItemView.swift in Sources */, 03DC7C6A2A3CA852000BF7C9 /* EZAppCell.m in Sources */, + 96099AE22B5D40330055C4DD /* ShortcutTab.swift in Sources */, 0399C6AC29A860AA00B4AFCC /* EZOpenAIService.m in Sources */, 03542A432937B45E00C34C33 /* EZBaiduTranslate.m in Sources */, 03BB2DEB29F57DC000447EDD /* NSImage+EZSymbolmage.m in Sources */, diff --git a/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift new file mode 100644 index 000000000..d18125c37 --- /dev/null +++ b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift @@ -0,0 +1,21 @@ +// +// ShortcutTab.swift +// Easydict +// +// Created by Sharker on 2024/1/21. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +@available(macOS 13, *) +struct ShortcutTab: View { + var body: some View { + Text("xx") + } +} + +@available(macOS 13, *) +#Preview { + ShortcutTab() +} From 17e264ba7082dd1e7d5599bfd4ee095269a5fa32 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sun, 21 Jan 2024 23:10:34 +0800 Subject: [PATCH 12/26] feat: add shortcut into menu item --- .../NewApp/Feature/Shortcut/Shortcut.swift | 64 +++++++++++-------- Easydict/NewApp/View/MenuItemView.swift | 22 ++++--- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index bea6d7d30..e693da16f 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -9,9 +9,10 @@ import Defaults import Foundation import KeyHolder import Magnet +import SwiftUI /// Shortcut Service -enum ShortcutType: String { +public enum ShortcutType: String { case inputTranslate = "EZInputShortcutKey" case snipTranslate = "EZSnipShortcutKey" case selectTranslate = "EZSelectionShortcutKey" @@ -154,27 +155,9 @@ extension Shortcut { } } -// fetch shortcut string +// fetch shortcut KeyCombo extension Shortcut { - // can't using keyEquivalent and EventModifiers in SwiftUI MenuItemView direct, because item - // keyboardShortcut not support double modifier key - -// func fetchShortcutKeyEquivalent(_ type: ShortcutType) -> String { -// guard let keyCombo = fetchShortcutKeyCombo(type) else { return "" } -// return keyCombo.keyEquivalent -// } -// -// func fetchShortcutKeyEventModifiers(_ type: ShortcutType) -> EventModifiers { -// guard let keyCombo = fetchShortcutKeyCombo(type) else { return [] } -// return [.command, .command] -// } - - func fetchShortcutKeyStr(_: ShortcutType) -> String { - guard let keyCombo = restoreInputTranslate() else { return "" } - return shortcutKeyStr(keyCombo) - } - - private func shortcutKeyCombo(_ type: ShortcutType) -> KeyCombo? { + public func shortcutKeyCombo(_ type: ShortcutType) -> KeyCombo? { switch type { case .inputTranslate: guard let keyCombo = restoreInputTranslate() else { return nil } @@ -193,14 +176,43 @@ extension Shortcut { return keyCombo } } +} + +/// can't using keyEquivalent and EventModifiers in SwiftUI MenuItemView direct, because item +/// keyboardShortcut not support double modifier key but can use ⌥ as character +extension View { + public func keyboardShortcut(_ type: ShortcutType) -> some View { + guard let keyCombo = Shortcut.shared.shortcutKeyCombo(type) else { return AnyView(self) } + return AnyView(keyboardShortcut(fetchShortcutKeyEquivalent(keyCombo), modifiers: fetchShortcutKeyEventModifiers(keyCombo))) + } - private func shortcutKeyStr(_ keyCombo: KeyCombo) -> String { - var shortcut = "" + private func fetchShortcutKeyEquivalent(_ keyCombo: KeyCombo) -> KeyEquivalent { if keyCombo.doubledModifiers { - shortcut = keyCombo.keyEquivalentModifierMaskString + keyCombo.keyEquivalentModifierMaskString + return KeyEquivalent(Character(keyCombo.keyEquivalentModifierMaskString)) } else { - shortcut = keyCombo.keyEquivalentModifierMaskString + keyCombo.keyEquivalent + return KeyEquivalent(Character(keyCombo.keyEquivalent)) } - return shortcut + } + + private func fetchShortcutKeyEventModifiers(_ keyCombo: KeyCombo) -> EventModifiers { + var modifiers: EventModifiers = [] + + if keyCombo.keyEquivalentModifierMask.contains(NSEvent.ModifierFlags.command) { + modifiers.update(with: EventModifiers.command) + } + + if keyCombo.keyEquivalentModifierMask.contains(NSEvent.ModifierFlags.control) { + modifiers.update(with: EventModifiers.control) + } + + if keyCombo.keyEquivalentModifierMask.contains(NSEvent.ModifierFlags.option) { + modifiers.update(with: EventModifiers.option) + } + + if keyCombo.keyEquivalentModifierMask.contains(NSEvent.ModifierFlags.shift) { + modifiers.update(with: EventModifiers.shift) + } + + return modifiers } } diff --git a/Easydict/NewApp/View/MenuItemView.swift b/Easydict/NewApp/View/MenuItemView.swift index b98485b9f..7895de528 100644 --- a/Easydict/NewApp/View/MenuItemView.swift +++ b/Easydict/NewApp/View/MenuItemView.swift @@ -36,11 +36,16 @@ struct MenuItemView: View { versionItem Divider() inputItem + .keyboardShortcut(.inputTranslate) screenshotItem + .keyboardShortcut(.snipTranslate) selectWordItem + .keyboardShortcut(.selectTranslate) miniWindowItem + .keyboardShortcut(.showMiniWindow) Divider() ocrItem + .keyboardShortcut(.silentScreenshotOcr) Divider() settingItem .keyboardShortcut(.init(",")) @@ -104,17 +109,14 @@ struct MenuItemView: View { @ViewBuilder private var inputItem: some View { - HStack { - Button { - NSLog("输入翻译") - EZWindowManager.shared().inputTranslate() - } label: { - HStack { - Image(systemName: "keyboard") - Text("menu_input_translate") - } + Button { + NSLog("输入翻译") + EZWindowManager.shared().inputTranslate() + } label: { + HStack { + Image(systemName: "keyboard") + Text("menu_input_translate") } - Text(Shortcut.shared.fetchShortcutKeyStr(.inputTranslate)) } } From f693368c56c1bfc99d08490e92c5bba23bc2fb8c Mon Sep 17 00:00:00 2001 From: Lava <34743145+CanglongCl@users.noreply.github.com> Date: Sun, 21 Jan 2024 13:16:54 -0800 Subject: [PATCH 13/26] fix: unable to delete shortcut & menubar shortcut update & refactor using defaults bridge --- Easydict.xcodeproj/project.pbxproj | 12 +++ Easydict/App/Localizable.xcstrings | 3 + .../NewApp/Configuration/Configuration.swift | 11 +- .../NewApp/Feature/Shortcut/Shortcut.swift | 101 ++++++++++-------- .../KeyCombo+Defaults.Serializable.swift | 31 ++++++ .../Genearl/GeneralKeyHolderWrapper.swift | 25 ++--- 6 files changed, 117 insertions(+), 66 deletions(-) create mode 100644 Easydict/NewApp/Utility/Extensions/Defaults/KeyCombo+Defaults.Serializable.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index d63cc2771..2da67b0ef 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -272,6 +272,7 @@ DC3C643F2B187119008EEDD8 /* ChangeFontSizeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3C643E2B187119008EEDD8 /* ChangeFontSizeView.swift */; }; DC6D9C872B352EBC0055EFFC /* FontSizeHintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6D9C862B352EBC0055EFFC /* FontSizeHintView.swift */; }; DC6D9C892B3969510055EFFC /* Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6D9C882B3969510055EFFC /* Appearance.swift */; }; + EA1013442B5DBDB1005E43F9 /* KeyCombo+Defaults.Serializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1013432B5DBDB1005E43F9 /* KeyCombo+Defaults.Serializable.swift */; }; EA3B81F92B5254AA004C0E8B /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B81F82B5254AA004C0E8B /* Configuration.swift */; }; EA3B81FC2B52555C004C0E8B /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = EA3B81FB2B52555C004C0E8B /* Defaults */; }; EA9943E32B534C3300EE7B97 /* TTSServiceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9943E22B534C3300EE7B97 /* TTSServiceType.swift */; }; @@ -769,6 +770,7 @@ DC3C643E2B187119008EEDD8 /* ChangeFontSizeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeFontSizeView.swift; sourceTree = ""; }; DC6D9C862B352EBC0055EFFC /* FontSizeHintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeHintView.swift; sourceTree = ""; }; DC6D9C882B3969510055EFFC /* Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Appearance.swift; sourceTree = ""; }; + EA1013432B5DBDB1005E43F9 /* KeyCombo+Defaults.Serializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyCombo+Defaults.Serializable.swift"; sourceTree = ""; }; EA3B81F82B5254AA004C0E8B /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; EA9943E22B534C3300EE7B97 /* TTSServiceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TTSServiceType.swift; sourceTree = ""; }; EA9943E72B534D8900EE7B97 /* LanguageDetectOptimizeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageDetectOptimizeExtensions.swift; sourceTree = ""; }; @@ -2256,6 +2258,14 @@ path = ChangeFontSizeView; sourceTree = ""; }; + EA1013412B5DBDA5005E43F9 /* Defaults */ = { + isa = PBXGroup; + children = ( + EA1013432B5DBDB1005E43F9 /* KeyCombo+Defaults.Serializable.swift */, + ); + path = Defaults; + sourceTree = ""; + }; EA3B81F72B52549B004C0E8B /* Configuration */ = { isa = PBXGroup; children = ( @@ -2284,6 +2294,7 @@ EA9943E62B534D7C00EE7B97 /* Extensions */ = { isa = PBXGroup; children = ( + EA1013412B5DBDA5005E43F9 /* Defaults */, EAED41F02B54B1A60005FE0A /* QueryService+ConfigurableService */, EA9943E72B534D8900EE7B97 /* LanguageDetectOptimizeExtensions.swift */, EA9943ED2B5353AB00EE7B97 /* WindowTypeExtensions.swift */, @@ -2745,6 +2756,7 @@ 03BB2DEB29F57DC000447EDD /* NSImage+EZSymbolmage.m in Sources */, 03B0230629231FA6001C7E63 /* EZLabel.m in Sources */, 03F25CB329327BC200E66A12 /* EZShortcut.m in Sources */, + EA1013442B5DBDB1005E43F9 /* KeyCombo+Defaults.Serializable.swift in Sources */, 033B7134293CE2430096E2DF /* EZWebViewTranslator.m in Sources */, 03CF88632B137F650030C199 /* Array+Convenience.swift in Sources */, 03B0231229231FA6001C7E63 /* NSObject+DarkMode.m in Sources */, diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index b8a4d9137..5d0d13957 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3412,6 +3412,9 @@ } } } + }, + "xx" : { + }, "Youdao" : { "extractionState" : "manual", diff --git a/Easydict/NewApp/Configuration/Configuration.swift b/Easydict/NewApp/Configuration/Configuration.swift index dfc6b9b2c..fa301a90b 100644 --- a/Easydict/NewApp/Configuration/Configuration.swift +++ b/Easydict/NewApp/Configuration/Configuration.swift @@ -8,6 +8,7 @@ import Defaults import Foundation +import Magnet // Setting extension Defaults.Keys { @@ -90,9 +91,9 @@ extension Defaults.Keys { /// shortcut extension Defaults.Keys { - static let selectionShortcutKey = Key("EZSelectionShortcutKey_keyHolder", default: Data()) - static let snipShortcutKey = Key("EZSnipShortcutKey_keyHolder", default: Data()) - static let inputShortcutKey = Key("EZInputShortcutKey_keyHolder", default: Data()) - static let screenshotOCRShortcutKey = Key("EZScreenshotOCRShortcutKey_keyHolder", default: Data()) - static let showMiniWindowShortcutKey = Key("EZShowMiniShortcutKey_keyHolder", default: Data()) + static let selectionShortcut = Key("EZSelectionShortcutKey_keyHolder", default: nil) + static let snipShortcut = Key("EZSnipShortcutKey_keyHolder", default: nil) + static let inputShortcut = Key("EZInputShortcutKey_keyHolder", default: nil) + static let screenshotOCRShortcut = Key("EZScreenshotOCRShortcutKey_keyHolder", default: nil) + static let showMiniWindowShortcut = Key("EZShowMiniShortcutKey_keyHolder", default: nil) } diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index e693da16f..a85aa407e 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -49,57 +49,31 @@ class Shortcut: NSObject { // restore shortcut extension Shortcut { func restoreShortcut() { - if let inputTranslateKeyCombo = restoreInputTranslate() { + if let inputTranslateKeyCombo = Defaults[.inputShortcut] { bindingShortCut(keyCombo: inputTranslateKeyCombo, type: .inputTranslate) } - if let snipShortcutKeyKeyCombo = restoreSnipShortcutKey() { + if let snipShortcutKeyKeyCombo = Defaults[.snipShortcut] { bindingShortCut(keyCombo: snipShortcutKeyKeyCombo, type: .snipTranslate) } - if let selectionShortcutKeyCombo = restoreSelectionShortcutKey() { + if let selectionShortcutKeyCombo = Defaults[.selectionShortcut] { bindingShortCut(keyCombo: selectionShortcutKeyCombo, type: .selectTranslate) } - if let screenshotOCRShortcutKeyCombo = restoreScreenshotOCRShortcutKey() { + if let screenshotOCRShortcutKeyCombo = Defaults[.screenshotOCRShortcut] { bindingShortCut(keyCombo: screenshotOCRShortcutKeyCombo, type: .silentScreenshotOcr) } - if let showMiniWindowShortcutKeyCombo = restoreShowMiniWindow() { + if let showMiniWindowShortcutKeyCombo = Defaults[.showMiniWindowShortcut] { bindingShortCut(keyCombo: showMiniWindowShortcutKeyCombo, type: .showMiniWindow) } } - - private func restoreInputTranslate() -> KeyCombo? { - let data = Defaults[.inputShortcutKey] - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } - return keyCombo - } - - private func restoreSnipShortcutKey() -> KeyCombo? { - let data = Defaults[.snipShortcutKey] - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } - return keyCombo - } - - private func restoreSelectionShortcutKey() -> KeyCombo? { - let data = Defaults[.selectionShortcutKey] - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } - return keyCombo - } - - private func restoreScreenshotOCRShortcutKey() -> KeyCombo? { - let data = Defaults[.screenshotOCRShortcutKey] - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } - return keyCombo - } - - private func restoreShowMiniWindow() -> KeyCombo? { - let data = Defaults[.showMiniWindowShortcutKey] - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return nil } - return keyCombo - } } // binding shortcut extension Shortcut { - func bindingShortCut(keyCombo: KeyCombo, type: ShortcutType) { + func bindingShortCut(keyCombo: KeyCombo?, type: ShortcutType) { + guard let keyCombo else { + HotKeyCenter.shared.unregisterHotKey(with: type.rawValue) + return + } var hotKey: HotKey switch type { case .inputTranslate: @@ -160,30 +134,54 @@ extension Shortcut { public func shortcutKeyCombo(_ type: ShortcutType) -> KeyCombo? { switch type { case .inputTranslate: - guard let keyCombo = restoreInputTranslate() else { return nil } + guard let keyCombo = Defaults[.inputShortcut] else { return nil } return keyCombo case .snipTranslate: - guard let keyCombo = restoreSnipShortcutKey() else { return nil } + guard let keyCombo = Defaults[.snipShortcut] else { return nil } return keyCombo case .selectTranslate: - guard let keyCombo = restoreSelectionShortcutKey() else { return nil } + guard let keyCombo = Defaults[.selectionShortcut] else { return nil } return keyCombo case .silentScreenshotOcr: - guard let keyCombo = restoreScreenshotOCRShortcutKey() else { return nil } + guard let keyCombo = Defaults[.screenshotOCRShortcut] else { return nil } return keyCombo case .showMiniWindow: - guard let keyCombo = restoreShowMiniWindow() else { return nil } + guard let keyCombo = Defaults[.showMiniWindowShortcut] else { return nil } return keyCombo } } } -/// can't using keyEquivalent and EventModifiers in SwiftUI MenuItemView direct, because item -/// keyboardShortcut not support double modifier key but can use ⌥ as character -extension View { - public func keyboardShortcut(_ type: ShortcutType) -> some View { - guard let keyCombo = Shortcut.shared.shortcutKeyCombo(type) else { return AnyView(self) } - return AnyView(keyboardShortcut(fetchShortcutKeyEquivalent(keyCombo), modifiers: fetchShortcutKeyEventModifiers(keyCombo))) +struct KeyboardShortcut: ViewModifier { + init(type: ShortcutType) { + let key: Defaults.Key = switch type { + case .inputTranslate: + .inputShortcut + case .snipTranslate: + .snipShortcut + case .selectTranslate: + .selectionShortcut + case .silentScreenshotOcr: + .screenshotOCRShortcut + case .showMiniWindow: + .showMiniWindowShortcut + } + + _shortcut = .init(key) + } + + @Default var shortcut: KeyCombo? + + func body(content: Content) -> some View { + if let shortcut { + content + .keyboardShortcut( + fetchShortcutKeyEquivalent(shortcut), + modifiers: fetchShortcutKeyEventModifiers(shortcut) + ) + } else { + content + } } private func fetchShortcutKeyEquivalent(_ keyCombo: KeyCombo) -> KeyEquivalent { @@ -216,3 +214,12 @@ extension View { return modifiers } } + +/// can't using keyEquivalent and EventModifiers in SwiftUI MenuItemView direct, because item +/// keyboardShortcut not support double modifier key but can use ⌥ as character +public extension View { + @ViewBuilder + func keyboardShortcut(_ type: ShortcutType) -> some View { + modifier(KeyboardShortcut(type: type)) + } +} diff --git a/Easydict/NewApp/Utility/Extensions/Defaults/KeyCombo+Defaults.Serializable.swift b/Easydict/NewApp/Utility/Extensions/Defaults/KeyCombo+Defaults.Serializable.swift new file mode 100644 index 000000000..6858aa387 --- /dev/null +++ b/Easydict/NewApp/Utility/Extensions/Defaults/KeyCombo+Defaults.Serializable.swift @@ -0,0 +1,31 @@ +// +// KeyCombo+Defaults.Serializable.swift +// Easydict +// +// Created by 戴藏龙 on 2024/1/21. +// Copyright © 2024 izual. All rights reserved. +// + +import Defaults +import Foundation +import Magnet + +extension KeyCombo: Defaults.Serializable { + public static var bridge = ShortcutBridge() + + public struct ShortcutBridge: Defaults.Bridge { + public func serialize(_ value: Magnet.KeyCombo??) -> Data? { + guard let value else { return nil } + return try? JSONEncoder().encode(value) + } + + public func deserialize(_ object: Data?) -> Magnet.KeyCombo?? { + guard let data = object else { return nil } + return try? JSONDecoder().decode(KeyCombo.self, from: data) as Magnet.KeyCombo? + } + + public typealias Value = KeyCombo? + + public typealias Serializable = Data + } +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift index 9774d9e4f..8cdf368ee 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift @@ -56,43 +56,40 @@ extension GeneralKeyHolderWrapper { func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { storeKeyCombo(with: keyCombo) - guard let keyCombo else { return } Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) } func restoreKeyCombo(_ recordView: RecordView) { - var data: Data + var keyCombo: KeyCombo? switch type { case .inputTranslate: - data = Defaults[.inputShortcutKey] + keyCombo = Defaults[.inputShortcut] case .snipTranslate: - data = Defaults[.snipShortcutKey] + keyCombo = Defaults[.snipShortcut] case .selectTranslate: - data = Defaults[.selectionShortcutKey] + keyCombo = Defaults[.selectionShortcut] case .silentScreenshotOcr: - data = Defaults[.screenshotOCRShortcutKey] + keyCombo = Defaults[.screenshotOCRShortcut] case .showMiniWindow: - data = Defaults[.showMiniWindowShortcutKey] + keyCombo = Defaults[.showMiniWindowShortcut] } - guard let keyCombo = try? JSONDecoder().decode(KeyCombo.self, from: data) else { return } recordView.keyCombo = keyCombo Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) } // shortcut func storeKeyCombo(with keyCombo: KeyCombo?) { - let data = try? JSONEncoder().encode(keyCombo) switch type { case .inputTranslate: - Defaults[.inputShortcutKey] = data ?? Data() + Defaults[.inputShortcut] = keyCombo case .snipTranslate: - Defaults[.snipShortcutKey] = data ?? Data() + Defaults[.snipShortcut] = keyCombo case .selectTranslate: - Defaults[.selectionShortcutKey] = data ?? Data() + Defaults[.selectionShortcut] = keyCombo case .silentScreenshotOcr: - Defaults[.screenshotOCRShortcutKey] = data ?? Data() + Defaults[.screenshotOCRShortcut] = keyCombo case .showMiniWindow: - Defaults[.showMiniWindowShortcutKey] = data ?? Data() + Defaults[.showMiniWindowShortcut] = keyCombo } } } From 6444614d1dc868c98b01e8169eaff36876c2cb5a Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Sat, 27 Jan 2024 14:22:00 +0800 Subject: [PATCH 14/26] feat: add shortcut into new page --- Easydict.xcodeproj/project.pbxproj | 6 ++--- Easydict/App/Localizable.xcstrings | 24 ++++++++++++++++--- .../NewApp/View/SettingView/SettingView.swift | 6 ++++- .../View/SettingView/Tabs/GeneralTab.swift | 1 - .../View/SettingView/Tabs/ShortcutTab.swift | 4 +++- .../GeneralKeyHolderWrapper.swift | 0 .../GeneralShortcutSetting.swift | 9 +++++-- 7 files changed, 39 insertions(+), 11 deletions(-) rename Easydict/NewApp/View/SettingView/Tabs/View/{Genearl => Shortcut}/GeneralKeyHolderWrapper.swift (100%) rename Easydict/NewApp/View/SettingView/Tabs/View/{Genearl => Shortcut}/GeneralShortcutSetting.swift (75%) diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 2da67b0ef..cf35c6fcf 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -2162,18 +2162,18 @@ 9627F9332B59956800B1E999 /* View */ = { isa = PBXGroup; children = ( - 9627F9342B59956800B1E999 /* Genearl */, + 9627F9342B59956800B1E999 /* Shortcut */, ); path = View; sourceTree = ""; }; - 9627F9342B59956800B1E999 /* Genearl */ = { + 9627F9342B59956800B1E999 /* Shortcut */ = { isa = PBXGroup; children = ( 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */, 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */, ); - path = Genearl; + path = Shortcut; sourceTree = ""; }; 967712EB2B5B93E200105E0F /* Feature */ = { diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 5d0d13957..c10cd4c3b 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1308,6 +1308,23 @@ } } }, + "global_shortcut_setting" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Global Shortcut" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "全局快捷键" + } + } + } + }, "google_translate" : { "localizations" : { "en" : { @@ -3004,6 +3021,9 @@ } } } + }, + "shortcut" : { + }, "shortcut_select_translate_window_type" : { "localizations" : { @@ -3022,6 +3042,7 @@ } }, "shortcut_setting" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -3412,9 +3433,6 @@ } } } - }, - "xx" : { - }, "Youdao" : { "extractionState" : "manual", diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index f64f70efc..395820a77 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -12,6 +12,7 @@ enum SettingTab: Int { case general case service case disabled + case shortcut case privacy case about } @@ -35,6 +36,9 @@ struct SettingView: View { .tabItem { Label("disabled_app_list", systemImage: "nosign") } .tag(SettingTab.disabled) + ShortcutTab() + .tabItem { Label("shortcut", systemImage: "command.square") } + .tag(SettingTab.shortcut) PrivacyTab() .tabItem { Label("privacy", systemImage: "hand.raised.square") } .tag(SettingTab.privacy) @@ -65,7 +69,7 @@ struct SettingView: View { let height = switch selection { case .general: maxWidth - case .service, .disabled: + case .service, .disabled, .shortcut: 500 case .privacy: 320 diff --git a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift index 15a990542..852631707 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift @@ -13,7 +13,6 @@ import SwiftUI struct GeneralTab: View { var body: some View { Form { - ShortcutSettingView() Section { Picker("setting.general.appearance.light_dark_appearance", selection: $appearanceType) { ForEach(AppearenceType.allCases, id: \.rawValue) { option in diff --git a/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift index d18125c37..136b1e34e 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift @@ -11,7 +11,9 @@ import SwiftUI @available(macOS 13, *) struct ShortcutTab: View { var body: some View { - Text("xx") + Form { + ShortcutSettingView() + }.formStyle(.grouped) } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift similarity index 100% rename from Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralKeyHolderWrapper.swift rename to Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift similarity index 75% rename from Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift rename to Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index 99f627849..5d4855f20 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Genearl/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -9,32 +9,37 @@ import SwiftUI @available(macOS 13, *) -extension GeneralTab { +extension ShortcutTab { struct ShortcutSettingView: View { var body: some View { Section { HStack { Text("input_translate") + .frame(minWidth: 140, alignment: .trailing) GeneralKeyHolderWrapper(shortcutType: .inputTranslate).frame(width: 180, height: 24) } HStack { Text("snip_translate") + .frame(minWidth: 140, alignment: .trailing) GeneralKeyHolderWrapper(shortcutType: .snipTranslate).frame(width: 180, height: 24) } HStack { Text("select_translate") + .frame(minWidth: 140, alignment: .trailing) GeneralKeyHolderWrapper(shortcutType: .selectTranslate).frame(width: 180, height: 24) } HStack { Text("show_mini_window") + .frame(minWidth: 140, alignment: .trailing) GeneralKeyHolderWrapper(shortcutType: .showMiniWindow).frame(width: 180, height: 24) } HStack { Text("silent_screenshot_ocr") + .frame(minWidth: 140, alignment: .trailing) GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr).frame(width: 180, height: 24) } } header: { - Text("shortcut_setting") + Text("global_shortcut_setting") } } } From 1ea12a2a28c4a14c60b72e82e4e035b80ee935cc Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Mon, 29 Jan 2024 17:47:08 +0800 Subject: [PATCH 15/26] feat: add shortcut confict validator --- .../NewApp/Feature/Shortcut/Shortcut.swift | 2 + .../Feature/Shortcut/ShortcutValidator.swift | 101 ++++++++++++++++++ .../Shortcut/GeneralKeyHolderWrapper.swift | 6 ++ 3 files changed, 109 insertions(+) create mode 100644 Easydict/NewApp/Feature/Shortcut/ShortcutValidator.swift diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index a85aa407e..9b91a1e05 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -21,6 +21,8 @@ public enum ShortcutType: String { } class Shortcut: NSObject { + var confictMenuItem: NSMenuItem? + static let shared = Shortcut() @objc static func setupShortcut() { diff --git a/Easydict/NewApp/Feature/Shortcut/ShortcutValidator.swift b/Easydict/NewApp/Feature/Shortcut/ShortcutValidator.swift new file mode 100644 index 000000000..0f818a228 --- /dev/null +++ b/Easydict/NewApp/Feature/Shortcut/ShortcutValidator.swift @@ -0,0 +1,101 @@ +// +// ShortcutValidator.swift +// Easydict +// +// Created by Sharker on 2024/1/29. +// Copyright © 2024 izual. All rights reserved. +// + +import Carbon +import Carbon.HIToolbox +import Foundation +import KeyHolder +import Magnet +import Sauce + +extension Shortcut { + static func validateShortcut(_ keyCombo: KeyCombo) -> Bool { + validateShortcutConfictBySystem(keyCombo) || + validateShortcutConfictByMenuItem(keyCombo) || + validateShortcutConfictByCustom(keyCombo) + } +} + +// validate shortcut used by system +// ref: https://github.com/cocoabits/MASShortcut/blob/6f2603c6b6cc18f64a799e5d2c9d3bbc467c413a/Framework/Model/MASShortcutValidator.m#L94 +extension Shortcut { + static func validateShortcutConfictBySystem(_ keyCombo: KeyCombo) -> Bool { + systemUsedShortcut().contains(keyCombo) + } + + static func systemUsedShortcut() -> [KeyCombo] { + var shortcutsUnmanaged: Unmanaged? + guard + CopySymbolicHotKeys(&shortcutsUnmanaged) == noErr, + let shortcuts = shortcutsUnmanaged?.takeRetainedValue() as? [[String: Any]] + else { + assertionFailure("Could not get system keyboard shortcuts") + return [] + } + return shortcuts.compactMap { + guard + ($0[kHISymbolicHotKeyEnabled] as? Bool) == true, + let carbonKeyCode = $0[kHISymbolicHotKeyCode] as? Int, + let carbonModifiers = $0[kHISymbolicHotKeyModifiers] as? Int + else { + return nil + } + guard let key = Sauce.shared.key(for: Int(carbonKeyCode)) else { return nil } + guard let keyCombo = KeyCombo(key: key, carbonModifiers: carbonModifiers) else { return nil } + return keyCombo + } + } +} + +// validate shortcut used by menuItem +extension Shortcut { + static func validateShortcutConfictByMenuItem(_ keyCombo: KeyCombo) -> Bool { + if let item = menuItemUsedShortcut(keyCombo) { + Shortcut.shared.confictMenuItem = item + return true + } else { + return false + } + } + + static func menuItemUsedShortcut(_ keyCombo: KeyCombo) -> NSMenuItem? { + guard let mainMenu = NSApp.mainMenu else { + return nil + } + return menuItemWithMatchingShortcut(in: mainMenu, keyCombo: keyCombo) + } + + static func menuItemWithMatchingShortcut(in menu: NSMenu, keyCombo: KeyCombo) -> NSMenuItem? { + for item in menu.items { + let keyEquivalent = item.keyEquivalent + let keyEquivalentModifierMask = item.keyEquivalentModifierMask + if keyCombo.keyEquivalent == keyEquivalent, + keyCombo.keyEquivalentModifierMask == keyEquivalentModifierMask, + keyCombo.keyEquivalent != "" + { + return item + } + if let submenu = item.submenu, + let menuItem = menuItemWithMatchingShortcut(in: submenu, keyCombo: keyCombo) + { + return menuItem + } + } + return nil + } +} + +// validate shortcut used by custom +// ref: https://support.apple.com/zh-cn/HT201236 +extension Shortcut { + static func validateShortcutConfictByCustom(_: KeyCombo) -> Bool { + false + } + + static func customUsedShortcut(_: KeyCombo) {} +} diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index 8cdf368ee..0deee0f8a 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -55,6 +55,12 @@ extension GeneralKeyHolderWrapper { func recordViewDidEndRecording(_: RecordView) {} func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { + if let key = keyCombo { + // shortcut validate confict + if Shortcut.validateShortcut(key) { + print("confict") + } + } storeKeyCombo(with: keyCombo) Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) } From 1d6aa55cfae7df2c4fb6c228ff5310f54464656d Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Tue, 30 Jan 2024 11:10:23 +0800 Subject: [PATCH 16/26] feat: shortcut confict alter --- Easydict.xcodeproj/project.pbxproj | 4 ++ Easydict/App/Localizable.xcstrings | 51 +++++++++++++++++++ .../NewApp/Feature/Shortcut/Shortcut.swift | 6 +++ .../View/SettingView/Tabs/ShortcutTab.swift | 4 +- .../Shortcut/GeneralKeyHolderWrapper.swift | 16 ++++-- .../Shortcut/GeneralShortcutSetting.swift | 36 ++++++++++--- 6 files changed, 105 insertions(+), 12 deletions(-) diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index cf35c6fcf..72a6258c5 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -256,6 +256,7 @@ 62E2BF4B2B4082BA00E42D38 /* AliResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF482B4082BA00E42D38 /* AliResponse.swift */; }; 62E2BF4C2B4082BA00E42D38 /* AliTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E2BF492B4082BA00E42D38 /* AliTranslateType.swift */; }; 62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ED29A12B15F1F500901F51 /* EZWrapView.m */; }; + 960835502B6791F200C6A931 /* ShortcutValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9608354F2B6791F200C6A931 /* ShortcutValidator.swift */; }; 96099AE22B5D40330055C4DD /* ShortcutTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96099AE12B5D40330055C4DD /* ShortcutTab.swift */; }; 9627F9382B59956800B1E999 /* GeneralShortcutSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */; }; 9627F9392B59956800B1E999 /* GeneralKeyHolderWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */; }; @@ -753,6 +754,7 @@ 62ED29A12B15F1F500901F51 /* EZWrapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZWrapView.m; sourceTree = ""; }; 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Easydict.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 91E3E579C6DB88658B4BB102 /* Pods-Easydict.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.release.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.release.xcconfig"; sourceTree = ""; }; + 9608354F2B6791F200C6A931 /* ShortcutValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutValidator.swift; sourceTree = ""; }; 96099AE12B5D40330055C4DD /* ShortcutTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutTab.swift; sourceTree = ""; }; 9627F9352B59956800B1E999 /* GeneralShortcutSetting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralShortcutSetting.swift; sourceTree = ""; }; 9627F9362B59956800B1E999 /* GeneralKeyHolderWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralKeyHolderWrapper.swift; sourceTree = ""; }; @@ -2188,6 +2190,7 @@ isa = PBXGroup; children = ( 967712ED2B5B943400105E0F /* Shortcut.swift */, + 9608354F2B6791F200C6A931 /* ShortcutValidator.swift */, ); path = Shortcut; sourceTree = ""; @@ -2720,6 +2723,7 @@ 03B3B8B22925D5B200168E8D /* EZPopButtonWindow.m in Sources */, 03B0231529231FA6001C7E63 /* SnipWindow.m in Sources */, 033363A0293A05D200FED9C8 /* EZSelectLanguageButton.m in Sources */, + 960835502B6791F200C6A931 /* ShortcutValidator.swift in Sources */, 03542A522937B69200C34C33 /* EZYoudaoTranslateResponse.m in Sources */, 03B0230129231FA6001C7E63 /* EZQueryView.m in Sources */, 03542A3D2937AF4F00C34C33 /* EZQueryResult.m in Sources */, diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index c10cd4c3b..2aec8da33 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3024,6 +3024,57 @@ }, "shortcut" : { + }, + "shortcut_confict" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Shortcut Confict" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "快捷键冲突" + } + } + } + }, + "shortcut_confict_confirm" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "确定" + } + } + } + }, + "shortcut_confict_message" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Shortcut Confict With:" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "快捷键冲突:" + } + } + } }, "shortcut_select_translate_window_type" : { "localizations" : { diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index 9b91a1e05..2234d52fc 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -20,6 +20,12 @@ public enum ShortcutType: String { case showMiniWindow = "EZShowMiniShortcutKey" } +// Confict Message +public struct ShortcutConfictAlertMessage: Identifiable { + public var id: String { message } + var message: String +} + class Shortcut: NSObject { var confictMenuItem: NSMenuItem? diff --git a/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift index 136b1e34e..52daaabe6 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ShortcutTab.swift @@ -12,7 +12,9 @@ import SwiftUI struct ShortcutTab: View { var body: some View { Form { - ShortcutSettingView() + // Global shortcut + GeneralShortcutSettingView() + // In app shortcut }.formStyle(.grouped) } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index 0deee0f8a..1a73ecd91 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -14,12 +14,14 @@ import SwiftUI struct GeneralKeyHolderWrapper: NSViewRepresentable { func makeCoordinator() -> Coordinator { - .init(shortcutType: type) + .init(shortcutType: type, confictAlterMessage: $confictAlterMessage) } private var type: ShortcutType - init(shortcutType: ShortcutType) { + @Binding var confictAlterMessage: ShortcutConfictAlertMessage + init(shortcutType: ShortcutType, confictAlterMessage: Binding) { type = shortcutType + _confictAlterMessage = confictAlterMessage } func makeNSView(context: Context) -> some NSView { @@ -40,8 +42,10 @@ struct GeneralKeyHolderWrapper: NSViewRepresentable { extension GeneralKeyHolderWrapper { class Coordinator: NSObject, RecordViewDelegate { private var type: ShortcutType - init(shortcutType: ShortcutType) { + @Binding var confictAlterMessage: ShortcutConfictAlertMessage + init(shortcutType: ShortcutType, confictAlterMessage: Binding) { type = shortcutType + _confictAlterMessage = confictAlterMessage } func recordViewShouldBeginRecording(_: KeyHolder.RecordView) -> Bool { @@ -54,11 +58,13 @@ extension GeneralKeyHolderWrapper { func recordViewDidEndRecording(_: RecordView) {} - func recordView(_: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { + func recordView(_ recordView: RecordView, didChangeKeyCombo keyCombo: KeyCombo?) { if let key = keyCombo { // shortcut validate confict if Shortcut.validateShortcut(key) { - print("confict") + confictAlterMessage = ShortcutConfictAlertMessage(message: "shortcut_confict_message\(String(describing: Shortcut.shared.confictMenuItem?.title))") + recordView.clear() + return } } storeKeyCombo(with: keyCombo) diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index 5d4855f20..da365fc36 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -10,37 +10,61 @@ import SwiftUI @available(macOS 13, *) extension ShortcutTab { - struct ShortcutSettingView: View { + struct GeneralShortcutSettingView: View { + @State var confictAlterMessage: ShortcutConfictAlertMessage = .init(message: "") +// @State var showAlter: Bool = false + var body: some View { + let showAlter = Binding( + get: { + if !confictAlterMessage.message.isEmpty { + true + } else { + false + } + }, set: { _ in + } + ) Section { HStack { Text("input_translate") .frame(minWidth: 140, alignment: .trailing) - GeneralKeyHolderWrapper(shortcutType: .inputTranslate).frame(width: 180, height: 24) + GeneralKeyHolderWrapper(shortcutType: .inputTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("snip_translate") .frame(minWidth: 140, alignment: .trailing) - GeneralKeyHolderWrapper(shortcutType: .snipTranslate).frame(width: 180, height: 24) + GeneralKeyHolderWrapper(shortcutType: .snipTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("select_translate") .frame(minWidth: 140, alignment: .trailing) - GeneralKeyHolderWrapper(shortcutType: .selectTranslate).frame(width: 180, height: 24) + GeneralKeyHolderWrapper(shortcutType: .selectTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("show_mini_window") .frame(minWidth: 140, alignment: .trailing) - GeneralKeyHolderWrapper(shortcutType: .showMiniWindow).frame(width: 180, height: 24) + GeneralKeyHolderWrapper(shortcutType: .showMiniWindow, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("silent_screenshot_ocr") .frame(minWidth: 140, alignment: .trailing) - GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr).frame(width: 180, height: 24) + GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } } header: { Text("global_shortcut_setting") } + + .alert(String(localized: "shortcut_confict"), + isPresented: showAlter, + presenting: confictAlterMessage) + { _ in + Button(String(localized: "shortcut_confict_confirm")) { + confictAlterMessage = ShortcutConfictAlertMessage(message: "") + } + } message: { message in + Text(message.message) + } } } } From 1354628cc16b88e5ea0562033190903f99e49e1b Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Tue, 30 Jan 2024 12:52:27 +0800 Subject: [PATCH 17/26] feat: shortcut confict msg --- Easydict/App/Localizable.xcstrings | 4 ++-- .../Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 2aec8da33..7743385cc 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3065,13 +3065,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Shortcut Confict With:" + "value" : "Shortcut Confict With" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷键冲突:" + "value" : "快捷键冲突" } } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index 1a73ecd91..8cc830bfc 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -62,7 +62,13 @@ extension GeneralKeyHolderWrapper { if let key = keyCombo { // shortcut validate confict if Shortcut.validateShortcut(key) { - confictAlterMessage = ShortcutConfictAlertMessage(message: "shortcut_confict_message\(String(describing: Shortcut.shared.confictMenuItem?.title))") + if #available(macOS 12, *) { + confictAlterMessage = ShortcutConfictAlertMessage(message: String(localized: "shortcut_confict_message") + (Shortcut.shared.confictMenuItem?.title ?? "")) + } else { + // Fallback on earlier versions + let msg = NSLocalizedString("shortcut_confict_message", comment: "") + (Shortcut.shared.confictMenuItem?.title ?? "") + confictAlterMessage = ShortcutConfictAlertMessage(message: msg) + } recordView.clear() return } From 4a937a3b1a6cee312b8b56f0ebcbc012f6d423bf Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Tue, 30 Jan 2024 14:07:02 +0800 Subject: [PATCH 18/26] fix: string formate --- .../Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index 8cc830bfc..a40007270 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -63,10 +63,10 @@ extension GeneralKeyHolderWrapper { // shortcut validate confict if Shortcut.validateShortcut(key) { if #available(macOS 12, *) { - confictAlterMessage = ShortcutConfictAlertMessage(message: String(localized: "shortcut_confict_message") + (Shortcut.shared.confictMenuItem?.title ?? "")) + confictAlterMessage = ShortcutConfictAlertMessage(message: String(localized: "shortcut_confict_message") + " " + (Shortcut.shared.confictMenuItem?.title ?? "")) } else { // Fallback on earlier versions - let msg = NSLocalizedString("shortcut_confict_message", comment: "") + (Shortcut.shared.confictMenuItem?.title ?? "") + let msg = NSLocalizedString("shortcut_confict_message", comment: "") + " " + (Shortcut.shared.confictMenuItem?.title ?? "") confictAlterMessage = ShortcutConfictAlertMessage(message: msg) } recordView.clear() From a4add69cd2ebfbab6254ead740cfa01d532b2e22 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Tue, 30 Jan 2024 15:55:24 +0800 Subject: [PATCH 19/26] fix: unused string in xcstrings --- Easydict/App/Localizable.xcstrings | 34 +++++++++++++----------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index e040b2d88..ddb6909bf 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3064,7 +3064,20 @@ } }, "shortcut" : { - + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Shortcut" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "快捷键" + } + } + } }, "shortcut_confict" : { "extractionState" : "manual", @@ -3133,23 +3146,6 @@ } } }, - "shortcut_setting" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Shortcut" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "快捷键" - } - } - } - }, "show" : { "localizations" : { "en" : { @@ -3555,4 +3551,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file From 41afc5e20eedc26cdb25ae5ca69fa5f1b1086519 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Tue, 30 Jan 2024 16:45:10 +0800 Subject: [PATCH 20/26] fix: add advanced en string --- Easydict/App/Localizable.xcstrings | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index ddb6909bf..15ab5ef11 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -46,9 +46,15 @@ }, "advanced" : { "localizations" : { - "zh-Hans" : { + "en" : { "stringUnit" : { "state" : "translated", + "value" : "Advanced" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "needs_review", "value" : "高级" } } From 560be05767018ddbd207746a5720d70c8f1e6abf Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Wed, 31 Jan 2024 21:15:11 +0800 Subject: [PATCH 21/26] pref: UI optimize --- Easydict/App/Localizable.xcstrings | 22 +++++++++---------- .../Shortcut/GeneralShortcutSetting.swift | 10 ++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 15ab5ef11..76c0bb81f 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1510,13 +1510,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Input Translate:" + "value" : "Input Translate" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "输入翻译:" + "value" : "输入翻译" } } } @@ -2335,13 +2335,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Select Text Translate:" + "value" : "Select Text Translate" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "划词翻译:" + "value" : "划词翻译" } } } @@ -3237,13 +3237,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Show Mini Window:" + "value" : "Show Mini Window" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "显示迷你窗口:" + "value" : "显示迷你窗口" } } } @@ -3253,13 +3253,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Silent Screenshot OCR:" + "value" : "Silent Screenshot OCR" } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", - "value" : "静默截图 OCR:" + "state" : "needs_review", + "value" : "静默截图 OCR" } } } @@ -3302,13 +3302,13 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Snip Translate:" + "value" : "Snip Translate" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "截图翻译:" + "value" : "截图翻译" } } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index da365fc36..2d2770101 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -28,27 +28,27 @@ extension ShortcutTab { Section { HStack { Text("input_translate") - .frame(minWidth: 140, alignment: .trailing) + Spacer() GeneralKeyHolderWrapper(shortcutType: .inputTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("snip_translate") - .frame(minWidth: 140, alignment: .trailing) + Spacer() GeneralKeyHolderWrapper(shortcutType: .snipTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("select_translate") - .frame(minWidth: 140, alignment: .trailing) + Spacer() GeneralKeyHolderWrapper(shortcutType: .selectTranslate, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("show_mini_window") - .frame(minWidth: 140, alignment: .trailing) + Spacer() GeneralKeyHolderWrapper(shortcutType: .showMiniWindow, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } HStack { Text("silent_screenshot_ocr") - .frame(minWidth: 140, alignment: .trailing) + Spacer() GeneralKeyHolderWrapper(shortcutType: .silentScreenshotOcr, confictAlterMessage: $confictAlterMessage).frame(width: 180, height: 24) } } header: { From b5169dcde3a8fd1348bd83fe4ef30860821228f1 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Wed, 31 Jan 2024 22:29:17 +0800 Subject: [PATCH 22/26] fix: marked the localized as reviewed --- Easydict/App/Localizable.xcstrings | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 76c0bb81f..808bcc268 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -54,7 +54,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "高级" } } @@ -1332,7 +1332,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "Gemini 翻译" } } @@ -1359,7 +1359,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "全局快捷键" } } @@ -3096,7 +3096,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "快捷键冲突" } } @@ -3258,7 +3258,7 @@ }, "zh-Hans" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "静默截图 OCR" } } From a496ff518a824ac60d4323a08c591ea0ff105967 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Thu, 1 Feb 2024 15:58:04 +0800 Subject: [PATCH 23/26] fix: review problem --- .../NewApp/Feature/Shortcut/Shortcut.swift | 27 ++++++++----------- .../Shortcut/GeneralKeyHolderWrapper.swift | 4 +-- .../Shortcut/GeneralShortcutSetting.swift | 1 - 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index 2234d52fc..f4eaf72ec 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -57,27 +57,22 @@ class Shortcut: NSObject { // restore shortcut extension Shortcut { func restoreShortcut() { - if let inputTranslateKeyCombo = Defaults[.inputShortcut] { - bindingShortCut(keyCombo: inputTranslateKeyCombo, type: .inputTranslate) - } - if let snipShortcutKeyKeyCombo = Defaults[.snipShortcut] { - bindingShortCut(keyCombo: snipShortcutKeyKeyCombo, type: .snipTranslate) - } - if let selectionShortcutKeyCombo = Defaults[.selectionShortcut] { - bindingShortCut(keyCombo: selectionShortcutKeyCombo, type: .selectTranslate) - } - if let screenshotOCRShortcutKeyCombo = Defaults[.screenshotOCRShortcut] { - bindingShortCut(keyCombo: screenshotOCRShortcutKeyCombo, type: .silentScreenshotOcr) - } - if let showMiniWindowShortcutKeyCombo = Defaults[.showMiniWindowShortcut] { - bindingShortCut(keyCombo: showMiniWindowShortcutKeyCombo, type: .showMiniWindow) - } + // inputTranslate + bindingShortcut(keyCombo: Defaults[.inputShortcut], type: .inputTranslate) + // snipTranslate + bindingShortcut(keyCombo: Defaults[.snipShortcut], type: .snipTranslate) + // selectTranslate + bindingShortcut(keyCombo: Defaults[.selectionShortcut], type: .selectTranslate) + // silentScreenshotOcr + bindingShortcut(keyCombo: Defaults[.screenshotOCRShortcut], type: .silentScreenshotOcr) + // showMiniWindow + bindingShortcut(keyCombo: Defaults[.showMiniWindowShortcut], type: .showMiniWindow) } } // binding shortcut extension Shortcut { - func bindingShortCut(keyCombo: KeyCombo?, type: ShortcutType) { + func bindingShortcut(keyCombo: KeyCombo?, type: ShortcutType) { guard let keyCombo else { HotKeyCenter.shared.unregisterHotKey(with: type.rawValue) return diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index a40007270..7c8b50c5f 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -74,7 +74,7 @@ extension GeneralKeyHolderWrapper { } } storeKeyCombo(with: keyCombo) - Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) + Shortcut.shared.bindingShortcut(keyCombo: keyCombo, type: type) } func restoreKeyCombo(_ recordView: RecordView) { @@ -92,7 +92,7 @@ extension GeneralKeyHolderWrapper { keyCombo = Defaults[.showMiniWindowShortcut] } recordView.keyCombo = keyCombo - Shortcut.shared.bindingShortCut(keyCombo: keyCombo, type: type) + Shortcut.shared.bindingShortcut(keyCombo: keyCombo, type: type) } // shortcut diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index 2d2770101..c18ef3c88 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -12,7 +12,6 @@ import SwiftUI extension ShortcutTab { struct GeneralShortcutSettingView: View { @State var confictAlterMessage: ShortcutConfictAlertMessage = .init(message: "") -// @State var showAlter: Bool = false var body: some View { let showAlter = Binding( From d497caa51ca45d9b05b2f20dc79c3b0e8e9e0634 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Thu, 1 Feb 2024 16:33:25 +0800 Subject: [PATCH 24/26] fix: optimize the shortcut confict alter message --- Easydict/App/Localizable.xcstrings | 29 +++++++++++++++++-- .../NewApp/Feature/Shortcut/Shortcut.swift | 1 + .../Shortcut/GeneralKeyHolderWrapper.swift | 7 +++-- .../Shortcut/GeneralShortcutSetting.swift | 4 +-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 344105d83..99c333888 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3136,19 +3136,42 @@ } } }, - "shortcut_confict_message" : { + "shortcut_confict_message (Shortcut.shared.confictMenuItem?.title ?? \"\")" : { + + }, + "shortcut_confict_message %@" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Shortcut Confict With" + "value" : "The current shortcut can't be used because it is already used \"%@\"" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷键冲突" + "value" : "当前快捷键无法使用,因为它已被\n“%@”占用" + } + } + } + }, + "shortcut_confict_title (keyCombo!.keyEquivalentModifierMaskString + keyCombo!.characters)" : { + + }, + "shortcut_confict_title %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Shortcut Confict With \"%@\" Unable Use This" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "快捷键”%@“,无法使用" } } } diff --git a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift index f4eaf72ec..434c33c77 100644 --- a/Easydict/NewApp/Feature/Shortcut/Shortcut.swift +++ b/Easydict/NewApp/Feature/Shortcut/Shortcut.swift @@ -23,6 +23,7 @@ public enum ShortcutType: String { // Confict Message public struct ShortcutConfictAlertMessage: Identifiable { public var id: String { message } + var title: String var message: String } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift index 7c8b50c5f..e94dfda4e 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralKeyHolderWrapper.swift @@ -63,11 +63,12 @@ extension GeneralKeyHolderWrapper { // shortcut validate confict if Shortcut.validateShortcut(key) { if #available(macOS 12, *) { - confictAlterMessage = ShortcutConfictAlertMessage(message: String(localized: "shortcut_confict_message") + " " + (Shortcut.shared.confictMenuItem?.title ?? "")) + confictAlterMessage = ShortcutConfictAlertMessage(title: String(localized: "shortcut_confict_title \(keyCombo!.keyEquivalentModifierMaskString + keyCombo!.characters)"), message: String(localized: "shortcut_confict_message \(Shortcut.shared.confictMenuItem?.title ?? "")")) } else { // Fallback on earlier versions - let msg = NSLocalizedString("shortcut_confict_message", comment: "") + " " + (Shortcut.shared.confictMenuItem?.title ?? "") - confictAlterMessage = ShortcutConfictAlertMessage(message: msg) + let title = NSLocalizedString("shortcut_confict_title \(keyCombo!.keyEquivalentModifierMaskString + keyCombo!.characters)", comment: "") + let msg = NSLocalizedString("shortcut_confict_message \(Shortcut.shared.confictMenuItem?.title ?? "")", comment: "") + confictAlterMessage = ShortcutConfictAlertMessage(title: title, message: msg) } recordView.clear() return diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index c18ef3c88..aaede6309 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -11,7 +11,7 @@ import SwiftUI @available(macOS 13, *) extension ShortcutTab { struct GeneralShortcutSettingView: View { - @State var confictAlterMessage: ShortcutConfictAlertMessage = .init(message: "") + @State var confictAlterMessage: ShortcutConfictAlertMessage = .init(title: "", message: "") var body: some View { let showAlter = Binding( @@ -59,7 +59,7 @@ extension ShortcutTab { presenting: confictAlterMessage) { _ in Button(String(localized: "shortcut_confict_confirm")) { - confictAlterMessage = ShortcutConfictAlertMessage(message: "") + confictAlterMessage = ShortcutConfictAlertMessage(title: "", message: "") } } message: { message in Text(message.message) From 8d1e68a85554fb18e5f2ce5fd3b9571a5da9afb7 Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Thu, 1 Feb 2024 16:42:01 +0800 Subject: [PATCH 25/26] fix: optimize alter message --- Easydict/App/Localizable.xcstrings | 10 +++++----- .../Tabs/View/Shortcut/GeneralShortcutSetting.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 99c333888..6e2c2cf10 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -3102,19 +3102,19 @@ } } }, - "shortcut_confict" : { + "shortcut_confict %@" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Shortcut Confict" + "value" : "%@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷键冲突" + "value" : "%@" } } } @@ -3151,7 +3151,7 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "当前快捷键无法使用,因为它已被\n“%@”占用" + "value" : "当前快捷键无法使用,因为它已被\n\"%@\"占用" } } } @@ -3171,7 +3171,7 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "快捷键”%@“,无法使用" + "value" : "快捷键\"%@\",无法使用" } } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift index aaede6309..7387a5b32 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/View/Shortcut/GeneralShortcutSetting.swift @@ -54,7 +54,7 @@ extension ShortcutTab { Text("global_shortcut_setting") } - .alert(String(localized: "shortcut_confict"), + .alert(String(localized: "shortcut_confict \(confictAlterMessage.title)"), isPresented: showAlter, presenting: confictAlterMessage) { _ in From e3c5aa4c3bc1815d733f4961c037292cfeed69cc Mon Sep 17 00:00:00 2001 From: Sharker <1548742234@qq.com> Date: Thu, 1 Feb 2024 23:35:34 +0800 Subject: [PATCH 26/26] fix: remove the duplicate package.resloved --- .../xcshareddata/swiftpm/Package.resolved | 257 ------------------ 1 file changed, 257 deletions(-) delete mode 100644 Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 4adaef040..000000000 --- a/Easydict.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,257 +0,0 @@ -{ - "pins" : [ - { - "identity" : "abseil-cpp-binary", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/abseil-cpp-binary.git", - "state" : { - "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", - "version" : "1.2022062300.0" - } - }, - { - "identity" : "alamofire", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Alamofire/Alamofire.git", - "state" : { - "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad", - "version" : "5.8.1" - } - }, - { - "identity" : "app-check", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/app-check.git", - "state" : { - "revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2", - "version" : "10.18.1" - } - }, - { - "identity" : "appcenter-sdk-apple", - "kind" : "remoteSourceControl", - "location" : "https://github.com/microsoft/appcenter-sdk-apple.git", - "state" : { - "revision" : "1120c26835925f8314d035127c580bc71689c620", - "version" : "5.0.4" - } - }, - { - "identity" : "cocoalumberjack", - "kind" : "remoteSourceControl", - "location" : "https://github.com/CocoaLumberjack/CocoaLumberjack.git", - "state" : { - "revision" : "80ada1f753b0d53d9b57c465936a7c4169375002", - "version" : "3.7.4" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift", - "state" : { - "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version" : "1.8.1" - } - }, - { - "identity" : "defaults", - "kind" : "remoteSourceControl", - "location" : "https://github.com/sindresorhus/Defaults.git", - "state" : { - "revision" : "3efef5a28ebdbbe922d4a2049493733ed14475a6", - "version" : "7.3.1" - } - }, - { - "identity" : "firebase-ios-sdk", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/firebase-ios-sdk", - "state" : { - "revision" : "b880ec8ec927a838c51c12862c6222c30d7097d7", - "version" : "10.20.0" - } - }, - { - "identity" : "googleappmeasurement", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleAppMeasurement.git", - "state" : { - "revision" : "ceec9f28dea12b7cf3dabf18b5ed7621c88fd4aa", - "version" : "10.20.0" - } - }, - { - "identity" : "googledatatransport", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleDataTransport.git", - "state" : { - "revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117", - "version" : "9.3.0" - } - }, - { - "identity" : "googleutilities", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/GoogleUtilities.git", - "state" : { - "revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3", - "version" : "7.12.1" - } - }, - { - "identity" : "grpc-binary", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/grpc-binary.git", - "state" : { - "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", - "version" : "1.49.1" - } - }, - { - "identity" : "gtm-session-fetcher", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/gtm-session-fetcher.git", - "state" : { - "revision" : "115f75e43851774934d695449a4836123c3246e1", - "version" : "3.2.0" - } - }, - { - "identity" : "hue", - "kind" : "remoteSourceControl", - "location" : "https://github.com/zenangst/Hue", - "state" : { - "revision" : "b9d920cee4ba795fefb828d130744eee1e3d2feb", - "version" : "5.0.1" - } - }, - { - "identity" : "interop-ios-for-google-sdks", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/interop-ios-for-google-sdks.git", - "state" : { - "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", - "version" : "100.0.0" - } - }, - { - "identity" : "leveldb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/leveldb.git", - "state" : { - "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", - "version" : "1.22.3" - } - }, - { - "identity" : "mjextension", - "kind" : "remoteSourceControl", - "location" : "https://github.com/CoderMJLee/MJExtension", - "state" : { - "revision" : "43dce6be9c91a7034d37ed171b3e60a7bb760857", - "version" : "3.4.1" - } - }, - { - "identity" : "nanopb", - "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/nanopb.git", - "state" : { - "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692", - "version" : "2.30909.0" - } - }, - { - "identity" : "plcrashreporter", - "kind" : "remoteSourceControl", - "location" : "https://github.com/microsoft/PLCrashReporter.git", - "state" : { - "revision" : "1aed8f7dc79ce8e674c61e430ef51ca3db18cea9", - "version" : "1.11.1" - } - }, - { - "identity" : "promises", - "kind" : "remoteSourceControl", - "location" : "https://github.com/google/promises.git", - "state" : { - "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", - "version" : "2.3.1" - } - }, - { - "identity" : "realm-core", - "kind" : "remoteSourceControl", - "location" : "https://github.com/realm/realm-core.git", - "state" : { - "revision" : "7227d6a447821c28895daa099b6c7cd4c99d461b", - "version" : "13.25.1" - } - }, - { - "identity" : "realm-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/realm/realm-swift.git", - "state" : { - "revision" : "836cc4b8619886f979f8961c3f592a82b0741591", - "version" : "10.45.3" - } - }, - { - "identity" : "snapkit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SnapKit/SnapKit", - "state" : { - "revision" : "e74fe2a978d1216c3602b129447c7301573cc2d8", - "version" : "5.7.0" - } - }, - { - "identity" : "sparkle", - "kind" : "remoteSourceControl", - "location" : "https://github.com/sparkle-project/Sparkle", - "state" : { - "revision" : "47d3d90aee3c52b6f61d04ceae426e607df62347", - "version" : "2.5.2" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", - "version" : "1.5.3" - } - }, - { - "identity" : "swift-protobuf", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-protobuf.git", - "state" : { - "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", - "version" : "1.25.2" - } - }, - { - "identity" : "swiftshell", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kareman/SwiftShell", - "state" : { - "revision" : "99680b2efc7c7dbcace1da0b3979d266f02e213c", - "version" : "5.1.0" - } - }, - { - "identity" : "ziparchive", - "kind" : "remoteSourceControl", - "location" : "https://github.com/ZipArchive/ZipArchive.git", - "state" : { - "revision" : "79d4dc9729096c6ad83dd3cee2b9f354d1b4ab7b", - "version" : "2.5.5" - } - } - ], - "version" : 2 -}