diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 663778224..b6da03de7 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -245,6 +245,7 @@ C98CAE75239F4619005F7DCA /* EasydictHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = C90BE309239F38EB00ADE88B /* EasydictHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 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 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -712,6 +713,7 @@ C99EEB182385796700FEE666 /* Easydict-debug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Easydict-debug.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1227,6 +1229,7 @@ 03542A572937CC3200C34C33 /* EZConfiguration.m */, 03D8A65A2A433B4100D9A968 /* EZConfiguration+EZUserData.h */, 03D8A65B2A433B4100D9A968 /* EZConfiguration+EZUserData.m */, + DC6D9C882B3969510055EFFC /* Appearance.swift */, ); path = Configuration; sourceTree = ""; @@ -2550,6 +2553,7 @@ 03BDA7BE2A26DA280079D04F /* XPMCountedArgument.m in Sources */, 03D35DAA2AA6C49B00B023FE /* NSString+EZRegex.m in Sources */, 03B022FE29231FA6001C7E63 /* EZBaseQueryViewController.m in Sources */, + DC6D9C892B3969510055EFFC /* Appearance.swift in Sources */, 0396D611292C932F006A11D9 /* EZSelectLanguageCell.m in Sources */, 036196752A000F5900806370 /* FWEncryptorAES.m in Sources */, 0399C6A829A74E0F00B4AFCC /* EZQueryResult+EZDeepLTranslateResponse.m in Sources */, diff --git a/Easydict/App/Localizable.xcstrings b/Easydict/App/Localizable.xcstrings index 3cad0f617..cf9787fae 100644 --- a/Easydict/App/Localizable.xcstrings +++ b/Easydict/App/Localizable.xcstrings @@ -110,6 +110,70 @@ } } }, + "app_appearance" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appearance:" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "外观:" + } + } + } + }, + "appearenceType_dark" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dark" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "深色模式" + } + } + } + }, + "appearenceType_followSystem" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Follow System" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "跟随系统" + } + } + } + }, + "appearenceType_light" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Light" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "浅色模式" + } + } + } + }, "Apple" : { "extractionState" : "manual", "localizations" : { diff --git a/Easydict/Feature/Configuration/Appearance.swift b/Easydict/Feature/Configuration/Appearance.swift new file mode 100644 index 000000000..3a59f1124 --- /dev/null +++ b/Easydict/Feature/Configuration/Appearance.swift @@ -0,0 +1,54 @@ +// +// Appearance.swift +// Easydict +// +// Created by yqing on 2023/12/25. +// Copyright © 2023 izual. All rights reserved. +// + +import Foundation + +@objc enum AppearenceType: Int, CaseIterable { + case followSystem = 0 + case light + case dark + + var title: String { + switch self { + case .followSystem: + return NSLocalizedString("appearenceType_followSystem", comment: "") + case .light: + return NSLocalizedString("appearenceType_light", comment: "") + case .dark: + return NSLocalizedString("appearenceType_dark", comment: "") + } + } + + var appearence: NSAppearance? { + switch self { + case .followSystem: + return nil + case .light: + return NSAppearance(named: .aqua) + case .dark: + return NSAppearance(named: .darkAqua) + } + } + + static func titles() -> [String] { + let array = AppearenceType.allCases.map(\.title) + return array + } +} + +@objcMembers class AppearenceHelper: NSObject { + static let shared = AppearenceHelper() + + func titles() -> [String] { + AppearenceType.titles() + } + + func updateAppApperance(_ apperanceType: AppearenceType) { + NSApplication.shared.appearance = apperanceType.appearence + } +} diff --git a/Easydict/Feature/Configuration/EZConfiguration.h b/Easydict/Feature/Configuration/EZConfiguration.h index d9722a539..eabee5f8b 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 "Easydict-Swift.h" NS_ASSUME_NONNULL_BEGIN @@ -75,6 +76,8 @@ typedef NS_ENUM(NSUInteger, EZLanguageDetectOptimize) { @property (nonatomic, assign, readonly) CGFloat fontSizeRatio; @property (nonatomic, assign) NSInteger fontSizeIndex; +@property (nonatomic, assign) AppearenceType appearance; + + (instancetype)shared; + (void)destroySharedInstance; diff --git a/Easydict/Feature/Configuration/EZConfiguration.m b/Easydict/Feature/Configuration/EZConfiguration.m index 01042f008..2331900a6 100644 --- a/Easydict/Feature/Configuration/EZConfiguration.m +++ b/Easydict/Feature/Configuration/EZConfiguration.m @@ -17,6 +17,7 @@ #import "EZLanguageManager.h" #import "AppDelegate.h" #import "Easydict-Swift.h" +#import "DarkModeManager.h" static NSString *const kEasydictHelperBundleId = @"com.izual.EasydictHelper"; @@ -52,6 +53,7 @@ static NSString *const kAllowAnalyticsKey = @"EZConfiguration_kAllowAnalyticsKey"; static NSString *const kClearInputKey = @"EZConfiguration_kClearInputKey"; static NSString *const kTranslationControllerFontKey = @"EZConfiguration_kTranslationControllerFontKey"; +static NSString *const kApperanceKey = @"EZConfiguration_kApperanceKey"; NSString *const kHideMainWindowKey = @"EZConfiguration_kHideMainWindowKey"; NSString *const kLaunchAtStartupKey = @"EZConfiguration_kLaunchAtStartupKey"; @@ -130,6 +132,7 @@ - (void)setup { _fontSizeIndex = [[NSUserDefaults standardUserDefaults]integerForKey:kTranslationControllerFontKey]; + self.appearance = [NSUserDefaults mm_readInteger:kApperanceKey defaultValue:AppearenceTypeFollowSystem]; } #pragma mark - getter @@ -447,6 +450,15 @@ - (CGFloat)fontSizeRatio { return _fontSizes[_fontSizeIndex].floatValue; } +- (void)setAppearance:(AppearenceType)appearance { + _appearance = appearance; + + [NSUserDefaults mm_write:@(appearance) forKey:kApperanceKey]; + + [[DarkModeManager manager] updateDarkMode]; + +} + #pragma mark - Window Frame - (CGRect)windowFrameWithType:(EZWindowType)windowType { diff --git a/Easydict/Feature/DarkMode/DarkModeManager.h b/Easydict/Feature/DarkMode/DarkModeManager.h index c9b74b551..722bee8a3 100644 --- a/Easydict/Feature/DarkMode/DarkModeManager.h +++ b/Easydict/Feature/DarkMode/DarkModeManager.h @@ -18,6 +18,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)manager; - (void)excuteLight:(void (^)(void))light dark:(void (^)(void))dark; +- (void)updateDarkMode; + @end NS_ASSUME_NONNULL_END diff --git a/Easydict/Feature/DarkMode/DarkModeManager.m b/Easydict/Feature/DarkMode/DarkModeManager.m index e132d044c..16d267140 100644 --- a/Easydict/Feature/DarkMode/DarkModeManager.m +++ b/Easydict/Feature/DarkMode/DarkModeManager.m @@ -7,7 +7,7 @@ // #import "DarkModeManager.h" - +#import "EZConfiguration.h" @interface DarkModeManager () @@ -21,7 +21,6 @@ @implementation DarkModeManager singleton_m(DarkModeManager); + (void)load { - [[self manager] setup]; [[self manager] monitor]; } @@ -40,11 +39,6 @@ - (void)excuteLight:(void (^)(void))light dark:(void (^)(void))dark { }]; } -- (void)setup { - [self updateDarkMode]; -} - - - (void)monitor { NSString *const darkModeNotificationName = @"AppleInterfaceThemeChangedNotification"; [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDarkMode) name:darkModeNotificationName object:nil]; @@ -53,7 +47,22 @@ - (void)monitor { - (void)updateDarkMode { BOOL isDarkMode = [self isDarkMode]; NSLog(@"%@", isDarkMode ? @"深色模式" : @"浅色模式"); - self.systemDarkMode = isDarkMode; + + switch (EZConfiguration.shared.appearance) { + case AppearenceTypeDark: + self.systemDarkMode = true; + break; + case AppearenceTypeLight: + self.systemDarkMode = false; + break; + case AppearenceTypeFollowSystem: + self.systemDarkMode = isDarkMode; + break; + default: + break; + } + [AppearenceHelper.shared updateAppApperance:EZConfiguration.shared.appearance]; + } - (BOOL)isDarkMode { diff --git a/Easydict/Feature/PerferenceWindow/EZSettingViewController.m b/Easydict/Feature/PerferenceWindow/EZSettingViewController.m index 5865ac739..3e0094572 100644 --- a/Easydict/Feature/PerferenceWindow/EZSettingViewController.m +++ b/Easydict/Feature/PerferenceWindow/EZSettingViewController.m @@ -35,6 +35,9 @@ @interface EZSettingViewController () @property (nonatomic, strong) MMOrderedDictionary *allLanguageDict; +@property (nonatomic, strong) NSTextField *apperanceLabel; +@property (nonatomic, strong) NSPopUpButton *apperancePopUpButton; + @property (nonatomic, strong) NSTextField *firstLanguageLabel; @property (nonatomic, strong) NSPopUpButton *firstLanguagePopUpButton; @property (nonatomic, strong) NSTextField *secondLanguageLabel; @@ -146,7 +149,6 @@ @implementation EZSettingViewController return _enabledTTSServiceTypes; } - - (void)viewDidLoad { [super viewDidLoad]; // Do view setup here. @@ -241,6 +243,18 @@ - (void)setupUI { self.firstLanguagePopUpButton.target = self; self.firstLanguagePopUpButton.action = @selector(firstLangaugePopUpButtonClicked:); + NSTextField *apperanceLabel = [NSTextField labelWithString:NSLocalizedString(@"app_appearance", nil)]; + apperanceLabel.font = font; + [self.contentView addSubview:apperanceLabel]; + self.apperanceLabel = apperanceLabel; + + self.apperancePopUpButton = [[NSPopUpButton alloc] init]; + [self.contentView addSubview:self.apperancePopUpButton]; + [self.apperancePopUpButton addItemsWithTitles:[AppearenceHelper shared].titles]; + [self.apperancePopUpButton selectItemAtIndex:self.config.appearance]; + self.apperancePopUpButton.target = self; + self.apperancePopUpButton.action = @selector(appearancePopUpButtonClicked:); + NSTextField *secondLanguageLabel = [NSTextField labelWithString:NSLocalizedString(@"second_language", nil)]; secondLanguageLabel.font = font; [self.contentView addSubview:secondLanguageLabel]; @@ -607,10 +621,19 @@ - (void)updateViewConstraints { make.height.mas_equalTo(1); }]; - [self.firstLanguageLabel mas_remakeConstraints:^(MASConstraintMaker *make) { + [self.apperanceLabel mas_remakeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.selectLabel); make.top.equalTo(self.separatorView.mas_bottom).offset(1.5 * self.verticalPadding); }]; + [self.apperancePopUpButton mas_remakeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.apperanceLabel.mas_right).offset(self.horizontalPadding); + make.centerY.equalTo(self.apperanceLabel); + }]; + + [self.firstLanguageLabel mas_remakeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.selectLabel); + make.top.equalTo(self.apperanceLabel.mas_bottom).offset(self.verticalPadding); + }]; [self.firstLanguagePopUpButton mas_remakeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.firstLanguageLabel.mas_right).offset(self.horizontalPadding); make.centerY.equalTo(self.firstLanguageLabel); @@ -1075,6 +1098,12 @@ - (void)updatePreferredLanguagesPopUpButton { [self.secondLanguagePopUpButton selectItemAtIndex:secondLanguageIndex]; } +#pragma mark - Appearance +- (void)appearancePopUpButtonClicked:(NSPopUpButton *)button { + NSInteger selectedIndex = button.indexOfSelectedItem; + self.config.appearance = selectedIndex; +} + #pragma mark - MASPreferencesViewController - (NSString *)viewIdentifier {