From f04e65964f5eb53f32a86508cbef57d945b4a96b Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sat, 6 Jan 2024 23:36:26 +0800 Subject: [PATCH 01/18] feat: add service tab screen use SwiftUI --- Easydict.xcodeproj/project.pbxproj | 20 +++++ Easydict/App/Easydict-Bridging-Header.h | 1 + .../Swift/Binding/Binding+DidSet.swift | 24 +++++ Easydict/NewApp/View/ServiceItemView.swift | 40 +++++++++ .../NewApp/View/SettingView/SettingView.swift | 3 + .../View/SettingView/Tabs/ServiceTab.swift | 87 +++++++++++++++++++ 6 files changed, 175 insertions(+) create mode 100644 Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift create mode 100644 Easydict/NewApp/View/ServiceItemView.swift create mode 100644 Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 00aad8201..c54cea561 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -228,6 +228,9 @@ 03FC699A2B39D13A0035D2DA /* EZOpenAIChatResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FC69992B39D13A0035D2DA /* EZOpenAIChatResponse.m */; }; 03FD68BB2B1DC59600FD388E /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 03FD68BA2B1DC59600FD388E /* CryptoSwift */; }; 03FD68BE2B1E151A00FD388E /* String+EncryptAES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */; }; + 0A057D6D2B499A000025C51D /* ServiceTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A057D6C2B499A000025C51D /* ServiceTab.swift */; }; + 0A057D6F2B499A0B0025C51D /* ServiceItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */; }; + 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */; }; 17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; }; 17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; }; 2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; }; @@ -689,6 +692,9 @@ 03FC69992B39D13A0035D2DA /* EZOpenAIChatResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZOpenAIChatResponse.m; sourceTree = ""; }; 03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+EncryptAES.swift"; sourceTree = ""; }; 06E15747A7BD34D510ADC6A8 /* Pods-Easydict.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.debug.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.debug.xcconfig"; sourceTree = ""; }; + 0A057D6C2B499A000025C51D /* ServiceTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTab.swift; sourceTree = ""; }; + 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceItemView.swift; sourceTree = ""; }; + 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Binding+DidSet.swift"; sourceTree = ""; }; 17BCAEF32B0DFF9000A7D372 /* EZNiuTransTranslateResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslateResponse.h; sourceTree = ""; }; 17BCAEF42B0DFF9000A7D372 /* EZNiuTransTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslate.h; sourceTree = ""; }; 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslateResponse.m; sourceTree = ""; }; @@ -1792,6 +1798,7 @@ 03CF88602B137ECB0030C199 /* Swift */ = { isa = PBXGroup; children = ( + 0A2BA95E2B49A967002872A4 /* Binding */, 03FD68BC2B1E14B500FD388E /* String */, 03CF88612B137ED60030C199 /* Array */, ); @@ -1970,6 +1977,14 @@ path = String; sourceTree = ""; }; + 0A2BA95E2B49A967002872A4 /* Binding */ = { + isa = PBXGroup; + children = ( + 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */, + ); + path = Binding; + sourceTree = ""; + }; 17BCAEF22B0DFF9000A7D372 /* Niutrans */ = { isa = PBXGroup; children = ( @@ -2005,6 +2020,7 @@ isa = PBXGroup; children = ( 27FE980A2B3DD5D1000AD654 /* MenuItemView.swift */, + 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */, 27FE98072B3DD52B000AD654 /* SettingView */, ); path = View; @@ -2023,6 +2039,7 @@ isa = PBXGroup; children = ( 278540332B3DE04F004E9488 /* GeneralTab.swift */, + 0A057D6C2B499A000025C51D /* ServiceTab.swift */, 276742042B3DC230002A2C75 /* PrivacyTab.swift */, 276742052B3DC230002A2C75 /* AboutTab.swift */, ); @@ -2516,6 +2533,7 @@ 03991166292A8A4400E1B06D /* EZTitleBarMoveView.m in Sources */, 03542A582937CC3200C34C33 /* EZConfiguration.m in Sources */, 27FE98092B3DD536000AD654 /* SettingView.swift in Sources */, + 0A057D6F2B499A0B0025C51D /* ServiceItemView.swift in Sources */, 035E37E72A0953120061DFAF /* EZToast.m in Sources */, 03542A492937B5CF00C34C33 /* EZGoogleTranslate.m in Sources */, 03D0435A2928C4C800E7559E /* EZWindowManager.m in Sources */, @@ -2582,6 +2600,7 @@ 03B0230529231FA6001C7E63 /* EZButton.m in Sources */, 03B0232329231FA6001C7E63 /* NSString+MM.m in Sources */, 036196772A000F5900806370 /* NSData+CommonCrypto.m in Sources */, + 0A057D6D2B499A000025C51D /* ServiceTab.swift in Sources */, 03882F8D29D95044005B5A52 /* CTView.m in Sources */, 278322602B0FB0EA0026644C /* CaiyunResponse.swift in Sources */, 03B3B8B52925DD3D00168E8D /* EZPopButtonViewController.m in Sources */, @@ -2648,6 +2667,7 @@ 03B0232629231FA6001C7E63 /* NSAttributedString+MM.m in Sources */, 03542A402937B3C900C34C33 /* EZOCRResult.m in Sources */, C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */, + 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */, 036A0DBB2AD941F9006E6D4F /* EZReplaceTextButton.m in Sources */, 03DC7C662A3CA465000BF7C9 /* HWSegmentedControl.m in Sources */, 037E006D2B3DC098006491C6 /* EZOpenAIService+EZPromptMessages.m in Sources */, diff --git a/Easydict/App/Easydict-Bridging-Header.h b/Easydict/App/Easydict-Bridging-Header.h index 2747a587f..9fb49a114 100644 --- a/Easydict/App/Easydict-Bridging-Header.h +++ b/Easydict/App/Easydict-Bridging-Header.h @@ -21,5 +21,6 @@ #import "entry.h" #import "AppDelegate.h" #import "EZConfiguration.h" +#import "EZLocalStorage.h" #import "NSString+EZConvenience.h" diff --git a/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift b/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift new file mode 100644 index 000000000..ef20210c0 --- /dev/null +++ b/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift @@ -0,0 +1,24 @@ +// +// Binding+DidSet.swift +// Easydict +// +// Created by phlpsong on 2024/1/6. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +// Ref https://stackoverflow.com/a/62871938 +// Toggle onChange not trigger issue +extension Binding { + func didSet(execute: @escaping (Value) -> Void) -> Binding { + Binding( + get: { self.wrappedValue }, + set: { + self.wrappedValue = $0 + execute($0) + } + ) + } +} + diff --git a/Easydict/NewApp/View/ServiceItemView.swift b/Easydict/NewApp/View/ServiceItemView.swift new file mode 100644 index 000000000..4807fa7c1 --- /dev/null +++ b/Easydict/NewApp/View/ServiceItemView.swift @@ -0,0 +1,40 @@ +// +// ServiceItemView.swift +// Easydict +// +// Created by phlpsong on 2024/1/6. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +struct ServiceItemView: View { + @Binding var service: QueryService + + var toggleValueChanged: (Bool) -> Void + + var body: some View { + HStack { + Image(nsImage: NSImage(named: service.serviceType().rawValue) ?? NSImage()) + .resizable() + .frame(maxWidth: 24.0, maxHeight: 24.0) + + Text(service.name()) + + Toggle(isOn: $service.enabled.didSet(execute: { value in + toggleValueChanged(value) + })) {} + .toggleStyle(.switch) + } + + .padding(4.0) + } +} + + +#Preview { + let service = EZLocalStorage.shared().allServices(.mini).first + return ServiceItemView(service: .constant(service ?? QueryService())) { val in + print("toggle value changed: \(val)") + } +} diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index 2e5da7bf3..d098543f5 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -15,6 +15,9 @@ struct SettingView: View { GeneralTab() .tabItem { Label("setting_general", systemImage: "gear") } .frame(width: 500, height: 400) + ServiceTab() + .tabItem { Label("service", systemImage: "briefcase") } + .frame(width: 500, height: 400) PrivacyTab() .tabItem { Label("privacy", systemImage: "hand.raised.square") } .frame(width: 500, height: 400) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift new file mode 100644 index 000000000..50dc50be8 --- /dev/null +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -0,0 +1,87 @@ +// +// ServiceTab.swift +// Easydict +// +// Created by phlpsong on 2024/1/6. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +enum ServiceWindowType: Int { + case mini + case fixed + case main +} + +struct ServiceTab: View { + @State private var windowTypeValue = EZWindowType.mini.rawValue + + @State private var serviceTypes: [ServiceType] = [] + + @State private var services: [QueryService] = [] + + var segmentCtrl: some View { + Picker("", selection: $windowTypeValue) { + Text("mini_window") + .tag(EZWindowType.mini.rawValue) + + Text("fixed_window") + .tag(EZWindowType.fixed.rawValue) + + Text("main_window") + .tag(EZWindowType.main.rawValue) + } + .padding() + .pickerStyle(.segmented) + .onChange(of: windowTypeValue) { type in + loadService(type: type) + } + } + + var serviceList: some View { + List { + ForEach(Array(serviceTypes.enumerated()), id: \.offset) { index, _ in + ServiceItemView( + service: $services[index] + ) { isEnable in + serviceToggled(index: index, isEnable: isEnable) + } + } + } + .listStyle(.inset) + .clipShape(RoundedRectangle(cornerRadius: 10.0)) + .padding([.horizontal, .bottom]) + } + + var body: some View { + VStack { + segmentCtrl + + serviceList + } + .onAppear { + loadService(type: windowTypeValue) + } + } + + func loadService(type: Int) { + let windowType = EZWindowType(rawValue: type) ?? .none + serviceTypes = EZLocalStorage.shared().allServiceTypes(windowType) + services = EZLocalStorage.shared().allServices(windowType) + } + + func serviceToggled(index: Int, isEnable: Bool) { + let service = services[index] + service.enabled = isEnable + if isEnable { + service.enabledQuery = true + } + let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none + EZLocalStorage.shared().setService(services[index], windowType: windowType) + } +} + +#Preview { + ServiceTab() +} From f5b6bb13ab68a264687bbcc4fbbb36630d640de9 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sun, 7 Jan 2024 10:31:35 +0800 Subject: [PATCH 02/18] feat: add service list move function --- Easydict.xcodeproj/project.pbxproj | 12 ++++++ Easydict/App/Localizable.xcstrings | 3 ++ .../Swift/Binding/Binding+DidSet.swift | 1 - .../Notification/Notification+Name.swift | 17 ++++++++ Easydict/NewApp/View/ServiceItemView.swift | 1 - .../View/SettingView/Tabs/ServiceTab.swift | 39 +++++++++++++++++++ 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 Easydict/Feature/Utility/Swift/Notification/Notification+Name.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index c54cea561..aea43950e 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -231,6 +231,7 @@ 0A057D6D2B499A000025C51D /* ServiceTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A057D6C2B499A000025C51D /* ServiceTab.swift */; }; 0A057D6F2B499A0B0025C51D /* ServiceItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */; }; 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */; }; + 0A2BA9642B4A3CCD002872A4 /* Notification+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */; }; 17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; }; 17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; }; 2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; }; @@ -695,6 +696,7 @@ 0A057D6C2B499A000025C51D /* ServiceTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTab.swift; sourceTree = ""; }; 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceItemView.swift; sourceTree = ""; }; 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Binding+DidSet.swift"; sourceTree = ""; }; + 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Name.swift"; sourceTree = ""; }; 17BCAEF32B0DFF9000A7D372 /* EZNiuTransTranslateResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslateResponse.h; sourceTree = ""; }; 17BCAEF42B0DFF9000A7D372 /* EZNiuTransTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslate.h; sourceTree = ""; }; 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslateResponse.m; sourceTree = ""; }; @@ -1798,6 +1800,7 @@ 03CF88602B137ECB0030C199 /* Swift */ = { isa = PBXGroup; children = ( + 0A2BA9622B4A3CBB002872A4 /* Notification */, 0A2BA95E2B49A967002872A4 /* Binding */, 03FD68BC2B1E14B500FD388E /* String */, 03CF88612B137ED60030C199 /* Array */, @@ -1985,6 +1988,14 @@ path = Binding; sourceTree = ""; }; + 0A2BA9622B4A3CBB002872A4 /* Notification */ = { + isa = PBXGroup; + children = ( + 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */, + ); + path = Notification; + sourceTree = ""; + }; 17BCAEF22B0DFF9000A7D372 /* Niutrans */ = { isa = PBXGroup; children = ( @@ -2625,6 +2636,7 @@ 039CC90D292F664E0037B91E /* NSObject+EZWindowType.m in Sources */, 03B0232229231FA6001C7E63 /* NSImage+MM.m in Sources */, 03BB2DEF29F59C8A00447EDD /* EZSymbolImageButton.m in Sources */, + 0A2BA9642B4A3CCD002872A4 /* Notification+Name.swift in Sources */, 62A2D03F2A82967F007EEB01 /* EZBingRequest.m in Sources */, 03BDA7BE2A26DA280079D04F /* XPMCountedArgument.m in Sources */, 03D35DAA2AA6C49B00B023FE /* NSString+EZRegex.m in Sources */, diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 0ee5bae52..62c8fd48d 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1,6 +1,9 @@ { "sourceLanguage" : "en", "strings" : { + "" : { + + }, "about" : { "comment" : "about", "localizations" : { diff --git a/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift b/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift index ef20210c0..244b735cb 100644 --- a/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift +++ b/Easydict/Feature/Utility/Swift/Binding/Binding+DidSet.swift @@ -21,4 +21,3 @@ extension Binding { ) } } - diff --git a/Easydict/Feature/Utility/Swift/Notification/Notification+Name.swift b/Easydict/Feature/Utility/Swift/Notification/Notification+Name.swift new file mode 100644 index 000000000..71c773f81 --- /dev/null +++ b/Easydict/Feature/Utility/Swift/Notification/Notification+Name.swift @@ -0,0 +1,17 @@ +// +// Notification+Name.swift +// Easydict +// +// Created by phlpsong on 2024/1/7. +// Copyright © 2024 izual. All rights reserved. +// + +import Foundation + +extension Notification.Name { + static let serviceHasUpdated = Notification.Name(EZServiceHasUpdatedNotification) +} + +@objc public extension NSNotification { + static let serviceHasUpdated = Notification.Name.serviceHasUpdated +} diff --git a/Easydict/NewApp/View/ServiceItemView.swift b/Easydict/NewApp/View/ServiceItemView.swift index 4807fa7c1..e5b0d5eac 100644 --- a/Easydict/NewApp/View/ServiceItemView.swift +++ b/Easydict/NewApp/View/ServiceItemView.swift @@ -31,7 +31,6 @@ struct ServiceItemView: View { } } - #Preview { let service = EZLocalStorage.shared().allServices(.mini).first return ServiceItemView(service: .constant(service ?? QueryService())) { val in diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 50dc50be8..4a5159a60 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -48,6 +48,9 @@ struct ServiceTab: View { serviceToggled(index: index, isEnable: isEnable) } } + .onMove(perform: { indices, newOffset in + onServiceItemMove(fromOffsets: indices, toOffset: newOffset) + }) } .listStyle(.inset) .clipShape(RoundedRectangle(cornerRadius: 10.0)) @@ -79,6 +82,42 @@ struct ServiceTab: View { } let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none EZLocalStorage.shared().setService(services[index], windowType: windowType) + postUpdateServiceNotification() + } + + func enabledServices(in services: [QueryService]) -> [QueryService] { + services.filter(\.enabled) + } + + func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) { + services.move(fromOffsets: fromOffsets, toOffset: toOffset) + serviceTypes.move(fromOffsets: fromOffsets, toOffset: toOffset) + + let oldEnabledServices = enabledServices(in: services) + let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none + EZLocalStorage.shared().setAllServiceTypes(serviceTypes, windowType: windowType) + let newServices = EZLocalStorage.shared().allServices(windowType) + let newEnabledServices = enabledServices(in: newServices) + + if isEnabledServicesOrderChanged(source: oldEnabledServices, dest: newEnabledServices) { + postUpdateServiceNotification() + } + } + + func isEnabledServicesOrderChanged( + source: [QueryService], + dest: [QueryService] + ) -> Bool { + !source.elementsEqual(dest) { sItem, dItem in + sItem.serviceType() == dItem.serviceType() && sItem.name() == dItem.name() + } + } + + func postUpdateServiceNotification() { + let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none + let userInfo: [String: Any] = [EZWindowTypeKey: windowType] + let notification = Notification(name: .serviceHasUpdated, object: nil, userInfo: userInfo) + NotificationCenter.default.post(notification) } } From 7ae9c0adb40dfcf3e6afb788d146956b448eacd3 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sun, 7 Jan 2024 10:46:24 +0800 Subject: [PATCH 03/18] fix: Removed a file change --- Easydict/App/Localizable.xcstrings | 3 --- 1 file changed, 3 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 62c8fd48d..0ee5bae52 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1,9 +1,6 @@ { "sourceLanguage" : "en", "strings" : { - "" : { - - }, "about" : { "comment" : "about", "localizations" : { From f0e7b1117775fc244fce1b41ab7b3d1d34f744a7 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sun, 7 Jan 2024 12:57:22 +0800 Subject: [PATCH 04/18] fix: service list order issue and UI change --- Easydict/NewApp/View/ServiceItemView.swift | 3 ++- Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Easydict/NewApp/View/ServiceItemView.swift b/Easydict/NewApp/View/ServiceItemView.swift index e5b0d5eac..9f34a1740 100644 --- a/Easydict/NewApp/View/ServiceItemView.swift +++ b/Easydict/NewApp/View/ServiceItemView.swift @@ -17,7 +17,7 @@ struct ServiceItemView: View { HStack { Image(nsImage: NSImage(named: service.serviceType().rawValue) ?? NSImage()) .resizable() - .frame(maxWidth: 24.0, maxHeight: 24.0) + .frame(maxWidth: 18.0, maxHeight: 18.0) Text(service.name()) @@ -25,6 +25,7 @@ struct ServiceItemView: View { toggleValueChanged(value) })) {} .toggleStyle(.switch) + .controlSize(.small) } .padding(4.0) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 4a5159a60..d96cc86dc 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -82,6 +82,8 @@ struct ServiceTab: View { } let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none EZLocalStorage.shared().setService(services[index], windowType: windowType) + // refresh service list + loadService(type: windowTypeValue) postUpdateServiceNotification() } @@ -90,15 +92,17 @@ struct ServiceTab: View { } func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) { + let oldEnabledServices = enabledServices(in: services) + services.move(fromOffsets: fromOffsets, toOffset: toOffset) serviceTypes.move(fromOffsets: fromOffsets, toOffset: toOffset) - let oldEnabledServices = enabledServices(in: services) let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none EZLocalStorage.shared().setAllServiceTypes(serviceTypes, windowType: windowType) let newServices = EZLocalStorage.shared().allServices(windowType) let newEnabledServices = enabledServices(in: newServices) + // post notification after enabled services order changed if isEnabledServicesOrderChanged(source: oldEnabledServices, dest: newEnabledServices) { postUpdateServiceNotification() } @@ -114,8 +118,7 @@ struct ServiceTab: View { } func postUpdateServiceNotification() { - let windowType = EZWindowType(rawValue: windowTypeValue) ?? .none - let userInfo: [String: Any] = [EZWindowTypeKey: windowType] + let userInfo: [String: Any] = [EZWindowTypeKey: windowTypeValue] let notification = Notification(name: .serviceHasUpdated, object: nil, userInfo: userInfo) NotificationCenter.default.post(notification) } From 238f524850636ac0d642ee1997c10c15ac00d400 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Sun, 7 Jan 2024 16:25:13 +0800 Subject: [PATCH 05/18] style: format code --- Easydict/App/Localizable.xcstrings | 3 +++ Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 0ee5bae52..62c8fd48d 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1,6 +1,9 @@ { "sourceLanguage" : "en", "strings" : { + "" : { + + }, "about" : { "comment" : "about", "localizations" : { diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index d96cc86dc..96fd368a9 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -93,7 +93,7 @@ struct ServiceTab: View { func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) { let oldEnabledServices = enabledServices(in: services) - + services.move(fromOffsets: fromOffsets, toOffset: toOffset) serviceTypes.move(fromOffsets: fromOffsets, toOffset: toOffset) From cac16393e3aed6952cb9133e661f34ff497d6724 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sun, 7 Jan 2024 17:10:55 +0800 Subject: [PATCH 06/18] fix: change service tab frame size --- Easydict/App/Localizable.xcstrings | 3 --- Easydict/NewApp/View/SettingView/SettingView.swift | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 62c8fd48d..0ee5bae52 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1,9 +1,6 @@ { "sourceLanguage" : "en", "strings" : { - "" : { - - }, "about" : { "comment" : "about", "localizations" : { diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index d098543f5..de1464158 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -17,7 +17,7 @@ struct SettingView: View { .frame(width: 500, height: 400) ServiceTab() .tabItem { Label("service", systemImage: "briefcase") } - .frame(width: 500, height: 400) + .frame(width: 360, height: 540) PrivacyTab() .tabItem { Label("privacy", systemImage: "hand.raised.square") } .frame(width: 500, height: 400) From 2efd70dca51a67ff93976ab7463ecaed99a46886 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Mon, 8 Jan 2024 14:22:00 +0800 Subject: [PATCH 07/18] feat: update the style of service list --- .../Contents.json | 38 +++++++++++++++++++ Easydict/NewApp/View/ServiceItemView.swift | 7 ++-- .../View/SettingView/Tabs/ServiceTab.swift | 26 ++++++++----- 3 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 Easydict/App/Assets.xcassets/service_cell_highlight.colorset/Contents.json diff --git a/Easydict/App/Assets.xcassets/service_cell_highlight.colorset/Contents.json b/Easydict/App/Assets.xcassets/service_cell_highlight.colorset/Contents.json new file mode 100644 index 000000000..f6b481345 --- /dev/null +++ b/Easydict/App/Assets.xcassets/service_cell_highlight.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "0.847", + "red" : "0.706" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.251", + "green" : "0.251", + "red" : "0.251" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Easydict/NewApp/View/ServiceItemView.swift b/Easydict/NewApp/View/ServiceItemView.swift index 9f34a1740..d21f17e98 100644 --- a/Easydict/NewApp/View/ServiceItemView.swift +++ b/Easydict/NewApp/View/ServiceItemView.swift @@ -8,6 +8,7 @@ import SwiftUI +@available(macOS 13.0, *) struct ServiceItemView: View { @Binding var service: QueryService @@ -27,14 +28,14 @@ struct ServiceItemView: View { .toggleStyle(.switch) .controlSize(.small) } - .padding(4.0) } } +@available(macOS 13, *) #Preview { - let service = EZLocalStorage.shared().allServices(.mini).first - return ServiceItemView(service: .constant(service ?? QueryService())) { val in + let service = EZLocalStorage.shared().allServices(.mini).first ?? QueryService() + return ServiceItemView(service: .constant(service)) { val in print("toggle value changed: \(val)") } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 96fd368a9..2cb904369 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -8,18 +8,12 @@ import SwiftUI -enum ServiceWindowType: Int { - case mini - case fixed - case main -} - +@available(macOS 13, *) struct ServiceTab: View { @State private var windowTypeValue = EZWindowType.mini.rawValue - @State private var serviceTypes: [ServiceType] = [] - @State private var services: [QueryService] = [] + @State private var selectedIndex: Int? var segmentCtrl: some View { Picker("", selection: $windowTypeValue) { @@ -47,13 +41,24 @@ struct ServiceTab: View { ) { isEnable in serviceToggled(index: index, isEnable: isEnable) } + .tag(index) + .contentShape(Rectangle()) + .onTapGesture { + if selectedIndex == nil || selectedIndex != index { + selectedIndex = index + } else { + selectedIndex = nil + } + } + .listRowBackground(selectedIndex == index ? Color("service_cell_highlight") : Color.clear) } .onMove(perform: { indices, newOffset in onServiceItemMove(fromOffsets: indices, toOffset: newOffset) }) + .listRowSeparator(.hidden) } - .listStyle(.inset) - .clipShape(RoundedRectangle(cornerRadius: 10.0)) + .listStyle(.plain) + .clipShape(RoundedRectangle(cornerRadius: 8.0)) .padding([.horizontal, .bottom]) } @@ -124,6 +129,7 @@ struct ServiceTab: View { } } +@available(macOS 13, *) #Preview { ServiceTab() } From c9d2d786a09bc38f8650dc135df9394f68d2598b Mon Sep 17 00:00:00 2001 From: tisfeng Date: Mon, 8 Jan 2024 20:27:50 +0800 Subject: [PATCH 08/18] style: auto update Localizable.xcstrings --- Easydict/App/Localizable.xcstrings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 160e6409b..f13b05364 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1,6 +1,9 @@ { "sourceLanguage" : "en", "strings" : { + "" : { + + }, "about" : { "comment" : "about", "localizations" : { From 76cb6d9b4ebf1a7b26f954cbc5269ad8a8d30254 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Mon, 8 Jan 2024 20:30:28 +0800 Subject: [PATCH 09/18] perf: remove unused variables --- Easydict/Feature/StatusItem/EZMenuItemManager.m | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Easydict/Feature/StatusItem/EZMenuItemManager.m b/Easydict/Feature/StatusItem/EZMenuItemManager.m index 7f87b5103..1d47cb1d6 100644 --- a/Easydict/Feature/StatusItem/EZMenuItemManager.m +++ b/Easydict/Feature/StatusItem/EZMenuItemManager.m @@ -16,9 +16,6 @@ #import "EZConfiguration.h" #import "Easydict-Swift.h" -static CGFloat const kImageMenuItemHeightRatio = 1.4; -static CGFloat const kTitleMenuItemHeightRatio = 1.2; - @interface EZMenuItemManager () @property (weak) IBOutlet NSMenu *menu; @@ -96,9 +93,7 @@ - (void)setup { self.appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; self.versionItem.title = self.versionTitle; - - NSArray *items = @[self.versionItem, self.settingsItem, self.checkForUpdateItem, self.helpItem, self.quitItem]; - + [self updateVersionItem]; } From 8c388c10c45f1589c4d66002615a8c525fa27800 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Mon, 8 Jan 2024 21:54:38 +0800 Subject: [PATCH 10/18] fix: service list index of bounds issue and tap issue --- .../View/SettingView/Tabs/ServiceTab.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 2cb904369..bf50b8274 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -34,8 +34,8 @@ struct ServiceTab: View { } var serviceList: some View { - List { - ForEach(Array(serviceTypes.enumerated()), id: \.offset) { index, _ in + List(selection: $selectedIndex) { + ForEach(Array(zip(serviceTypes.indices, serviceTypes)), id: \.0) { index, _ in ServiceItemView( service: $services[index] ) { isEnable in @@ -43,14 +43,14 @@ struct ServiceTab: View { } .tag(index) .contentShape(Rectangle()) - .onTapGesture { - if selectedIndex == nil || selectedIndex != index { - selectedIndex = index - } else { - selectedIndex = nil - } - } - .listRowBackground(selectedIndex == index ? Color("service_cell_highlight") : Color.clear) +// .onTapGesture { +// if selectedIndex == nil || selectedIndex != index { +// selectedIndex = index +// } else { +// selectedIndex = nil +// } +// } +// .listRowBackground(selectedIndex == index ? Color("service_cell_highlight") : Color.clear) } .onMove(perform: { indices, newOffset in onServiceItemMove(fromOffsets: indices, toOffset: newOffset) From ea8c9e0386155fe3c50328bd95799421aed9ade6 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Mon, 8 Jan 2024 22:56:02 +0800 Subject: [PATCH 11/18] fix: serviceTypes count is greater than services count, cause crash --- Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 2cb904369..f67f3bf49 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -75,8 +75,10 @@ struct ServiceTab: View { func loadService(type: Int) { let windowType = EZWindowType(rawValue: type) ?? .none - serviceTypes = EZLocalStorage.shared().allServiceTypes(windowType) services = EZLocalStorage.shared().allServices(windowType) + serviceTypes = services.map { service in + service.serviceType() + } } func serviceToggled(index: Int, isEnable: Bool) { From 2e60d3354c1150e9c436b5664f3937d1c59f7fda Mon Sep 17 00:00:00 2001 From: tisfeng Date: Mon, 8 Jan 2024 23:18:40 +0800 Subject: [PATCH 12/18] perf: adjust service rowHeight to 30 --- Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index f67f3bf49..1ebddfc52 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -41,6 +41,7 @@ struct ServiceTab: View { ) { isEnable in serviceToggled(index: index, isEnable: isEnable) } + .frame(height: 30) .tag(index) .contentShape(Rectangle()) .onTapGesture { @@ -76,9 +77,7 @@ struct ServiceTab: View { func loadService(type: Int) { let windowType = EZWindowType(rawValue: type) ?? .none services = EZLocalStorage.shared().allServices(windowType) - serviceTypes = services.map { service in - service.serviceType() - } + serviceTypes = services.compactMap { $0.serviceType() } } func serviceToggled(index: Int, isEnable: Bool) { From a5e957fcd15265c68c1da3c4f0b3705196f94340 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Mon, 8 Jan 2024 23:27:48 +0800 Subject: [PATCH 13/18] perf: hide scrollIndicators --- Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 1ebddfc52..e0bd91ce7 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -58,6 +58,7 @@ struct ServiceTab: View { }) .listRowSeparator(.hidden) } + .scrollIndicators(.hidden) .listStyle(.plain) .clipShape(RoundedRectangle(cornerRadius: 8.0)) .padding([.horizontal, .bottom]) From e72ef0dd6c2c809dae2ab17ce0c2193d14fe04eb Mon Sep 17 00:00:00 2001 From: phlpsong Date: Mon, 8 Jan 2024 23:43:45 +0800 Subject: [PATCH 14/18] fix: reset service list selection --- Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 881e1875b..59ffe5db1 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -30,6 +30,7 @@ struct ServiceTab: View { .pickerStyle(.segmented) .onChange(of: windowTypeValue) { type in loadService(type: type) + selectedIndex = nil } } @@ -40,6 +41,7 @@ struct ServiceTab: View { service: $services[index] ) { isEnable in serviceToggled(index: index, isEnable: isEnable) + selectedIndex = nil } .frame(height: 30) .tag(index) @@ -55,6 +57,7 @@ struct ServiceTab: View { } .onMove(perform: { indices, newOffset in onServiceItemMove(fromOffsets: indices, toOffset: newOffset) + selectedIndex = nil }) .listRowSeparator(.hidden) } From afbe77531b05d6e54a62fbb9714eb372758e65f3 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Tue, 9 Jan 2024 13:57:01 +0800 Subject: [PATCH 15/18] feat: optimize tab selection window transition --- Easydict.xcodeproj/project.pbxproj | 4 ++ .../NewApp/View/SettingView/SettingView.swift | 39 ++++++++++++++++--- .../View/SettingView/Tabs/AboutTab.swift | 2 + Easydict/NewApp/View/WindowAccessor.swift | 23 +++++++++++ 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 Easydict/NewApp/View/WindowAccessor.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 5f142b1d0..74ad242f6 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -232,6 +232,7 @@ 0A057D6F2B499A0B0025C51D /* ServiceItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */; }; 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */; }; 0A2BA9642B4A3CCD002872A4 /* Notification+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */; }; + 0AC11B222B4D16A500F07198 /* WindowAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */; }; 17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; }; 17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; }; 2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; }; @@ -697,6 +698,7 @@ 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceItemView.swift; sourceTree = ""; }; 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Binding+DidSet.swift"; sourceTree = ""; }; 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Name.swift"; sourceTree = ""; }; + 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowAccessor.swift; sourceTree = ""; }; 17BCAEF32B0DFF9000A7D372 /* EZNiuTransTranslateResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslateResponse.h; sourceTree = ""; }; 17BCAEF42B0DFF9000A7D372 /* EZNiuTransTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslate.h; sourceTree = ""; }; 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslateResponse.m; sourceTree = ""; }; @@ -2032,6 +2034,7 @@ children = ( 27FE980A2B3DD5D1000AD654 /* MenuItemView.swift */, 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */, + 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */, 27FE98072B3DD52B000AD654 /* SettingView */, ); path = View; @@ -2593,6 +2596,7 @@ 033B7134293CE2430096E2DF /* EZWebViewTranslator.m in Sources */, 03CF88632B137F650030C199 /* Array+Convenience.swift in Sources */, 03B0231229231FA6001C7E63 /* NSObject+DarkMode.m in Sources */, + 0AC11B222B4D16A500F07198 /* WindowAccessor.swift in Sources */, 03B0233829231FA6001C7E63 /* MMOrderedDictionary.m in Sources */, 278540342B3DE04F004E9488 /* GeneralTab.swift in Sources */, 03BDA7BC2A26DA280079D04F /* XPMArgumentSignature.m in Sources */, diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index de1464158..fb4105d66 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -8,23 +8,52 @@ import SwiftUI +enum SettingTab: Int { + case general + case service + case privacy + case about +} + @available(macOS 13, *) struct SettingView: View { + @State private var selection = SettingTab.general.rawValue + @State private var window: NSWindow? + var body: some View { - TabView { + TabView(selection: $selection.didSet(execute: { _ in + resizeWindowFrame() + })) { GeneralTab() .tabItem { Label("setting_general", systemImage: "gear") } - .frame(width: 500, height: 400) + .tag(SettingTab.general.rawValue) + ServiceTab() .tabItem { Label("service", systemImage: "briefcase") } - .frame(width: 360, height: 540) + .tag(SettingTab.service.rawValue) + PrivacyTab() .tabItem { Label("privacy", systemImage: "hand.raised.square") } - .frame(width: 500, height: 400) + .tag(SettingTab.privacy.rawValue) + AboutTab() .tabItem { Label("about", systemImage: "info.bubble") } - .frame(width: 500, height: 400) + .tag(SettingTab.about.rawValue) } + .background(WindowAccessor(window: $window)) + } + + func resizeWindowFrame() { + guard let window else { return } + + let originalFrame = window.frame + let newSize = selection == SettingTab.service.rawValue + ? CGSize(width: 360, height: 520) : CGSize(width: 500, height: 400) + + let newY = originalFrame.origin.y + originalFrame.size.height - newSize.height + let newRect = NSRect(origin: CGPoint(x: originalFrame.origin.x, y: newY), size: newSize) + + window.setFrame(newRect, display: true, animate: true) } } diff --git a/Easydict/NewApp/View/SettingView/Tabs/AboutTab.swift b/Easydict/NewApp/View/SettingView/Tabs/AboutTab.swift index 92de82c24..aa6f6a4e4 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/AboutTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/AboutTab.swift @@ -34,7 +34,9 @@ struct AboutTab: View { } .padding(.horizontal, 50) .padding(.vertical, 30) + .frame(maxWidth: .infinity) } + .scrollIndicators(.hidden) .task { let version = await EZMenuItemManager.shared().fetchRepoLatestVersion(EZGithubRepoEasydict) await MainActor.run { diff --git a/Easydict/NewApp/View/WindowAccessor.swift b/Easydict/NewApp/View/WindowAccessor.swift new file mode 100644 index 000000000..b748023cb --- /dev/null +++ b/Easydict/NewApp/View/WindowAccessor.swift @@ -0,0 +1,23 @@ +// +// WindowAccessor.swift +// Easydict +// +// Created by phlpsong on 2024/1/9. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +struct WindowAccessor: NSViewRepresentable { + @Binding var window: NSWindow? + + func makeNSView(context _: Context) -> NSView { + let view = NSView() + DispatchQueue.main.async { + window = view.window + } + return view + } + + func updateNSView(_: NSView, context _: Context) {} +} From 50770c847e5c0785b637fd111ab95b524230202a Mon Sep 17 00:00:00 2001 From: phlpsong Date: Tue, 9 Jan 2024 14:01:45 +0800 Subject: [PATCH 16/18] fix: window frame not reset issue --- Easydict/NewApp/View/SettingView/SettingView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index fb4105d66..4e8f605b3 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -40,7 +40,9 @@ struct SettingView: View { .tabItem { Label("about", systemImage: "info.bubble") } .tag(SettingTab.about.rawValue) } - .background(WindowAccessor(window: $window)) + .background(WindowAccessor(window: $window.didSet(execute: { _ in + resizeWindowFrame() + }))) } func resizeWindowFrame() { From b05f2baf7996c15cd14cca213aefbe2490d6730b Mon Sep 17 00:00:00 2001 From: phlpsong Date: Wed, 10 Jan 2024 14:15:53 +0800 Subject: [PATCH 17/18] fix: onTap conflict with onMove in service tab --- Easydict.xcodeproj/project.pbxproj | 4 ++ .../NewApp/View/SettingView/SettingView.swift | 1 + .../View/SettingView/Tabs/ServiceTab.swift | 26 ++++++----- Easydict/NewApp/View/TapHandlerView.swift | 43 +++++++++++++++++++ 4 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 Easydict/NewApp/View/TapHandlerView.swift diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 74ad242f6..0d7029cbb 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -233,6 +233,7 @@ 0A2BA9602B49A989002872A4 /* Binding+DidSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */; }; 0A2BA9642B4A3CCD002872A4 /* Notification+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */; }; 0AC11B222B4D16A500F07198 /* WindowAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */; }; + 0AC11B242B4E46B300F07198 /* TapHandlerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC11B232B4E46B300F07198 /* TapHandlerView.swift */; }; 17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; }; 17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; }; 2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; }; @@ -699,6 +700,7 @@ 0A2BA95F2B49A989002872A4 /* Binding+DidSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Binding+DidSet.swift"; sourceTree = ""; }; 0A2BA9632B4A3CCD002872A4 /* Notification+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Name.swift"; sourceTree = ""; }; 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowAccessor.swift; sourceTree = ""; }; + 0AC11B232B4E46B300F07198 /* TapHandlerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TapHandlerView.swift; sourceTree = ""; }; 17BCAEF32B0DFF9000A7D372 /* EZNiuTransTranslateResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslateResponse.h; sourceTree = ""; }; 17BCAEF42B0DFF9000A7D372 /* EZNiuTransTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslate.h; sourceTree = ""; }; 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZNiuTransTranslateResponse.m; sourceTree = ""; }; @@ -2035,6 +2037,7 @@ 27FE980A2B3DD5D1000AD654 /* MenuItemView.swift */, 0A057D6E2B499A0B0025C51D /* ServiceItemView.swift */, 0AC11B212B4D16A500F07198 /* WindowAccessor.swift */, + 0AC11B232B4E46B300F07198 /* TapHandlerView.swift */, 27FE98072B3DD52B000AD654 /* SettingView */, ); path = View; @@ -2585,6 +2588,7 @@ 27FE95272B3DC55F000AD654 /* EasydictApp.swift in Sources */, 03882F9129D95044005B5A52 /* CTCommon.m in Sources */, 276742082B3DC230002A2C75 /* PrivacyTab.swift in Sources */, + 0AC11B242B4E46B300F07198 /* TapHandlerView.swift in Sources */, 03882F8F29D95044005B5A52 /* CTScreen.m in Sources */, 27FE980B2B3DD5D1000AD654 /* MenuItemView.swift in Sources */, 03DC7C6A2A3CA852000BF7C9 /* EZAppCell.m in Sources */, diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index 4e8f605b3..8c4fec008 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -41,6 +41,7 @@ struct SettingView: View { .tag(SettingTab.about.rawValue) } .background(WindowAccessor(window: $window.didSet(execute: { _ in + // reset frame when first launch resizeWindowFrame() }))) } diff --git a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift index 59ffe5db1..3da7ca423 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift @@ -14,6 +14,8 @@ struct ServiceTab: View { @State private var serviceTypes: [ServiceType] = [] @State private var services: [QueryService] = [] @State private var selectedIndex: Int? + // workaround for tap gesture conflict with onMove + @State private var isNeedTapHandler = true var segmentCtrl: some View { Picker("", selection: $windowTypeValue) { @@ -35,25 +37,29 @@ struct ServiceTab: View { } var serviceList: some View { - List(selection: $selectedIndex) { + List { ForEach(Array(zip(serviceTypes.indices, serviceTypes)), id: \.0) { index, _ in ServiceItemView( service: $services[index] ) { isEnable in serviceToggled(index: index, isEnable: isEnable) selectedIndex = nil + isNeedTapHandler = false } .frame(height: 30) .tag(index) - .contentShape(Rectangle()) -// .onTapGesture { -// if selectedIndex == nil || selectedIndex != index { -// selectedIndex = index -// } else { -// selectedIndex = nil -// } -// } -// .listRowBackground(selectedIndex == index ? Color("service_cell_highlight") : Color.clear) + .listRowBackground(selectedIndex == index ? Color("service_cell_highlight") : Color.clear) + .overlay(TapHandler(tapAction: { + if !isNeedTapHandler { + isNeedTapHandler.toggle() + return + } + if selectedIndex == nil || selectedIndex != index { + selectedIndex = index + } else { + selectedIndex = nil + } + })) } .onMove(perform: { indices, newOffset in onServiceItemMove(fromOffsets: indices, toOffset: newOffset) diff --git a/Easydict/NewApp/View/TapHandlerView.swift b/Easydict/NewApp/View/TapHandlerView.swift new file mode 100644 index 000000000..5f273e37e --- /dev/null +++ b/Easydict/NewApp/View/TapHandlerView.swift @@ -0,0 +1,43 @@ +// +// TapHandlerView.swift +// Easydict +// +// Created by phlpsong on 2024/1/10. +// Copyright © 2024 izual. All rights reserved. +// + +import SwiftUI + +// Ref: https://stackoverflow.com/a/64194868/8378840 +// Fix conflicts between onTap and onMove modifier +class TapHandlerView: NSView { + var tapAction: () -> Void + + init(_ block: @escaping () -> Void) { + tapAction = block + super.init(frame: .zero) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func mouseDown(with event: NSEvent) { + print("event: \(event)") + super.mouseDown(with: event) + tapAction() + } +} + +struct TapHandler: NSViewRepresentable { + let tapAction: () -> Void + + func makeNSView(context _: Context) -> TapHandlerView { + TapHandlerView(tapAction) + } + + func updateNSView(_ nsView: TapHandlerView, context _: Context) { + nsView.tapAction = tapAction + } +} From 53c393d53fcadf45f62558fd3ec011f115977370 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Sun, 14 Jan 2024 17:31:11 +0800 Subject: [PATCH 18/18] fix: remove tap event print --- Easydict/NewApp/View/TapHandlerView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Easydict/NewApp/View/TapHandlerView.swift b/Easydict/NewApp/View/TapHandlerView.swift index 5f273e37e..39bdff50f 100644 --- a/Easydict/NewApp/View/TapHandlerView.swift +++ b/Easydict/NewApp/View/TapHandlerView.swift @@ -24,7 +24,6 @@ class TapHandlerView: NSView { } override func mouseDown(with event: NSEvent) { - print("event: \(event)") super.mouseDown(with: event) tapAction() }