diff --git a/Resource/ar.lproj/Localizable.strings b/Resource/ar.lproj/Localizable.strings index 0f1bd8db..a514c117 100644 --- a/Resource/ar.lproj/Localizable.strings +++ b/Resource/ar.lproj/Localizable.strings @@ -170,6 +170,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/de.lproj/Localizable.strings b/Resource/de.lproj/Localizable.strings index f8ec1ba6..fd072128 100644 --- a/Resource/de.lproj/Localizable.strings +++ b/Resource/de.lproj/Localizable.strings @@ -169,6 +169,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/en.lproj/Localizable.strings b/Resource/en.lproj/Localizable.strings index 155d60d2..b9f5fcf2 100644 --- a/Resource/en.lproj/Localizable.strings +++ b/Resource/en.lproj/Localizable.strings @@ -168,6 +168,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/es.lproj/Localizable.strings b/Resource/es.lproj/Localizable.strings index 63f6fd84..05983976 100644 --- a/Resource/es.lproj/Localizable.strings +++ b/Resource/es.lproj/Localizable.strings @@ -168,6 +168,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/fr.lproj/Localizable.strings b/Resource/fr.lproj/Localizable.strings index 1709e1ee..5a85f5b9 100644 --- a/Resource/fr.lproj/Localizable.strings +++ b/Resource/fr.lproj/Localizable.strings @@ -169,6 +169,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/ja.lproj/Localizable.strings b/Resource/ja.lproj/Localizable.strings index 56c8b0ad..e05e2ce9 100644 --- a/Resource/ja.lproj/Localizable.strings +++ b/Resource/ja.lproj/Localizable.strings @@ -169,6 +169,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/ko.lproj/Localizable.strings b/Resource/ko.lproj/Localizable.strings index ac05402d..1f1604fb 100644 --- a/Resource/ko.lproj/Localizable.strings +++ b/Resource/ko.lproj/Localizable.strings @@ -170,6 +170,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/mn.lproj/Localizable.strings b/Resource/mn.lproj/Localizable.strings index a6d7562e..6b61a34f 100644 --- a/Resource/mn.lproj/Localizable.strings +++ b/Resource/mn.lproj/Localizable.strings @@ -170,6 +170,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/pt.lproj/Localizable.strings b/Resource/pt.lproj/Localizable.strings index 1029c203..337552c5 100644 --- a/Resource/pt.lproj/Localizable.strings +++ b/Resource/pt.lproj/Localizable.strings @@ -168,6 +168,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/ru.lproj/Localizable.strings b/Resource/ru.lproj/Localizable.strings index 9c223374..d5299a89 100644 --- a/Resource/ru.lproj/Localizable.strings +++ b/Resource/ru.lproj/Localizable.strings @@ -168,6 +168,7 @@ "text_component.loadAverage1Min" = "Load Average (1 min)"; "text_component.loadAverage5Min" = "Load Average (5 min)"; "text_component.loadAverage15Min" = "Load Average (15 min)"; +"text_component.average" = "Average"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU Display Mode"; diff --git a/Resource/zh-Hans.lproj/Localizable.strings b/Resource/zh-Hans.lproj/Localizable.strings index 326cbb77..6aaf6240 100644 --- a/Resource/zh-Hans.lproj/Localizable.strings +++ b/Resource/zh-Hans.lproj/Localizable.strings @@ -168,6 +168,7 @@ "text_component.loadAverage1Min" = "平均负载 (1分钟)"; "text_component.loadAverage5Min" = "平均负载 (5分钟)"; "text_component.loadAverage15Min" = "平均负载 (15分钟)"; +"text_component.average" = "平均"; // MARK: CPU Display Mode "cpu_display_mode" = "CPU 显示"; diff --git a/eul.xcodeproj/project.pbxproj b/eul.xcodeproj/project.pbxproj index bf9aecc5..0eb405b6 100644 --- a/eul.xcodeproj/project.pbxproj +++ b/eul.xcodeproj/project.pbxproj @@ -147,6 +147,10 @@ 6C9A10CC2556C502000459E1 /* SharedLibrary.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6C2688EE2556762B00FB7306 /* SharedLibrary.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6CAEED6524A62DF800C39597 /* SMC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CAEED6424A62DF800C39597 /* SMC.swift */; }; 6CC0798C250CD793000D7DAC /* PreferenceGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC0798B250CD793000D7DAC /* PreferenceGeneralView.swift */; }; + 6CC1EBB725769B1F00BC05CA /* FanData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC1EBB625769B1F00BC05CA /* FanData.swift */; }; + 6CC1EBBA25769B4400BC05CA /* TemperatureData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC1EBB925769B4400BC05CA /* TemperatureData.swift */; }; + 6CC1EBBD25769E2400BC05CA /* FanTextComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC1EBBC25769E2400BC05CA /* FanTextComponent.swift */; }; + 6CC1EBC02576A0E200BC05CA /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC1EBBF2576A0E200BC05CA /* Array.swift */; }; 6CC73857256A9E4D003A15AC /* PreferenceComponentConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC73856256A9E4D003A15AC /* PreferenceComponentConfigView.swift */; }; 6CC7385E256BEABA003A15AC /* Dict.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC7385D256BEABA003A15AC /* Dict.swift */; }; 6CDBB4C1254462B100D01EA0 /* PreferenceSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CDBB4C0254462B100D01EA0 /* PreferenceSectionView.swift */; }; @@ -436,6 +440,10 @@ 6CB260AF250DF1A900328DAA /* BatteryIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIconView.swift; sourceTree = ""; }; 6CB26F7824E8310900E809FE /* SectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionView.swift; sourceTree = ""; }; 6CC0798B250CD793000D7DAC /* PreferenceGeneralView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceGeneralView.swift; sourceTree = ""; }; + 6CC1EBB625769B1F00BC05CA /* FanData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanData.swift; sourceTree = ""; }; + 6CC1EBB925769B4400BC05CA /* TemperatureData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemperatureData.swift; sourceTree = ""; }; + 6CC1EBBC25769E2400BC05CA /* FanTextComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanTextComponent.swift; sourceTree = ""; }; + 6CC1EBBF2576A0E200BC05CA /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; }; 6CC7384E2566C07D003A15AC /* mn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mn; path = mn.lproj/Localizable.strings; sourceTree = ""; }; 6CC738502566C140003A15AC /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; }; 6CC73856256A9E4D003A15AC /* PreferenceComponentConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceComponentConfigView.swift; sourceTree = ""; }; @@ -581,6 +589,7 @@ 6C3A002C256FF62F0030AB70 /* NetworkTextComponent.swift */, 6C3A0033256FF7510030AB70 /* BatteryTextComponent.swift */, 6C3A0036256FFB330030AB70 /* DiskTextComponent.swift */, + 6CC1EBBC25769E2400BC05CA /* FanTextComponent.swift */, ); path = TextComponents; sourceTree = ""; @@ -617,6 +626,8 @@ 6CEF48A5255C366A002E4D73 /* SizePreferenceKey.swift */, 6C7DB6E724E82C7700133B06 /* StringEnum.swift */, 6C19253E256FEBE5006B0D73 /* LocalizedStringConvertible.swift */, + 6CC1EBB625769B1F00BC05CA /* FanData.swift */, + 6CC1EBB925769B4400BC05CA /* TemperatureData.swift */, ); path = Schema; sourceTree = ""; @@ -817,6 +828,7 @@ 6C4CCCF0250BA68B00590E0E /* View.swift */, 6C387DC4253AF46000CBB81B /* NSRunningApplication.swift */, 6C15933E257241DB00FDE7EA /* Collection.swift */, + 6CC1EBBF2576A0E200BC05CA /* Array.swift */, ); path = Extension; sourceTree = ""; @@ -1284,8 +1296,10 @@ 6C16BF10255428EF00CCF5B7 /* StableWidth.swift in Sources */, 6C7DB6E624E82C5A00133B06 /* Preference.swift in Sources */, 6C993B8E2517909200586C6B /* MiniSectionView.swift in Sources */, + 6CC1EBC02576A0E200BC05CA /* Array.swift in Sources */, 6C1FA3F824A70DF300CA7F71 /* CpuView.swift in Sources */, 6C1FA40024A712AA00CA7F71 /* SmcControl.swift in Sources */, + 6CC1EBBD25769E2400BC05CA /* FanTextComponent.swift in Sources */, 6C33CECD25177CE300345977 /* CpuMenuBlockView.swift in Sources */, 6CF28D0D251758EE00EBE9CB /* StatusBarView.swift in Sources */, 6C1FA3FA24A70E6700CA7F71 /* CpuStore.swift in Sources */, @@ -1311,10 +1325,12 @@ 6C19252F256D56BF006B0D73 /* JSONCodable.swift in Sources */, 6C3A002D256FF62F0030AB70 /* NetworkTextComponent.swift in Sources */, 6CDBB4C325447B7500D01EA0 /* EulMenuComponent.swift in Sources */, + 6CC1EBB725769B1F00BC05CA /* FanData.swift in Sources */, 6CDBB4C1254462B100D01EA0 /* PreferenceSectionView.swift in Sources */, 6C7DB6E824E82C7700133B06 /* StringEnum.swift in Sources */, 6CC0798C250CD793000D7DAC /* PreferenceGeneralView.swift in Sources */, 6C572D81254EFD5B00EF9904 /* DiskList.swift in Sources */, + 6CC1EBBA25769B4400BC05CA /* TemperatureData.swift in Sources */, 6C1FA40724AA127E00CA7F71 /* MemoryView.swift in Sources */, 6CDE6C7424F0047600463114 /* SizeChangeView.swift in Sources */, 6C45751125568DCC00A2AD84 /* MemoryWidget.intentdefinition in Sources */, @@ -1506,7 +1522,7 @@ CODE_SIGN_ENTITLEMENTS = MemoryWidget/MemoryWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = MemoryWidget/Info.plist; @@ -1516,7 +1532,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.MemoryWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1532,7 +1548,7 @@ CODE_SIGN_ENTITLEMENTS = MemoryWidget/MemoryWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = MemoryWidget/Info.plist; @@ -1542,7 +1558,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.MemoryWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1558,7 +1574,7 @@ CODE_SIGN_ENTITLEMENTS = NetworkWidget/NetworkWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = NetworkWidget/Info.plist; @@ -1568,7 +1584,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.NetworkWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1584,7 +1600,7 @@ CODE_SIGN_ENTITLEMENTS = NetworkWidget/NetworkWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = NetworkWidget/Info.plist; @@ -1594,7 +1610,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.NetworkWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1729,7 +1745,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; @@ -1741,7 +1757,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -1760,7 +1776,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; @@ -1772,7 +1788,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -1788,7 +1804,7 @@ CODE_SIGN_ENTITLEMENTS = BatteryWidget/BatteryWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = BatteryWidget/Info.plist; @@ -1798,7 +1814,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.BatteryWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1814,7 +1830,7 @@ CODE_SIGN_ENTITLEMENTS = BatteryWidget/BatteryWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = BatteryWidget/Info.plist; @@ -1824,7 +1840,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.BatteryWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1840,7 +1856,7 @@ CODE_SIGN_ENTITLEMENTS = CpuWidget/CpuWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CpuWidget/Info.plist; @@ -1850,7 +1866,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.CpuWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -1866,7 +1882,7 @@ CODE_SIGN_ENTITLEMENTS = CpuWidget/CpuWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = M8G2RFZVFV; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CpuWidget/Info.plist; @@ -1876,7 +1892,7 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 1.4.6; + MARKETING_VERSION = 1.4.7; PRODUCT_BUNDLE_IDENTIFIER = com.gaosun.eul.CpuWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/eul/AppDelegate.swift b/eul/AppDelegate.swift index e7ff1352..8cbece5c 100644 --- a/eul/AppDelegate.swift +++ b/eul/AppDelegate.swift @@ -30,7 +30,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { private var isSleeping = false var window: NSWindow! - let statusBarManager = StatusBarManager() @ObservedObject var preferenceStore = SharedStore.preference func refreshSMCRepeatedly() { @@ -76,7 +75,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { // window.makeKeyAndOrderFront(nil) // NSApp.activate(ignoringOtherApps: true) - SmcControl.shared.start() + SmcControl.shared.subscribe() + StatusBarManager.shared.checkVisibilityIfNeeded() wakeUp() let notificationCenter = NSWorkspace.shared.notificationCenter diff --git a/eul/Extension/Array.swift b/eul/Extension/Array.swift new file mode 100644 index 00000000..5b81db27 --- /dev/null +++ b/eul/Extension/Array.swift @@ -0,0 +1,15 @@ +// +// Array.swift +// eul +// +// Created by Gao Sun on 2020/12/2. +// Copyright © 2020 Gao Sun. All rights reserved. +// + +import Foundation + +extension Array { + func appending(_ newElement: Element, condition: Bool = true) -> [Element] { + condition ? self + [newElement] : self + } +} diff --git a/eul/Schema/EulComponent.swift b/eul/Schema/EulComponent.swift index 3fad9004..27d7fc27 100644 --- a/eul/Schema/EulComponent.swift +++ b/eul/Schema/EulComponent.swift @@ -51,8 +51,11 @@ enum EulComponent: String, CaseIterable, Identifiable, Codable, JSONCodabble, Lo case Disk static var allCases: [EulComponent] { - let components: [EulComponent] = [.CPU, .Fan, .Memory, .Network, .Disk] - return SharedStore.battery.isValid ? components + [.Battery] : components + [.CPU, .Memory] + .appending(.Fan, condition: SmcControl.shared.isFanValid) + .appending(.Network) + .appending(.Battery, condition: SharedStore.battery.isValid) + .appending(.Disk) } } diff --git a/eul/Schema/FanData.swift b/eul/Schema/FanData.swift new file mode 100644 index 00000000..8ba8de88 --- /dev/null +++ b/eul/Schema/FanData.swift @@ -0,0 +1,29 @@ +// +// FanData.swift +// eul +// +// Created by Gao Sun on 2020/12/1. +// Copyright © 2020 Gao Sun. All rights reserved. +// + +import Foundation +import SharedLibrary +import SwiftyJSON + +class FanData: Identifiable { + let fan: Fan + var speed: Int + + var id: Int { + fan.id + } + + var percentage: Double { + Double(speed) / Double(fan.maxSpeed) * 100 + } + + init(fan: Fan, speed: Int = 0) { + self.fan = fan + self.speed = speed + } +} diff --git a/eul/Schema/TemperatureData.swift b/eul/Schema/TemperatureData.swift new file mode 100644 index 00000000..a07a80cb --- /dev/null +++ b/eul/Schema/TemperatureData.swift @@ -0,0 +1,20 @@ +// +// TemperatureData.swift +// eul +// +// Created by Gao Sun on 2020/12/1. +// Copyright © 2020 Gao Sun. All rights reserved. +// + +import Foundation +import SharedLibrary + +class TemperatureData { + let sensor: TemperatureSensor + var temp: Double + + init(sensor: TemperatureSensor, temp: Double = 0) { + self.sensor = sensor + self.temp = temp + } +} diff --git a/eul/Schema/TextComponents/FanTextComponent.swift b/eul/Schema/TextComponents/FanTextComponent.swift new file mode 100644 index 00000000..21865e39 --- /dev/null +++ b/eul/Schema/TextComponents/FanTextComponent.swift @@ -0,0 +1,48 @@ +// +// FanTextComponent.swift +// eul +// +// Created by Gao Sun on 2020/12/1. +// Copyright © 2020 Gao Sun. All rights reserved. +// + +import SwiftUI +import SwiftyJSON + +struct FanTextComponent: Hashable { + var id: Int + + var isAverage: Bool { + id == -1 + } +} + +extension FanTextComponent: CaseIterable { + static var allCases: [Self] + = defaultComponents + [FanTextComponent(id: -1)] + + static var defaultComponents: [Self] { + SmcControl.shared.fans.map { FanTextComponent(id: $0.id) } + } +} + +extension FanTextComponent: JSONCodabble { + init?(json: JSON) { + guard let id = json["id"].int else { + return nil + } + self.id = id + } + + var json: JSON { + JSON([ + "id": id, + ]) + } +} + +extension FanTextComponent: LocalizedStringConvertible { + var localizedDescription: String { + id == -1 ? "text_component.average".localized() : "fan".localized() + " \(id + 1)" + } +} diff --git a/eul/StatusBar/StatusBarItem.swift b/eul/StatusBar/StatusBarItem.swift index 71a406bb..d941fd2b 100644 --- a/eul/StatusBar/StatusBarItem.swift +++ b/eul/StatusBar/StatusBarItem.swift @@ -36,7 +36,6 @@ class StatusBarItem: NSObject, NSMenuDelegate { item.length = width statusView?.setFrameSize(NSSize(width: width, height: AppDelegate.statusBarHeight)) - checkVisibilityIfNeeded() } func onMenuSizeChange(size: CGSize) { diff --git a/eul/StatusBar/StatusBarManager.swift b/eul/StatusBar/StatusBarManager.swift index 7f39619d..495eea60 100644 --- a/eul/StatusBar/StatusBarManager.swift +++ b/eul/StatusBar/StatusBarManager.swift @@ -10,6 +10,8 @@ import Combine import SwiftUI class StatusBarManager { + static let shared = StatusBarManager() + @ObservedObject var preferenceStore = SharedStore.preference @ObservedObject var componentsStore = SharedStore.components private var activeCancellable: AnyCancellable? @@ -26,6 +28,10 @@ class StatusBarManager { } } + func checkVisibilityIfNeeded() { + item.checkVisibilityIfNeeded() + } + func subscribe() { // TO-DO: refactor activeCancellable = SharedStore.components.$activeComponents.sink { diff --git a/eul/Store/ComponentConfigStore.swift b/eul/Store/ComponentConfigStore.swift index e72dbade..a69cbfdb 100644 --- a/eul/Store/ComponentConfigStore.swift +++ b/eul/Store/ComponentConfigStore.swift @@ -30,6 +30,7 @@ class ComponentConfigStore: ObservableObject { private let userDefaultsKey = "componentConfig" private var cancellable: AnyCancellable? private var converted = false + private var onDidChange: (() -> Void)? @Published var configDict = ComponentConfigStore.makeConfigDict() @@ -40,13 +41,16 @@ class ComponentConfigStore: ObservableObject { ]) } - init() { + init(onDidChange didChange: (() -> Void)?) { + onDidChange = didChange + loadFromDefaults() convertIfNeeded() cancellable = objectWillChange.sink { - DispatchQueue.main.async { - self.saveToDefaults() + DispatchQueue.main.async { [self] in + saveToDefaults() + onDidChange?() } } } diff --git a/eul/Store/ComponentsStore.swift b/eul/Store/ComponentsStore.swift index 1cc676c9..e8500a4e 100644 --- a/eul/Store/ComponentsStore.swift +++ b/eul/Store/ComponentsStore.swift @@ -19,6 +19,7 @@ class ComponentsStore: ObservableObject { private let allComponents: [Component] private let userDefaultsKey: String private var cancellable: AnyCancellable? + private var onDidChange: (() -> Void)? var totalCount: Int { allComponents.count @@ -35,17 +36,20 @@ class ComponentsStore: ObservableObject { init( key: String = String(describing: Component.self), allComponents all: [Component], - defaultComponents: [Component]? = nil + defaultComponents: [Component]? = nil, + onDidChange didChange: (() -> Void)? = nil ) { let active = defaultComponents ?? all allComponents = all userDefaultsKey = key activeComponents = active availableComponents = all.filter { !active.contains($0) } + onDidChange = didChange loadFromDefaults() cancellable = objectWillChange.sink { - DispatchQueue.main.async { - self.saveToDefaults() + DispatchQueue.main.async { [self] in + saveToDefaults() + onDidChange?() } } } @@ -106,7 +110,16 @@ class ComponentsStore: ObservableObject { } extension ComponentsStore where Component: CaseIterable { - convenience init(key: String = String(describing: Component.self), defaultComponents: [Component]? = nil) { - self.init(key: key, allComponents: Array(Component.allCases), defaultComponents: defaultComponents) + convenience init( + key: String = String(describing: Component.self), + defaultComponents: [Component]? = nil, + onDidChange: (() -> Void)? = nil + ) { + self.init( + key: key, + allComponents: Array(Component.allCases), + defaultComponents: defaultComponents, + onDidChange: onDidChange + ) } } diff --git a/eul/Store/FanStore.swift b/eul/Store/FanStore.swift index 334be731..fc2565ed 100644 --- a/eul/Store/FanStore.swift +++ b/eul/Store/FanStore.swift @@ -9,7 +9,7 @@ import Foundation class FanStore: ObservableObject, Refreshable { - @Published var fans: [SmcControl.FanData] = [] + @Published var fans: [FanData] = [] @objc func refresh() { fans = SmcControl.shared.fans diff --git a/eul/Store/SharedStore.swift b/eul/Store/SharedStore.swift index 099417ab..4bab2e75 100644 --- a/eul/Store/SharedStore.swift +++ b/eul/Store/SharedStore.swift @@ -9,6 +9,7 @@ import SwiftUI enum SharedStore { + static let visibilityCheckClosure = { StatusBarManager.shared.checkVisibilityIfNeeded() } static let battery = BatteryStore() static let cpu = CpuStore() static let cpuTop = CpuTopStore() @@ -19,21 +20,31 @@ enum SharedStore { static let networkTop = NetworkTopStore() static let preference = PreferenceStore() static let ui = UIStore() - static let components = ComponentsStore() + static let components = ComponentsStore(onDidChange: visibilityCheckClosure) static let menuComponents = ComponentsStore() - static let componentConfig = ComponentConfigStore() + static let componentConfig = ComponentConfigStore(onDidChange: visibilityCheckClosure) static let cpuTextComponents = ComponentsStore( - defaultComponents: CpuTextComponent.defaultComponents + defaultComponents: CpuTextComponent.defaultComponents, + onDidChange: visibilityCheckClosure ) static let memoryTextComponents = ComponentsStore( - defaultComponents: MemoryTextComponent.defaultComponents + defaultComponents: MemoryTextComponent.defaultComponents, + onDidChange: visibilityCheckClosure + ) + static let networkTextComponents = ComponentsStore( + onDidChange: visibilityCheckClosure ) - static let networkTextComponents = ComponentsStore() static let batteryTextComponents = ComponentsStore( - defaultComponents: BatteryTextComponent.defaultComponents + defaultComponents: BatteryTextComponent.defaultComponents, + onDidChange: visibilityCheckClosure ) static let diskTextComponents = ComponentsStore( - defaultComponents: DiskTextComponent.defaultComponents + defaultComponents: DiskTextComponent.defaultComponents, + onDidChange: visibilityCheckClosure + ) + static let fanTextComponents = ComponentsStore( + defaultComponents: FanTextComponent.defaultComponents, + onDidChange: visibilityCheckClosure ) } @@ -57,5 +68,6 @@ extension View { .environmentObject(SharedStore.networkTextComponents) .environmentObject(SharedStore.batteryTextComponents) .environmentObject(SharedStore.diskTextComponents) + .environmentObject(SharedStore.fanTextComponents) } } diff --git a/eul/Utilities/SmcControl.swift b/eul/Utilities/SmcControl.swift index 3e5beae1..b9bad431 100644 --- a/eul/Utilities/SmcControl.swift +++ b/eul/Utilities/SmcControl.swift @@ -8,57 +8,11 @@ import Foundation import SharedLibrary - -extension TemperatureUnit { - var description: String { - switch self { - case .celius: - return "temp.celsius".localized() - case .fahrenheit: - return "temp.fahrenheit".localized() - case .kelvin: - return "temp.kelvin".localized() - } - } -} - -extension Double { - var temperatureString: String { - SmcControl.shared.formatTemp(self) - } -} +import SwiftyJSON class SmcControl: Refreshable { static var shared = SmcControl() - class TemperatureData { - let sensor: TemperatureSensor - var temp: Double - - init(sensor: TemperatureSensor, temp: Double = 0) { - self.sensor = sensor - self.temp = temp - } - } - - class FanData: Identifiable { - let fan: Fan - var speed: Int - - var id: Int { - fan.id - } - - var percentage: Double { - Double(speed) / Double(fan.maxSpeed) * 100 - } - - init(fan: Fan, speed: Int = 0) { - self.fan = fan - self.speed = speed - } - } - var sensors: [TemperatureData] = [] var fans: [FanData] = [] var tempUnit: TemperatureUnit = .celius @@ -74,12 +28,15 @@ class SmcControl: Refreshable { sensors.first(where: { $0.sensor.name == "MEM_SLOTS_PROXIMITY" })?.temp } + var isFanValid: Bool { + fans.count > 0 + } + func formatTemp(_ value: Double) -> String { String(format: "%.0f°\(tempUnit == .celius ? "C" : "F")", value) } - // must call a function explicitly to init shared instance - func start() { + init() { do { try SMCKit.open() sensors = try SMCKit.allKnownTemperatureSensors().map { .init(sensor: $0) } @@ -94,6 +51,13 @@ class SmcControl: Refreshable { } catch { print("SMC init error", error) } + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + func subscribe() { initObserver(for: .SMCShouldRefresh) } @@ -121,3 +85,48 @@ class SmcControl: Refreshable { NotificationCenter.default.post(name: .StoreShouldRefresh, object: nil) } } + +extension TemperatureUnit { + var description: String { + switch self { + case .celius: + return "temp.celsius".localized() + case .fahrenheit: + return "temp.fahrenheit".localized() + case .kelvin: + return "temp.kelvin".localized() + } + } +} + +extension Fan: JSONCodabble { + init?(json: JSON) { + guard + let id = json["id"].int, + let name = json["name"].string, + let minSpeed = json["id"].int, + let maxSpeed = json["id"].int + else { + return nil + } + self.id = id + self.name = name + self.minSpeed = minSpeed + self.maxSpeed = maxSpeed + } + + var json: JSON { + JSON([ + "id": id, + "name": name, + "minSpeed": minSpeed, + "maxSpeed": maxSpeed, + ]) + } +} + +extension Double { + var temperatureString: String { + SmcControl.shared.formatTemp(self) + } +} diff --git a/eul/Views/Preference/PreferenceComponentConfigView.swift b/eul/Views/Preference/PreferenceComponentConfigView.swift index dc61f653..78232b9c 100644 --- a/eul/Views/Preference/PreferenceComponentConfigView.swift +++ b/eul/Views/Preference/PreferenceComponentConfigView.swift @@ -34,6 +34,7 @@ extension Preference { } struct ComponentConfigView: View { + @EnvironmentObject var batteryStore: BatteryStore @EnvironmentObject var componentConfigStore: ComponentConfigStore var component: EulComponent @@ -62,10 +63,13 @@ extension Preference { if component == .Memory { ComponentTextConfigView() } + if SmcControl.shared.isFanValid, component == .Fan { + ComponentTextConfigView() + } if component == .Network { ComponentTextConfigView() } - if component == .Battery { + if batteryStore.isValid, component == .Battery { ComponentTextConfigView() } if component == .Disk { diff --git a/eul/Views/StatusBar/FanView.swift b/eul/Views/StatusBar/FanView.swift index b7061765..fc21520c 100644 --- a/eul/Views/StatusBar/FanView.swift +++ b/eul/Views/StatusBar/FanView.swift @@ -11,13 +11,26 @@ import SwiftUI struct FanView: View { @EnvironmentObject var fanStore: FanStore @EnvironmentObject var componentConfigStore: ComponentConfigStore + @EnvironmentObject var textStore: ComponentsStore var config: EulComponentConfig { componentConfigStore[.Fan] } + var averageRpm: String { + "\(fanStore.fans.reduce(0) { $0 + $1.speed } / fanStore.fans.count) rpm" + } + var texts: [String] { - fanStore.fans.map { "\($0.speed.description) rpm" } + textStore.activeComponents.compactMap { component in + if component.isAverage { + return averageRpm + } + guard let fan = fanStore.fans.first(where: { $0.id == component.id }) else { + return nil + } + return "\(fan.speed) rpm" + } } var body: some View { @@ -27,10 +40,10 @@ struct FanView: View { .resizable() .frame(width: 13, height: 13) } -// if config.showText { - StatusBarTextView(texts: texts) - .stableWidth() -// } + if textStore.showComponents { + StatusBarTextView(texts: texts) + .stableWidth() + } } } }