diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 0feacd3fa..dd2932c73 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -277,6 +277,7 @@ EA9943EE2B5353AB00EE7B97 /* WindowTypeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9943ED2B5353AB00EE7B97 /* WindowTypeExtensions.swift */; }; EA9943F02B5354C400EE7B97 /* ShowWindowPositionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9943EF2B5354C400EE7B97 /* ShowWindowPositionExtensions.swift */; }; EA9943F22B5358BF00EE7B97 /* LanguageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9943F12B5358BF00EE7B97 /* LanguageExtensions.swift */; }; + EAE3D3502B62E9DE001EE3E3 /* GlobalContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE3D34F2B62E9DE001EE3E3 /* GlobalContext.swift */; }; EAED41EC2B54AA920005FE0A /* ServiceConfigurationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAED41EB2B54AA920005FE0A /* ServiceConfigurationSection.swift */; }; EAED41EF2B54B1430005FE0A /* ConfigurableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAED41EE2B54B1430005FE0A /* ConfigurableService.swift */; }; EAED41F22B54B39D0005FE0A /* OpenAIService+ConfigurableService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAED41F12B54B39D0005FE0A /* OpenAIService+ConfigurableService.swift */; }; @@ -772,6 +773,7 @@ EA9943ED2B5353AB00EE7B97 /* WindowTypeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowTypeExtensions.swift; sourceTree = ""; }; EA9943EF2B5354C400EE7B97 /* ShowWindowPositionExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowWindowPositionExtensions.swift; sourceTree = ""; }; EA9943F12B5358BF00EE7B97 /* LanguageExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageExtensions.swift; sourceTree = ""; }; + EAE3D34F2B62E9DE001EE3E3 /* GlobalContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalContext.swift; sourceTree = ""; }; EAED41EB2B54AA920005FE0A /* ServiceConfigurationSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceConfigurationSection.swift; sourceTree = ""; }; EAED41EE2B54B1430005FE0A /* ConfigurableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurableService.swift; sourceTree = ""; }; EAED41F12B54B39D0005FE0A /* OpenAIService+ConfigurableService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenAIService+ConfigurableService.swift"; sourceTree = ""; }; @@ -2230,6 +2232,7 @@ EA9943DD2B534BAE00EE7B97 /* Utility */ = { isa = PBXGroup; children = ( + EAE3D34F2B62E9DE001EE3E3 /* GlobalContext.swift */, EAED41ED2B54B1390005FE0A /* Protocol */, EA9943E62B534D7C00EE7B97 /* Extensions */, ); @@ -2795,6 +2798,7 @@ 0320C5872B29F35700861B3D /* QueryServiceRecord.swift in Sources */, 03FC699A2B39D13A0035D2DA /* EZOpenAIChatResponse.m in Sources */, 03B022FA29231FA6001C7E63 /* EZServiceTypes.m in Sources */, + EAE3D3502B62E9DE001EE3E3 /* GlobalContext.swift in Sources */, EA9943F02B5354C400EE7B97 /* ShowWindowPositionExtensions.swift in Sources */, 03B0233129231FA6001C7E63 /* MMCrash.m in Sources */, 03B0232629231FA6001C7E63 /* NSAttributedString+MM.m in Sources */, diff --git a/Easydict/App/AppDelegate.h b/Easydict/App/AppDelegate.h index d604f4d1b..2ecaff2c6 100644 --- a/Easydict/App/AppDelegate.h +++ b/Easydict/App/AppDelegate.h @@ -7,10 +7,7 @@ // #import -#import @interface AppDelegate : NSObject -@property (weak) IBOutlet SPUStandardUpdaterController *updaterController; - @end diff --git a/Easydict/App/AppDelegate.m b/Easydict/App/AppDelegate.m index 6e6efd49c..ccec0a435 100644 --- a/Easydict/App/AppDelegate.m +++ b/Easydict/App/AppDelegate.m @@ -7,19 +7,12 @@ // #import "AppDelegate.h" -#import "EZMenuItemManager.h" #import "EZShortcut.h" #import "MMCrash.h" -#import "EZWindowManager.h" -#import "EZLanguageManager.h" -#import "EZLog.h" -#import "EZSchemeParser.h" #import "AppDelegate+EZURLScheme.h" -#import -#import #import "Easydict-Swift.h" -@interface AppDelegate () +@interface AppDelegate () @end @@ -99,20 +92,4 @@ - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)applica return NO; } -#pragma mark - SUUpdaterDelegate - -- (NSString *)feedURLStringForUpdater:(SPUUpdater *)updater { - NSString *feedURLString = @"https://raw.githubusercontent.com/tisfeng/Easydict/main/appcast.xml"; -#if DEBUG - feedURLString = @"http://localhost:8000/appcast.xml"; -#endif - return feedURLString; -} - -#pragma mark - SPUStandardUserDriverDelegate - -- (BOOL)supportsGentleScheduledUpdateReminders { - return YES; -} - @end diff --git a/Easydict/App/Base.lproj/Main.storyboard b/Easydict/App/Base.lproj/Main.storyboard index 9df59d2cb..52009ade9 100644 --- a/Easydict/App/Base.lproj/Main.storyboard +++ b/Easydict/App/Base.lproj/Main.storyboard @@ -716,18 +716,8 @@ DQ - - - - - + - - - - - - @@ -799,7 +789,7 @@ DQ - + diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index d96c42854..bb3696775 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -1958,16 +1958,6 @@ } } }, - "other" : { - "localizations" : { - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "其他" - } - } - } - }, "Parameter Error" : { "comment" : "Error description", "localizations" : { @@ -2772,6 +2762,23 @@ } } }, + "setting.general.other.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Other" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "其他" + } + } + } + }, "setting.general.quick_link.header" : { "localizations" : { "en" : { @@ -3443,4 +3450,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} diff --git a/Easydict/Feature/Configuration/Configuration.swift b/Easydict/Feature/Configuration/Configuration.swift index f888889c2..c78b3f2b1 100644 --- a/Easydict/Feature/Configuration/Configuration.swift +++ b/Easydict/Feature/Configuration/Configuration.swift @@ -30,12 +30,6 @@ let kHideMenuBarIconKey = "EZConfiguration_kHideMenuBarIconKey" } } - var appDelegate = NSApp.delegate as? AppDelegate - - var updater: SPUUpdater? { - appDelegate?.updaterController.updater - } - @DefaultsWrapper(.firstLanguage) var firstLanguage: Language @@ -65,10 +59,10 @@ let kHideMenuBarIconKey = "EZConfiguration_kHideMenuBarIconKey" var automaticallyChecksForUpdates: Bool { get { - updater?.automaticallyChecksForUpdates ?? false + GlobalContext.shared.updaterController.updater.automaticallyDownloadsUpdates } set { - updater?.automaticallyChecksForUpdates = newValue + GlobalContext.shared.updaterController.updater.automaticallyDownloadsUpdates = newValue logSettings(["automatically_checks_for_updates": newValue]) } } diff --git a/Easydict/Feature/Configuration/EZConfiguration.h b/Easydict/Feature/Configuration/EZConfiguration.h index 310f47031..266797563 100644 --- a/Easydict/Feature/Configuration/EZConfiguration.h +++ b/Easydict/Feature/Configuration/EZConfiguration.h @@ -9,6 +9,7 @@ #import #import "EZLanguageManager.h" #import "EZLayoutManager.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -84,6 +85,8 @@ typedef NS_ENUM(NSUInteger, EZAppearenceType) { @property (nonatomic, assign) EZAppearenceType appearance; +@property (nonatomic, strong, readonly) SPUUpdater *updater; + + (instancetype)shared; + (void)destroySharedInstance; diff --git a/Easydict/Feature/Configuration/EZConfiguration.m b/Easydict/Feature/Configuration/EZConfiguration.m index e1b40f69b..a3104745a 100644 --- a/Easydict/Feature/Configuration/EZConfiguration.m +++ b/Easydict/Feature/Configuration/EZConfiguration.m @@ -63,7 +63,7 @@ @interface EZConfiguration () @property (nonatomic, strong) AppDelegate *appDelegate; -@property (nonatomic, strong) SPUUpdater *updater; +@property (nonatomic, strong, readwrite) SPUUpdater *updater; @end @@ -142,12 +142,12 @@ - (BOOL)launchAtStartup { return launchAtStartup; } -- (BOOL)automaticallyChecksForUpdates { - return self.updater.automaticallyChecksForUpdates; +- (SPUUpdater *)updater { + return GlobalContext.shared.updaterController.updater; } -- (SPUUpdater *)updater { - return self.appDelegate.updaterController.updater; +- (BOOL)automaticallyChecksForUpdates { + return self.updater.automaticallyChecksForUpdates; } #pragma mark - setter diff --git a/Easydict/Feature/PerferenceWindow/DisableAutoSelectTextViewController/EZDisableAutoSelectTextViewController.m b/Easydict/Feature/PerferenceWindow/DisableAutoSelectTextViewController/EZDisableAutoSelectTextViewController.m index 86a5c8e56..8df326346 100644 --- a/Easydict/Feature/PerferenceWindow/DisableAutoSelectTextViewController/EZDisableAutoSelectTextViewController.m +++ b/Easydict/Feature/PerferenceWindow/DisableAutoSelectTextViewController/EZDisableAutoSelectTextViewController.m @@ -57,7 +57,7 @@ - (void)viewDidLoad { } - (void)setup { - self.appModelList = [[EZLocalStorage.shared selectTextTypeAppModelList] mutableCopy]; + [self setupAppModelList]; [self.titleTextField mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.right.inset(kMargin + 5); // ???: Why is the actual inset is 18? @@ -78,6 +78,18 @@ - (void)setup { }]; } +- (void)setupAppModelList { + self.appModelList = [[NSMutableArray alloc] init]; + NSArray *allAppModelList = [EZLocalStorage.shared selectTextTypeAppModelList]; + NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; + for (EZAppModel *appModel in allAppModelList) { + NSURL *appURL = [workspace URLForApplicationWithBundleIdentifier:appModel.appBundleID]; + if (appURL) { + [self.appModelList addObject:appModel]; + } + } +} + #pragma mark - Getter && Setter diff --git a/Easydict/Feature/Service/Apple/EZAppleService.m b/Easydict/Feature/Service/Apple/EZAppleService.m index be76679f2..e2a681b15 100644 --- a/Easydict/Feature/Service/Apple/EZAppleService.m +++ b/Easydict/Feature/Service/Apple/EZAppleService.m @@ -24,7 +24,7 @@ static NSArray *const kAllowedCharactersInPoetryList = @[ @"《", @"》", @"〔", @"〕" ]; -static CGFloat const kParagraphLineHeightRatio = 1.2; +static CGFloat const kParagraphLineHeightRatio = 1.5; static NSInteger const kShortPoetryCharacterCountOfLine = 12; @@ -1211,18 +1211,6 @@ - (void)setupOCRResult:(EZOCRResult *)ocrResult CGFloat deltaY = prevBoundingBox.origin.y - (boundingBox.origin.y + boundingBox.size.height); CGFloat deltaX = boundingBox.origin.x - (prevBoundingBox.origin.x + prevBoundingBox.size.width); - // Note that line spacing is inaccurate, sometimes it's too small 😢 - BOOL isNewParagraph = NO; - if (deltaY > 0) { - // averageLineSpacing may too small, so deltaY should be much larger than averageLineSpacing - BOOL isBigLineSpacing = [self isBigSpacingLineOfTextObservation:textObservation - prevTextObservation:prevTextObservation - greaterThanLineHeightRatio:kParagraphLineHeightRatio]; - if (isBigLineSpacing) { - isNewParagraph = YES; - } - } - // Note that sometimes the line frames will overlap a little, then deltaY will less then 0 BOOL isNewLine = NO; if (deltaY > 0) { @@ -1251,10 +1239,9 @@ - (void)setupOCRResult:(EZOCRResult *)ocrResult if (isNeedRemoveLastDashOfText) { mergedText = [mergedText substringToIndex:mergedText.length - 1].mutableCopy; } - } else if (isNewParagraph || isNewLine) { + } else if (isNewLine) { joinedString = [self joinedStringOfTextObservation:textObservation - prevTextObservation:prevTextObservation - isNewParagraph:isNewParagraph]; + prevTextObservation:prevTextObservation]; } else { joinedString = @" "; // if the same line, just join two texts } @@ -1489,9 +1476,10 @@ - (BOOL)isPoetryOftextObservations:(NSArray *)tex /// Get joined string of text, according to its last char. - (NSString *)joinedStringOfTextObservation:(VNRecognizedTextObservation *)textObservation prevTextObservation:(VNRecognizedTextObservation *)prevTextObservation - isNewParagraph:(BOOL)isNewParagraph { +{ NSString *joinedString = @""; BOOL needLineBreak = NO; + BOOL isNewParagraph = NO; CGRect prevBoundingBox = prevTextObservation.boundingBox; CGFloat prevLineLength = prevBoundingBox.size.width; @@ -1509,7 +1497,7 @@ - (NSString *)joinedStringOfTextObservation:(VNRecognizedTextObservation *)textO BOOL hasPrevIndentation = [self hasIndentationOfTextObservation:prevTextObservation]; BOOL hasIndentation = [self hasIndentationOfTextObservation:textObservation]; - + BOOL isPrevLongText = [self isLongTextObservation:prevTextObservation isStrict:NO]; BOOL isEqualChineseText = [self isEqualChineseTextObservation:textObservation prevTextObservation:prevTextObservation]; @@ -1895,6 +1883,20 @@ - (BOOL)hasIndentationOfTextObservation:(VNRecognizedTextObservation *)textObser return hasIndentation; } +- (BOOL)hasIndentationOfTextObservation:(VNRecognizedTextObservation *)textObservation + prevTextObservation:(VNRecognizedTextObservation *)prevTextObservation { + BOOL isEqualX = [self isEqualXOfTextObservation:textObservation prevTextObservation:prevTextObservation]; + + CGFloat lineX = CGRectGetMinX(textObservation.boundingBox); + CGFloat prevLineX = CGRectGetMinX(prevTextObservation.boundingBox); + CGFloat dx = lineX - prevLineX; + + if (!isEqualX && dx < 0) { + return YES; + } + return NO; +} + - (BOOL)isEqualTextObservation:(VNRecognizedTextObservation *)textObservation prevTextObservation:(VNRecognizedTextObservation *)prevTextObservation { // 0.06 - 0.025 diff --git a/Easydict/Feature/Service/DeepL/EZDeepLTranslate.m b/Easydict/Feature/Service/DeepL/EZDeepLTranslate.m index 44007d5ad..576c5de8c 100644 --- a/Easydict/Feature/Service/DeepL/EZDeepLTranslate.m +++ b/Easydict/Feature/Service/DeepL/EZDeepLTranslate.m @@ -390,7 +390,6 @@ - (void)deepLTranslate:(NSString *)text from:(EZLanguage)from to:(EZLanguage)to } */ NSString *translatedText = [responseObject[@"translations"] firstObject][@"text"]; - translatedText = [translatedText.trim removeExtraLineBreaks]; NSArray *translatedTextArray = [translatedText toParagraphs]; return translatedTextArray; diff --git a/Easydict/Feature/Service/Tencent/TencentTranslateType.swift b/Easydict/Feature/Service/Tencent/TencentTranslateType.swift index 84ac8b712..ca8bcd91b 100644 --- a/Easydict/Feature/Service/Tencent/TencentTranslateType.swift +++ b/Easydict/Feature/Service/Tencent/TencentTranslateType.swift @@ -14,24 +14,24 @@ struct TencentTranslateType: Equatable { static let unsupported = TencentTranslateType(sourceLanguage: "unsupported", targetLanguage: "unsupported") - // This docs missed traditionalChinese as target language if target languages contains simplifiedChinese. https://cloud.tencent.com/document/api/551/15619 + // https://cloud.tencent.com/document/api/551/15619 static let supportedTypes: [Language: [Language]] = [ .simplifiedChinese: [.english, .japanese, .korean, .french, .spanish, .italian, .german, .turkish, .russian, .portuguese, .vietnamese, .indonesian, .thai, .malay], .traditionalChinese: [.english, .japanese, .korean, .french, .spanish, .italian, .german, .turkish, .russian, .portuguese, .vietnamese, .indonesian, .thai, .malay], - .english: [.simplifiedChinese, .japanese, .korean, .french, .spanish, .italian, .german, .turkish, .russian, .portuguese, .vietnamese, .indonesian, .thai, .malay, .arabic, .hindi], - .japanese: [.simplifiedChinese, .english, .korean], - .korean: [.simplifiedChinese, .english, .japanese], - .french: [.simplifiedChinese, .english, .spanish, .italian, .german, .turkish, .russian, .portuguese], - .spanish: [.simplifiedChinese, .english, .french, .italian, .german, .turkish, .russian, .portuguese], - .italian: [.simplifiedChinese, .english, .french, .spanish, .german, .turkish, .russian, .portuguese], - .german: [.simplifiedChinese, .english, .french, .spanish, .italian, .turkish, .russian, .portuguese], - .turkish: [.simplifiedChinese, .english, .french, .spanish, .italian, .german, .russian, .portuguese], - .russian: [.simplifiedChinese, .english, .french, .spanish, .italian, .german, .turkish, .portuguese], - .portuguese: [.simplifiedChinese, .english, .french, .spanish, .italian, .german, .turkish, .russian], - .vietnamese: [.simplifiedChinese, .english], - .indonesian: [.simplifiedChinese, .english], - .thai: [.simplifiedChinese, .english], - .malay: [.simplifiedChinese, .english], + .english: [.simplifiedChinese, .traditionalChinese, .japanese, .korean, .french, .spanish, .italian, .german, .turkish, .russian, .portuguese, .vietnamese, .indonesian, .thai, .malay, .arabic, .hindi], + .japanese: [.simplifiedChinese, .traditionalChinese, .english, .korean], + .korean: [.simplifiedChinese, .traditionalChinese, .english, .japanese], + .french: [.simplifiedChinese, .traditionalChinese, .english, .spanish, .italian, .german, .turkish, .russian, .portuguese], + .spanish: [.simplifiedChinese, .traditionalChinese, .english, .french, .italian, .german, .turkish, .russian, .portuguese], + .italian: [.simplifiedChinese, .traditionalChinese, .english, .french, .spanish, .german, .turkish, .russian, .portuguese], + .german: [.simplifiedChinese, .traditionalChinese, .english, .french, .spanish, .italian, .turkish, .russian, .portuguese], + .turkish: [.simplifiedChinese, .traditionalChinese, .english, .french, .spanish, .italian, .german, .russian, .portuguese], + .russian: [.simplifiedChinese, .traditionalChinese, .english, .french, .spanish, .italian, .german, .turkish, .portuguese], + .portuguese: [.simplifiedChinese, .traditionalChinese, .english, .french, .spanish, .italian, .german, .turkish, .russian], + .vietnamese: [.simplifiedChinese, .traditionalChinese, .english], + .indonesian: [.simplifiedChinese, .traditionalChinese, .english], + .thai: [.simplifiedChinese, .traditionalChinese, .english], + .malay: [.simplifiedChinese, .traditionalChinese, .english], .arabic: [.english], .hindi: [.english], ] @@ -59,9 +59,16 @@ struct TencentTranslateType: Equatable { ] static func transType(from: Language, to: Language) -> TencentTranslateType { - // !!!: Tencent translate support traditionalChinese as target language if target languages contain simplifiedChinese. + /** + 1. zh <--> zh-TW + 2. zh --> zh + + Tencent Translate supports Simplified Chinese and Traditional Chinese translations of each other, but the documentation doesn't mention this, so we need to handle it ourselves. + + In addition, it also supports one language as both source and target language if the language is supported. + */ guard let targetLanguages = supportedTypes[from], - targetLanguages.containsChinese() || targetLanguages.contains(to) || from == to || from.isKindOfChinese() + targetLanguages.contains(to) || from == to || EZLanguageManager.shared().onlyContainsChineseLanguages([from, to]) else { return .unsupported } diff --git a/Easydict/Feature/StatusItem/EZMenuItemManager.m b/Easydict/Feature/StatusItem/EZMenuItemManager.m index 8d9f3b017..9f40e3fc9 100644 --- a/Easydict/Feature/StatusItem/EZMenuItemManager.m +++ b/Easydict/Feature/StatusItem/EZMenuItemManager.m @@ -15,6 +15,8 @@ #import "EZRightClickDetector.h" #import "EZConfiguration.h" #import "Easydict-Swift.h" +#import +#import @interface EZMenuItemManager () @@ -181,6 +183,11 @@ - (IBAction)settingAction:(NSMenuItem *)sender { [EZPreferencesWindowController.shared show]; } +- (IBAction)checkForUpdateItem:(id)sender { + NSLog(@"checkForUpdate"); + [EZConfiguration.shared.updater checkForUpdates]; +} + - (IBAction)feedbackAction:(NSMenuItem *)sender { NSLog(@"反馈问题"); NSString *issueURL = [NSString stringWithFormat:@"%@/issues", EZGithubRepoEasydictURL]; diff --git a/Easydict/NewApp/EasydictApp.swift b/Easydict/NewApp/EasydictApp.swift index c81ba83f4..bb3e1be41 100644 --- a/Easydict/NewApp/EasydictApp.swift +++ b/Easydict/NewApp/EasydictApp.swift @@ -6,6 +6,7 @@ // Copyright © 2023 izual. All rights reserved. // +import Defaults import Sparkle import SwiftUI @@ -21,28 +22,14 @@ enum EasydictCmpatibilityEntry { } } -class SPUUpdaterHelper: NSObject, SPUUpdaterDelegate { - func feedURLString(for _: SPUUpdater) -> String? { - var feedURLString = "https://raw.githubusercontent.com/tisfeng/Easydict/main/appcast.xml" - #if DEBUG - feedURLString = "http://localhost:8000/appcast.xml" - #endif - return feedURLString - } -} - -class SPUUserDriverHelper: NSObject, SPUStandardUserDriverDelegate { - var supportsGentleScheduledUpdateReminders: Bool { - true - } -} - struct EasydictApp: App { @NSApplicationDelegateAdaptor - var delegate: AppDelegate + private var delegate: AppDelegate - @AppStorage(kHideMenuBarIconKey) - private var hideMenuBar = false + // Use `@Default` will cause a purple warning and continuously call `set` of it. + // I'm not sure why. Just leave `AppStorage` here. + @AppStorage(Defaults.Key.hideMenuBarIcon.name) + private var hideMenuBar = Defaults.Key.hideMenuBarIcon.defaultValue private var menuBarImage: String { #if DEBUG @@ -52,22 +39,10 @@ struct EasydictApp: App { #endif } - let userDriverHelper = SPUUserDriverHelper() - let upadterHelper = SPUUpdaterHelper() - - private let updaterController: SPUStandardUpdaterController - - init() { - // 参考 https://sparkle-project.org/documentation/programmatic-setup/ - // 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) - } - var body: some Scene { if #available(macOS 13, *) { MenuBarExtra(isInserted: $hideMenuBar.toggledValue) { - MenuItemView(updater: updaterController.updater) + MenuItemView() } label: { Label { Text("Easydict") diff --git a/Easydict/NewApp/Utility/GlobalContext.swift b/Easydict/NewApp/Utility/GlobalContext.swift new file mode 100644 index 000000000..557c22ae1 --- /dev/null +++ b/Easydict/NewApp/Utility/GlobalContext.swift @@ -0,0 +1,43 @@ +// +// GlobalContext.swift +// Easydict +// +// Created by 戴藏龙 on 2024/1/25. +// Copyright © 2024 izual. All rights reserved. +// + +import Foundation +import Sparkle + +@objcMembers +class GlobalContext: NSObject { + static let shared = GlobalContext() + + let updaterController: SPUStandardUpdaterController + + private let updaterHelper: SPUUpdaterHelper + private let userDriverHelper: SPUUserDriverHelper + + override init() { + updaterHelper = SPUUpdaterHelper() + userDriverHelper = SPUUserDriverHelper() + + updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: updaterHelper, userDriverDelegate: userDriverHelper) + } + + class SPUUpdaterHelper: NSObject, SPUUpdaterDelegate { + func feedURLString(for _: SPUUpdater) -> String? { + var feedURLString = "https://raw.githubusercontent.com/tisfeng/Easydict/main/appcast.xml" + #if DEBUG + feedURLString = "http://localhost:8000/appcast.xml" + #endif + return feedURLString + } + } + + class SPUUserDriverHelper: NSObject, SPUStandardUserDriverDelegate { + var supportsGentleScheduledUpdateReminders: Bool { + true + } + } +} diff --git a/Easydict/NewApp/View/MenuItemView.swift b/Easydict/NewApp/View/MenuItemView.swift index 5f25919b1..65a264c59 100644 --- a/Easydict/NewApp/View/MenuItemView.swift +++ b/Easydict/NewApp/View/MenuItemView.swift @@ -13,21 +13,19 @@ import ZipArchive @available(macOS 13, *) final class MenuItemStore: ObservableObject { @Published var canCheckForUpdates = false - var updater: SPUUpdater - init(updater: SPUUpdater) { - self.updater = updater - self.updater.publisher(for: \.canCheckForUpdates) + + init() { + GlobalContext.shared + .updaterController + .updater + .publisher(for: \.canCheckForUpdates) .assign(to: &$canCheckForUpdates) } } @available(macOS 13, *) struct MenuItemView: View { - @ObservedObject var store: MenuItemStore - - init(updater: SPUUpdater) { - store = MenuItemStore(updater: updater) - } + @ObservedObject private var store = MenuItemStore() var body: some View { // ️.menuBarExtraStyle为 .menu 时某些控件可能会失效 ,只能显示内容(按照菜单项高度、图像以 template 方式渲染)无法交互 ,比如 Stepper、Slider 等,像基本的 Button、Text、Divider、Image 等还是能正常显示的。 @@ -173,7 +171,7 @@ struct MenuItemView: View { private var checkUpdateItem: some View { Button("check_updates") { NSLog("检查更新") - store.updater.checkForUpdates() + GlobalContext.shared.updaterController.updater.checkForUpdates() }.disabled(!store.canCheckForUpdates) } @@ -225,5 +223,5 @@ struct MenuItemView: View { @available(macOS 13, *) #Preview { - MenuItemView(updater: SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil).updater) + MenuItemView() } diff --git a/Easydict/NewApp/View/SettingView/SettingView.swift b/Easydict/NewApp/View/SettingView/SettingView.swift index ec5c395ab..81333b8ee 100644 --- a/Easydict/NewApp/View/SettingView/SettingView.swift +++ b/Easydict/NewApp/View/SettingView/SettingView.swift @@ -36,7 +36,7 @@ struct SettingView: View { .tabItem { Label("disabled_app_list", systemImage: "nosign") } .tag(SettingTab.disabled) AdvancedTab() - .tabItem { Label("advanced", systemImage: "wrench.and.screwdriver") } + .tabItem { Label("advanced", systemImage: "gearshape.2") } .tag(SettingTab.advanced) PrivacyTab() diff --git a/Easydict/NewApp/View/SettingView/Tabs/DisabledAppTab.swift b/Easydict/NewApp/View/SettingView/Tabs/DisabledAppTab.swift index d45ba5a44..ece9cc335 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/DisabledAppTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/DisabledAppTab.swift @@ -25,7 +25,12 @@ private class DisabledAppViewModel: ObservableObject { } func fetchDisabledApps() { - appModelList = EZLocalStorage.shared().selectTextTypeAppModelList + let allAppModelList = EZLocalStorage.shared().selectTextTypeAppModelList + + appModelList = allAppModelList.compactMap { appModel in + let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: appModel.appBundleID) + return url == nil ? nil : appModel + } } func saveDisabledApps() { diff --git a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift index 6471771c1..26e427fee 100644 --- a/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift +++ b/Easydict/NewApp/View/SettingView/Tabs/GeneralTab.swift @@ -137,7 +137,7 @@ struct GeneralTab: View { Text("hide_menu_bar_icon") } } header: { - Text("other") + Text("setting.general.other.header") } } .formStyle(.grouped)