mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
created view for CPU module
This commit is contained in:
13
Podfile
Normal file
13
Podfile
Normal file
@@ -0,0 +1,13 @@
|
||||
target 'Stats' do
|
||||
use_frameworks!
|
||||
|
||||
pod 'Charts'
|
||||
|
||||
end
|
||||
|
||||
target 'StatsLauncher' do
|
||||
use_frameworks!
|
||||
|
||||
# Pods for StatsLauncher
|
||||
|
||||
end
|
||||
18
Podfile.lock
Normal file
18
Podfile.lock
Normal file
@@ -0,0 +1,18 @@
|
||||
PODS:
|
||||
- Charts (3.3.0):
|
||||
- Charts/Core (= 3.3.0)
|
||||
- Charts/Core (3.3.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Charts
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Charts
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Charts: ec1f57f9340054155691e84d4544a1d239d382c5
|
||||
|
||||
PODFILE CHECKSUM: 1935eab6769b7093597e74f1286aedc1ea7c755a
|
||||
|
||||
COCOAPODS: 1.7.1
|
||||
107
Stats.xcodeproj/project.pbxproj
Executable file → Normal file
107
Stats.xcodeproj/project.pbxproj
Executable file → Normal file
@@ -3,10 +3,12 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
556DD3DCB38374D039BECE89 /* Pods_StatsLauncher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B76EECB31DFC37E1EA558662 /* Pods_StatsLauncher.framework */; };
|
||||
628D2DE0AAA753E9F47625B0 /* Pods_Stats.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 56B63995EBD3A1D1EBD3AF38 /* Pods_Stats.framework */; };
|
||||
9A09C89E22B3A7C90018426F /* Battery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A09C89D22B3A7C90018426F /* Battery.swift */; };
|
||||
9A09C8A022B3A7E20018426F /* BatteryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A09C89F22B3A7E20018426F /* BatteryReader.swift */; };
|
||||
9A09C8A222B3D94D0018426F /* BatteryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A09C8A122B3D94D0018426F /* BatteryView.swift */; };
|
||||
@@ -18,6 +20,8 @@
|
||||
9A57A19D22A1E3270033E318 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A57A19C22A1E3270033E318 /* CPU.swift */; };
|
||||
9A58D1B022C150C800405315 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1AF22C150C800405315 /* Network.swift */; };
|
||||
9A58D1B222C150D700405315 /* NetworkReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1B122C150D700405315 /* NetworkReader.swift */; };
|
||||
9A59AE54231ED1AC007989D6 /* CPUView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A59AE53231ED1AC007989D6 /* CPUView.swift */; };
|
||||
9A59AE56231EE02F007989D6 /* ChartMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A59AE55231EE02F007989D6 /* ChartMarker.swift */; };
|
||||
9A5B1CBF229E78F0008B9D3C /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B1CBE229E78F0008B9D3C /* Observable.swift */; };
|
||||
9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B1CC4229E7B40008B9D3C /* Extensions.swift */; };
|
||||
9A6CFC0122A1C9F5001E782D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */; };
|
||||
@@ -61,6 +65,11 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0BAA6D5F418C0F6999BD18BD /* Pods-StatsLauncher.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatsLauncher.release.xcconfig"; path = "Target Support Files/Pods-StatsLauncher/Pods-StatsLauncher.release.xcconfig"; sourceTree = "<group>"; };
|
||||
1A1A00B8A6C7702FA7C3FD9A /* Pods-Stats.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Stats.release.xcconfig"; path = "Target Support Files/Pods-Stats/Pods-Stats.release.xcconfig"; sourceTree = "<group>"; };
|
||||
2650ED499D83382C9C938E76 /* Pods-StatsLauncher.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatsLauncher.debug.xcconfig"; path = "Target Support Files/Pods-StatsLauncher/Pods-StatsLauncher.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
38B7BF640C895BAFBF1A44BE /* Pods-Stats.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Stats.debug.xcconfig"; path = "Target Support Files/Pods-Stats/Pods-Stats.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
56B63995EBD3A1D1EBD3AF38 /* Pods_Stats.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Stats.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9A09C89D22B3A7C90018426F /* Battery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Battery.swift; sourceTree = "<group>"; };
|
||||
9A09C89F22B3A7E20018426F /* BatteryReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryReader.swift; sourceTree = "<group>"; };
|
||||
9A09C8A122B3D94D0018426F /* BatteryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryView.swift; sourceTree = "<group>"; };
|
||||
@@ -75,6 +84,8 @@
|
||||
9A57A19C22A1E3270033E318 /* CPU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = "<group>"; };
|
||||
9A58D1AF22C150C800405315 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = "<group>"; };
|
||||
9A58D1B122C150D700405315 /* NetworkReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkReader.swift; sourceTree = "<group>"; };
|
||||
9A59AE53231ED1AC007989D6 /* CPUView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPUView.swift; sourceTree = "<group>"; };
|
||||
9A59AE55231EE02F007989D6 /* ChartMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartMarker.swift; sourceTree = "<group>"; };
|
||||
9A5B1CBE229E78F0008B9D3C /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = "<group>"; };
|
||||
9A5B1CC4229E7B40008B9D3C /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
|
||||
9A6CFC0022A1C9F5001E782D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
@@ -105,6 +116,7 @@
|
||||
9AFA402A22AE49A200FE90BC /* StatsLauncher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = StatsLauncher.entitlements; sourceTree = "<group>"; };
|
||||
9AFA402E22AE49AE00FE90BC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
9AFFCB3A22B3FD0500B0E6D8 /* About.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = About.storyboard; sourceTree = "<group>"; };
|
||||
B76EECB31DFC37E1EA558662 /* Pods_StatsLauncher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_StatsLauncher.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -112,6 +124,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
628D2DE0AAA753E9F47625B0 /* Pods_Stats.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -119,6 +132,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
556DD3DCB38374D039BECE89 /* Pods_StatsLauncher.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -141,6 +155,7 @@
|
||||
9AFA401F22AE49A100FE90BC /* StatsLauncher */,
|
||||
9A1410F6229E721100D29793 /* Products */,
|
||||
9A998CD622A199920087ADE7 /* Frameworks */,
|
||||
A159F8578E30ECA1F2F6028E /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -209,6 +224,7 @@
|
||||
9A5B1CBE229E78F0008B9D3C /* Observable.swift */,
|
||||
9A5B1CC4229E7B40008B9D3C /* Extensions.swift */,
|
||||
9A426DB722C2B5EE00C064C4 /* macAppUpdater.swift */,
|
||||
9A59AE55231EE02F007989D6 /* ChartMarker.swift */,
|
||||
);
|
||||
path = libs;
|
||||
sourceTree = "<group>";
|
||||
@@ -230,6 +246,7 @@
|
||||
children = (
|
||||
9A57A19C22A1E3270033E318 /* CPU.swift */,
|
||||
9A7B8F5D22A2A57600DEB352 /* CPUReader.swift */,
|
||||
9A59AE53231ED1AC007989D6 /* CPUView.swift */,
|
||||
);
|
||||
path = CPU;
|
||||
sourceTree = "<group>";
|
||||
@@ -257,6 +274,8 @@
|
||||
children = (
|
||||
9A998CD922A199970087ADE7 /* ServiceManagement.framework */,
|
||||
9A998CD722A199920087ADE7 /* Cocoa.framework */,
|
||||
56B63995EBD3A1D1EBD3AF38 /* Pods_Stats.framework */,
|
||||
B76EECB31DFC37E1EA558662 /* Pods_StatsLauncher.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -303,6 +322,17 @@
|
||||
path = StatsLauncher;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A159F8578E30ECA1F2F6028E /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
38B7BF640C895BAFBF1A44BE /* Pods-Stats.debug.xcconfig */,
|
||||
1A1A00B8A6C7702FA7C3FD9A /* Pods-Stats.release.xcconfig */,
|
||||
2650ED499D83382C9C938E76 /* Pods-StatsLauncher.debug.xcconfig */,
|
||||
0BAA6D5F418C0F6999BD18BD /* Pods-StatsLauncher.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -310,10 +340,12 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9A141105229E721200D29793 /* Build configuration list for PBXNativeTarget "Stats" */;
|
||||
buildPhases = (
|
||||
813D45DAD934E69BA5C6A78F /* [CP] Check Pods Manifest.lock */,
|
||||
9A1410F1229E721100D29793 /* Sources */,
|
||||
9A1410F2229E721100D29793 /* Frameworks */,
|
||||
9A1410F3229E721100D29793 /* Resources */,
|
||||
9AB54DAE22A19F96006192E0 /* Copy Files */,
|
||||
EDB5CB3173CB4B8BADA1278D /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -328,6 +360,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 9AFA402B22AE49A200FE90BC /* Build configuration list for PBXNativeTarget "StatsLauncher" */;
|
||||
buildPhases = (
|
||||
3AB22E5D98D11E0384E0FF21 /* [CP] Check Pods Manifest.lock */,
|
||||
9AFA401A22AE49A100FE90BC /* Sources */,
|
||||
9AFA401B22AE49A100FE90BC /* Frameworks */,
|
||||
9AFA401C22AE49A100FE90BC /* Resources */,
|
||||
@@ -359,7 +392,7 @@
|
||||
enabled = 0;
|
||||
};
|
||||
com.apple.Sandbox = {
|
||||
enabled = 1;
|
||||
enabled = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -416,6 +449,70 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3AB22E5D98D11E0384E0FF21 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-StatsLauncher-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
813D45DAD934E69BA5C6A78F /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Stats-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
EDB5CB3173CB4B8BADA1278D /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Stats/Pods-Stats-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Stats/Pods-Stats-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Stats/Pods-Stats-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
9A1410F1229E721100D29793 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -424,6 +521,7 @@
|
||||
9A09C8A222B3D94D0018426F /* BatteryView.swift in Sources */,
|
||||
9A426DB822C2B5EE00C064C4 /* macAppUpdater.swift in Sources */,
|
||||
9A79B36E22D3BEF900BF1C3A /* Reader.swift in Sources */,
|
||||
9A59AE54231ED1AC007989D6 /* CPUView.swift in Sources */,
|
||||
9A7B8F6F22A2C57000DEB352 /* DiskReader.swift in Sources */,
|
||||
9A7B8F6922A2C3A100DEB352 /* Memory.swift in Sources */,
|
||||
9AF0F32522DA92C400026AE6 /* NetworkText.swift in Sources */,
|
||||
@@ -446,6 +544,7 @@
|
||||
9AF0F32922DA92E800026AE6 /* NetworkArrowsText.swift in Sources */,
|
||||
9AF0F31F22DA925700026AE6 /* BarChart.swift in Sources */,
|
||||
9AF0F31B22DA924000026AE6 /* LineChart.swift in Sources */,
|
||||
9A59AE56231EE02F007989D6 /* ChartMarker.swift in Sources */,
|
||||
9A74D59722B44498004FE1FA /* Mini.swift in Sources */,
|
||||
9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */,
|
||||
9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */,
|
||||
@@ -600,6 +699,7 @@
|
||||
};
|
||||
9A141106229E721200D29793 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 38B7BF640C895BAFBF1A44BE /* Pods-Stats.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "Stats/Supporting Files/Stats.entitlements";
|
||||
@@ -627,6 +727,7 @@
|
||||
};
|
||||
9A141107229E721200D29793 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 1A1A00B8A6C7702FA7C3FD9A /* Pods-Stats.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "Stats/Supporting Files/Stats.entitlements";
|
||||
@@ -654,6 +755,7 @@
|
||||
};
|
||||
9AFA402C22AE49A200FE90BC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 2650ED499D83382C9C938E76 /* Pods-StatsLauncher.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = StatsLauncher/StatsLauncher.entitlements;
|
||||
@@ -676,6 +778,7 @@
|
||||
};
|
||||
9AFA402D22AE49A200FE90BC /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 0BAA6D5F418C0F6999BD18BD /* Pods-StatsLauncher.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = StatsLauncher/StatsLauncher.entitlements;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1100"
|
||||
LastUpgradeVersion = "1030"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,6 +27,8 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -36,8 +38,8 @@
|
||||
ReferencedContainer = "container:Stats.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -59,6 +61,8 @@
|
||||
ReferencedContainer = "container:Stats.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
10
Stats.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
Stats.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Stats.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
8
Stats.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Normal file
8
Stats.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -7,23 +7,25 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Charts
|
||||
|
||||
class CPU: Module {
|
||||
let name: String = "CPU"
|
||||
let shortName: String = "CPU"
|
||||
var view: NSView = NSView()
|
||||
var menu: NSMenuItem = NSMenuItem()
|
||||
var submenu: NSMenu = NSMenu()
|
||||
var active: Observable<Bool>
|
||||
var available: Observable<Bool>
|
||||
var hyperthreading: Observable<Bool>
|
||||
var reader: Reader = CPUReader()
|
||||
var tabView: NSTabViewItem = NSTabViewItem()
|
||||
public let name: String = "CPU"
|
||||
public let shortName: String = "CPU"
|
||||
public var view: NSView = NSView()
|
||||
public var menu: NSMenuItem = NSMenuItem()
|
||||
public var active: Observable<Bool>
|
||||
public var available: Observable<Bool>
|
||||
public var hyperthreading: Observable<Bool>
|
||||
public var reader: Reader = CPUReader()
|
||||
public var tabView: NSTabViewItem = NSTabViewItem()
|
||||
public var viewAvailable: Bool = true
|
||||
public var widgetType: WidgetType
|
||||
|
||||
var viewAvailable: Bool = true
|
||||
public var chart: LineChartView = LineChartView()
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
var widgetType: WidgetType
|
||||
private let defaults = UserDefaults.standard
|
||||
private var submenu: NSMenu = NSMenu()
|
||||
|
||||
init() {
|
||||
self.available = Observable(true)
|
||||
@@ -42,24 +44,6 @@ class CPU: Module {
|
||||
initTab()
|
||||
}
|
||||
|
||||
func initTab() {
|
||||
self.tabView.view?.frame = NSRect(x: 0, y: 0, width: TabWidth, height: TabHeight)
|
||||
|
||||
let text: NSTextField = NSTextField(string: self.name)
|
||||
text.isEditable = false
|
||||
text.isSelectable = false
|
||||
text.isBezeled = false
|
||||
text.wantsLayer = true
|
||||
text.textColor = .labelColor
|
||||
text.canDrawSubviewsIntoLayer = true
|
||||
text.alignment = .natural
|
||||
text.font = NSFont.systemFont(ofSize: 13, weight: .regular)
|
||||
text.frame.origin.x = ((self.tabView.view?.frame.size.width)! - 30) / 2
|
||||
text.frame.origin.y = ((self.tabView.view?.frame.size.height)! - 22) / 2
|
||||
|
||||
self.tabView.view?.addSubview(text)
|
||||
}
|
||||
|
||||
func initMenu() {
|
||||
menu = NSMenuItem(title: name, action: #selector(toggle), keyEquivalent: "")
|
||||
submenu = NSMenu()
|
||||
|
||||
@@ -8,23 +8,47 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CPUUsage {
|
||||
var value: Double = 0
|
||||
var system: Double = 0
|
||||
var user: Double = 0
|
||||
var idle: Double = 0
|
||||
}
|
||||
|
||||
struct CPUProcess {
|
||||
var pid: Int = 0
|
||||
var command: String = ""
|
||||
var usage: Double = 0
|
||||
}
|
||||
|
||||
class CPUReader: Reader {
|
||||
var value: Observable<[Double]>!
|
||||
var available: Bool = true
|
||||
var cpuInfo: processor_info_array_t!
|
||||
var prevCpuInfo: processor_info_array_t?
|
||||
var numCpuInfo: mach_msg_type_number_t = 0
|
||||
var numPrevCpuInfo: mach_msg_type_number_t = 0
|
||||
var numCPUs: uint = 0
|
||||
var updateTimer: Timer!
|
||||
let CPUUsageLock: NSLock = NSLock()
|
||||
public var value: Observable<[Double]>!
|
||||
public var usage: Observable<CPUUsage> = Observable(CPUUsage())
|
||||
public var processes: Observable<[CPUProcess]> = Observable([CPUProcess]())
|
||||
public var available: Bool = true
|
||||
public var updateTimer: Timer!
|
||||
public var perCoreMode: Bool = false
|
||||
public var hyperthreading: Bool = true
|
||||
|
||||
var perCoreMode: Bool = false
|
||||
var hyperthreading: Bool = true
|
||||
private var cpuInfo: processor_info_array_t!
|
||||
private var prevCpuInfo: processor_info_array_t?
|
||||
private var numCpuInfo: mach_msg_type_number_t = 0
|
||||
private var numPrevCpuInfo: mach_msg_type_number_t = 0
|
||||
private var numCPUs: uint = 0
|
||||
private let CPUUsageLock: NSLock = NSLock()
|
||||
private var loadPrevious = host_cpu_load_info()
|
||||
|
||||
private var topProcess: Process = Process()
|
||||
private var pipe: Pipe = Pipe()
|
||||
|
||||
init() {
|
||||
let mibKeys: [Int32] = [ CTL_HW, HW_NCPU ]
|
||||
self.value = Observable([])
|
||||
|
||||
self.topProcess.launchPath = "/usr/bin/top"
|
||||
self.topProcess.arguments = ["-s", "1", "-o", "cpu", "-n", "5", "-stats", "pid,command,cpu"]
|
||||
self.topProcess.standardOutput = pipe
|
||||
|
||||
mibKeys.withUnsafeBufferPointer() { mib in
|
||||
var sizeOfNumCPUs: size_t = MemoryLayout<uint>.size
|
||||
let status = sysctl(processor_info_array_t(mutating: mib.baseAddress), 2, &numCPUs, &sizeOfNumCPUs, nil, 0)
|
||||
@@ -40,6 +64,43 @@ class CPUReader: Reader {
|
||||
return
|
||||
}
|
||||
updateTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(read), userInfo: nil, repeats: true)
|
||||
|
||||
if topProcess.isRunning {
|
||||
return
|
||||
}
|
||||
self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: self.pipe.fileHandleForReading , queue: nil) { _ -> Void in
|
||||
defer {
|
||||
self.pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
}
|
||||
|
||||
let output = self.pipe.fileHandleForReading.availableData
|
||||
if output.isEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
let outputString = String(data: output, encoding: String.Encoding.utf8) ?? ""
|
||||
var processes: [CPUProcess] = []
|
||||
outputString.enumerateLines { (line, stop) -> () in
|
||||
if line.matches("^\\d+ + .+ +\\d+.\\d *$") {
|
||||
let arr = line.condenseWhitespace().split(separator: " ")
|
||||
let pid = Int(arr[0]) ?? 0
|
||||
let command = String(arr[1])
|
||||
let usage = Double(arr[2]) ?? 0
|
||||
let process = CPUProcess(pid: pid, command: command, usage: usage)
|
||||
processes.append(process)
|
||||
}
|
||||
}
|
||||
|
||||
self.processes << processes
|
||||
}
|
||||
|
||||
do {
|
||||
try topProcess.run()
|
||||
} catch let error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
func stop() {
|
||||
@@ -48,11 +109,14 @@ class CPUReader: Reader {
|
||||
}
|
||||
updateTimer.invalidate()
|
||||
updateTimer = nil
|
||||
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSFileHandleDataAvailable, object: nil)
|
||||
}
|
||||
|
||||
@objc func read() {
|
||||
var numCPUsU: natural_t = 0
|
||||
let err: kern_return_t = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo);
|
||||
let usage = getUsage()
|
||||
|
||||
if err == KERN_SUCCESS {
|
||||
CPUUsageLock.lock()
|
||||
|
||||
@@ -65,7 +129,7 @@ class CPUReader: Reader {
|
||||
incrementNumber = 2
|
||||
}
|
||||
|
||||
for i in stride(from: 0, to: Int32(numCPUs), by: incrementNumber){
|
||||
for i in stride(from: 0, to: Int32(numCPUs), by: incrementNumber) {
|
||||
var inUse: Int32
|
||||
var total: Int32
|
||||
if let prevCpuInfo = prevCpuInfo {
|
||||
@@ -96,6 +160,9 @@ class CPUReader: Reader {
|
||||
} else {
|
||||
self.value << [(Double(inUseOnAllCores) / Double(totalOnAllCores))]
|
||||
}
|
||||
if !usage.system.isNaN && !usage.user.isNaN && !usage.idle.isNaN {
|
||||
self.usage << CPUUsage(value: Double(inUseOnAllCores) / Double(totalOnAllCores), system: usage.system, user: usage.user, idle: usage.idle)
|
||||
}
|
||||
|
||||
CPUUsageLock.unlock()
|
||||
|
||||
@@ -113,4 +180,46 @@ class CPUReader: Reader {
|
||||
print("Error KERN_SUCCESS!")
|
||||
}
|
||||
}
|
||||
|
||||
func hostCPULoadInfo() -> host_cpu_load_info? {
|
||||
let HOST_CPU_LOAD_INFO_COUNT = MemoryLayout<host_cpu_load_info>.stride/MemoryLayout<integer_t>.stride
|
||||
var size = mach_msg_type_number_t(HOST_CPU_LOAD_INFO_COUNT)
|
||||
var cpuLoadInfo = host_cpu_load_info()
|
||||
|
||||
let result = withUnsafeMutablePointer(to: &cpuLoadInfo) {
|
||||
$0.withMemoryRebound(to: integer_t.self, capacity: HOST_CPU_LOAD_INFO_COUNT) {
|
||||
host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, $0, &size)
|
||||
}
|
||||
}
|
||||
if result != KERN_SUCCESS {
|
||||
print("Error - \(#file): \(#function) - kern_result_t = \(result)")
|
||||
return nil
|
||||
}
|
||||
return cpuLoadInfo
|
||||
}
|
||||
|
||||
public func getUsage() -> (system: Double, user: Double, idle : Double) {
|
||||
let load = hostCPULoadInfo()
|
||||
|
||||
let userDiff = Double(load!.cpu_ticks.0 - loadPrevious.cpu_ticks.0)
|
||||
let sysDiff = Double(load!.cpu_ticks.1 - loadPrevious.cpu_ticks.1)
|
||||
let idleDiff = Double(load!.cpu_ticks.2 - loadPrevious.cpu_ticks.2)
|
||||
let niceDiff = Double(load!.cpu_ticks.3 - loadPrevious.cpu_ticks.3)
|
||||
|
||||
let totalTicks = sysDiff + userDiff + niceDiff + idleDiff
|
||||
|
||||
let sys = sysDiff / totalTicks * 100.0
|
||||
let user = userDiff / totalTicks * 100.0
|
||||
let idle = idleDiff / totalTicks * 100.0
|
||||
|
||||
self.loadPrevious = load!
|
||||
|
||||
return (sys, user, idle)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func matches(_ regex: String) -> Bool {
|
||||
return self.range(of: regex, options: .regularExpression, range: nil, locale: nil) != nil
|
||||
}
|
||||
}
|
||||
|
||||
258
Stats/Modules/CPU/CPUView.swift
Normal file
258
Stats/Modules/CPU/CPUView.swift
Normal file
@@ -0,0 +1,258 @@
|
||||
//
|
||||
// CPUView.swift
|
||||
// Stats
|
||||
//
|
||||
// Created by Serhiy Mytrovtsiy on 03/09/2019.
|
||||
// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Foundation
|
||||
import Charts
|
||||
|
||||
extension CPU {
|
||||
|
||||
func initTab() {
|
||||
self.tabView.view?.frame = NSRect(x: 0, y: 0, width: TabWidth, height: TabHeight)
|
||||
|
||||
makeChart()
|
||||
makeOverview()
|
||||
makeProcesses()
|
||||
|
||||
(self.reader as! CPUReader).usage.subscribe(observer: self) { (value, _) in
|
||||
let v: Double = Double((value.value * 100).roundTo(decimalPlaces: 2))!
|
||||
self.updateChart(value: v)
|
||||
}
|
||||
}
|
||||
|
||||
func makeChart() {
|
||||
let lineColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 1.0)
|
||||
let gradientColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.5)
|
||||
|
||||
self.chart = LineChartView(frame: CGRect(x: 0, y: TabHeight - 108, width: TabWidth, height: 100))
|
||||
self.chart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInCubic)
|
||||
self.chart.backgroundColor = .white
|
||||
self.chart.noDataText = "No data about CPU usage"
|
||||
self.chart.legend.enabled = false
|
||||
self.chart.scaleXEnabled = false
|
||||
self.chart.scaleYEnabled = false
|
||||
self.chart.pinchZoomEnabled = false
|
||||
self.chart.doubleTapToZoomEnabled = false
|
||||
self.chart.drawBordersEnabled = false
|
||||
|
||||
self.chart.rightAxis.enabled = false
|
||||
|
||||
self.chart.leftAxis.axisMinimum = 0
|
||||
self.chart.leftAxis.axisMaximum = 100
|
||||
self.chart.leftAxis.labelCount = 6
|
||||
self.chart.leftAxis.drawGridLinesEnabled = false
|
||||
self.chart.leftAxis.drawAxisLineEnabled = false
|
||||
|
||||
self.chart.leftAxis.gridColor = NSColor(red:220/255, green:220/255, blue:220/255, alpha:1)
|
||||
self.chart.leftAxis.gridLineWidth = 0.5
|
||||
self.chart.leftAxis.drawGridLinesEnabled = true
|
||||
self.chart.leftAxis.labelTextColor = NSColor(red:150/255, green:150/255, blue:150/255, alpha:1)
|
||||
|
||||
self.chart.xAxis.drawAxisLineEnabled = false
|
||||
self.chart.xAxis.drawLimitLinesBehindDataEnabled = false
|
||||
self.chart.xAxis.gridLineWidth = 0.5
|
||||
self.chart.xAxis.drawGridLinesEnabled = false
|
||||
self.chart.xAxis.drawLabelsEnabled = false
|
||||
|
||||
let marker = ChartMarker()
|
||||
marker.chartView = self.chart
|
||||
self.chart.marker = marker
|
||||
|
||||
var lineChartEntry = [ChartDataEntry]()
|
||||
|
||||
lineChartEntry.append(ChartDataEntry(x: 0, y: 50))
|
||||
lineChartEntry.append(ChartDataEntry(x: 1, y: 25))
|
||||
|
||||
let chartDataSet = LineChartDataSet(entries: lineChartEntry, label: "CPU Usage")
|
||||
chartDataSet.drawCirclesEnabled = false
|
||||
chartDataSet.mode = .cubicBezier
|
||||
chartDataSet.cubicIntensity = 0.1
|
||||
chartDataSet.colors = [lineColor]
|
||||
chartDataSet.fillColor = gradientColor
|
||||
chartDataSet.drawFilledEnabled = true
|
||||
|
||||
let data = LineChartData()
|
||||
data.addDataSet(chartDataSet)
|
||||
data.setDrawValues(false)
|
||||
|
||||
self.chart.data = LineChartData(dataSet: chartDataSet)
|
||||
|
||||
self.tabView.view?.addSubview(self.chart)
|
||||
}
|
||||
|
||||
func updateChart(value: Double) {
|
||||
let index = Double((self.chart.data?.getDataSetByIndex(0)?.entryCount)!)
|
||||
self.chart.data?.addEntry(ChartDataEntry(x: index, y: value), dataSetIndex: 0)
|
||||
|
||||
if index > 120 {
|
||||
self.chart.xAxis.axisMinimum = index - 120
|
||||
}
|
||||
self.chart.xAxis.axisMaximum = index
|
||||
self.chart.notifyDataSetChanged()
|
||||
self.chart.moveViewToX(index)
|
||||
}
|
||||
|
||||
func makeOverview() {
|
||||
let overviewLabel: NSView = NSView(frame: NSRect(x: 0, y: TabHeight - 140, width: TabWidth, height: 25))
|
||||
|
||||
overviewLabel.wantsLayer = true
|
||||
overviewLabel.layer?.backgroundColor = NSColor(hexString: "#eeeeee", alpha: 0.5).cgColor
|
||||
|
||||
let overviewText: NSTextField = NSTextField(string: "Overview")
|
||||
overviewText.frame = NSRect(x: 0, y: 0, width: TabWidth, height: overviewLabel.frame.size.height - 5)
|
||||
overviewText.isEditable = false
|
||||
overviewText.isSelectable = false
|
||||
overviewText.isBezeled = false
|
||||
overviewText.wantsLayer = true
|
||||
overviewText.textColor = .labelColor
|
||||
overviewText.canDrawSubviewsIntoLayer = true
|
||||
overviewText.alignment = .center
|
||||
overviewText.backgroundColor = NSColor(hexString: "#dddddd", alpha: 0)
|
||||
overviewText.font = NSFont.systemFont(ofSize: 12, weight: .medium)
|
||||
|
||||
overviewLabel.addSubview(overviewText)
|
||||
self.tabView.view?.addSubview(overviewLabel)
|
||||
|
||||
let stackHeight: CGFloat = 22
|
||||
let vertical: NSStackView = NSStackView(frame: NSRect(x: 0, y: 147, width: TabWidth, height: stackHeight*3))
|
||||
vertical.orientation = .vertical
|
||||
|
||||
let system: NSStackView = NSStackView(frame: NSRect(x: 10, y: stackHeight*2, width: TabWidth - 20, height: stackHeight))
|
||||
system.orientation = .horizontal
|
||||
system.distribution = .equalCentering
|
||||
let systemLabel = labelField(string: "System")
|
||||
let systemValue = valueField(string: "0 %")
|
||||
system.addView(systemLabel, in: .center)
|
||||
system.addView(systemValue, in: .center)
|
||||
|
||||
let user: NSStackView = NSStackView(frame: NSRect(x: 10, y: stackHeight*1, width: TabWidth - 20, height: stackHeight))
|
||||
user.orientation = .horizontal
|
||||
user.distribution = .equalCentering
|
||||
let userLabel = labelField(string: "User")
|
||||
let userValue = valueField(string: "0 %")
|
||||
user.addView(userLabel, in: .center)
|
||||
user.addView(userValue, in: .center)
|
||||
|
||||
let idle: NSStackView = NSStackView(frame: NSRect(x: 10, y: 0, width: TabWidth - 20, height: stackHeight))
|
||||
idle.orientation = .horizontal
|
||||
idle.distribution = .equalCentering
|
||||
let idleLabel = labelField(string: "Idle")
|
||||
let idleValue = valueField(string: "0 %")
|
||||
idle.addView(idleLabel, in: .center)
|
||||
idle.addView(idleValue, in: .center)
|
||||
|
||||
vertical.addSubview(system)
|
||||
vertical.addSubview(user)
|
||||
vertical.addSubview(idle)
|
||||
|
||||
self.tabView.view?.addSubview(vertical)
|
||||
|
||||
(self.reader as! CPUReader).usage.subscribe(observer: self) { (value, _) in
|
||||
systemValue.stringValue = "\(value.system.roundTo(decimalPlaces: 2)) %"
|
||||
userValue.stringValue = "\(value.user.roundTo(decimalPlaces: 2)) %"
|
||||
idleValue.stringValue = "\(value.idle.roundTo(decimalPlaces: 2)) %"
|
||||
}
|
||||
}
|
||||
|
||||
func makeProcesses() {
|
||||
let label: NSView = NSView(frame: NSRect(x: 0, y: 0, width: TabWidth, height: 25))
|
||||
|
||||
label.wantsLayer = true
|
||||
label.layer?.backgroundColor = NSColor(hexString: "#eeeeee", alpha: 0.5).cgColor
|
||||
|
||||
let text: NSTextField = NSTextField(string: "Top Processes")
|
||||
text.frame = NSRect(x: 0, y: 0, width: TabWidth, height: label.frame.size.height - 5)
|
||||
text.isEditable = false
|
||||
text.isSelectable = false
|
||||
text.isBezeled = false
|
||||
text.wantsLayer = true
|
||||
text.textColor = .labelColor
|
||||
text.canDrawSubviewsIntoLayer = true
|
||||
text.alignment = .center
|
||||
text.backgroundColor = NSColor(hexString: "#dddddd", alpha: 0)
|
||||
text.font = NSFont.systemFont(ofSize: 12, weight: .medium)
|
||||
|
||||
label.addSubview(text)
|
||||
self.tabView.view?.addSubview(label)
|
||||
|
||||
let stackHeight: CGFloat = 22
|
||||
let vertical: NSStackView = NSStackView(frame: NSRect(x: 0, y: 4, width: TabWidth, height: stackHeight*5))
|
||||
vertical.orientation = .vertical
|
||||
vertical.distribution = .fill
|
||||
|
||||
var processViewList: [NSStackView] = []
|
||||
let process_1 = makeProcessView(num: 4, height: stackHeight, label: "", value: "")
|
||||
let process_2 = makeProcessView(num: 3, height: stackHeight, label: "", value: "")
|
||||
let process_3 = makeProcessView(num: 2, height: stackHeight, label: "", value: "")
|
||||
let process_4 = makeProcessView(num: 1, height: stackHeight, label: "", value: "")
|
||||
let process_5 = makeProcessView(num: 0, height: stackHeight, label: "", value: "")
|
||||
|
||||
processViewList.append(process_1)
|
||||
processViewList.append(process_2)
|
||||
processViewList.append(process_3)
|
||||
processViewList.append(process_4)
|
||||
processViewList.append(process_5)
|
||||
|
||||
vertical.addSubview(process_1)
|
||||
vertical.addSubview(process_2)
|
||||
vertical.addSubview(process_3)
|
||||
vertical.addSubview(process_4)
|
||||
vertical.addSubview(process_5)
|
||||
self.tabView.view?.addSubview(vertical)
|
||||
|
||||
label.frame = NSRect(x: 0, y: vertical.frame.origin.y + vertical.frame.size.height + 2, width: TabWidth, height: 25)
|
||||
self.tabView.view?.addSubview(label)
|
||||
|
||||
(self.reader as! CPUReader).processes.subscribe(observer: self) { (processes, _) in
|
||||
for (i, process) in processes.enumerated() {
|
||||
let processView = processViewList[i]
|
||||
|
||||
(processView.subviews[0] as! NSTextField).stringValue = process.command
|
||||
(processView.subviews[1] as! NSTextField).stringValue = "\(process.usage.roundTo(decimalPlaces: 2)) %"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeProcessView(num: Int, height: CGFloat, label: String, value: String) -> NSStackView {
|
||||
let view: NSStackView = NSStackView(frame: NSRect(x: 10, y: CGFloat(num)*height, width: TabWidth - 20, height: height))
|
||||
view.orientation = .horizontal
|
||||
view.distribution = .equalCentering
|
||||
let viewLabel = labelField(string: label)
|
||||
let viewValue = valueField(string: value)
|
||||
view.addView(viewLabel, in: .center)
|
||||
view.addView(viewValue, in: .center)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func labelField(string: String) -> NSTextField {
|
||||
let label: NSTextField = NSTextField(string: string)
|
||||
|
||||
label.isEditable = false
|
||||
label.isSelectable = false
|
||||
label.isBezeled = false
|
||||
label.textColor = .labelColor
|
||||
label.alignment = .center
|
||||
label.font = NSFont.systemFont(ofSize: 12, weight: .regular)
|
||||
|
||||
return label
|
||||
}
|
||||
|
||||
func valueField(string: String) -> NSTextField {
|
||||
let label: NSTextField = NSTextField(string: string)
|
||||
|
||||
label.isEditable = false
|
||||
label.isSelectable = false
|
||||
label.isBezeled = false
|
||||
label.textColor = .black
|
||||
label.alignment = .center
|
||||
label.font = NSFont.systemFont(ofSize: 13, weight: .regular)
|
||||
|
||||
return label
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class Network: Module {
|
||||
var available: Observable<Bool>
|
||||
var reader: Reader = NetworkReader()
|
||||
var widgetType: WidgetType = 2.0
|
||||
var viewAvailable: Bool = true
|
||||
var viewAvailable: Bool = false
|
||||
var tabView: NSTabViewItem = NSTabViewItem()
|
||||
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
import Cocoa
|
||||
import ServiceManagement
|
||||
|
||||
let TabWidth: CGFloat = 300
|
||||
let TabHeight: CGFloat = 356
|
||||
public let TabWidth: CGFloat = 300
|
||||
public let TabHeight: CGFloat = 356
|
||||
|
||||
class MainViewController: NSViewController {
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
41
Stats/libs/ChartMarker.swift
Normal file
41
Stats/libs/ChartMarker.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ChartMarker.swift
|
||||
// Stats
|
||||
//
|
||||
// Created by Serhiy Mytrovtsiy on 03/09/2019.
|
||||
// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Foundation
|
||||
import Charts
|
||||
|
||||
class ChartMarker: MarkerView {
|
||||
var text = ""
|
||||
|
||||
override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
|
||||
super.refreshContent(entry: entry, highlight: highlight)
|
||||
text = String(entry.y)
|
||||
}
|
||||
|
||||
override func draw(context: CGContext, point: CGPoint) {
|
||||
super.draw(context: context, point: point)
|
||||
|
||||
var drawAttributes = [NSAttributedString.Key : Any]()
|
||||
drawAttributes[.font] = NSFont.systemFont(ofSize: 13)
|
||||
drawAttributes[.foregroundColor] = NSColor.white
|
||||
drawAttributes[.backgroundColor] = NSColor.darkGray
|
||||
|
||||
self.bounds.size = (" \(text) " as NSString).size(withAttributes: drawAttributes)
|
||||
self.offset = CGPoint(x: 0, y: self.bounds.size.height)
|
||||
|
||||
let offset = self.offsetForDrawing(atPoint: point)
|
||||
drawText(text: " \(text) " as NSString, rect: CGRect(origin: CGPoint(x: point.x + offset.x, y: point.y + offset.y), size: self.bounds.size), withAttributes: drawAttributes)
|
||||
}
|
||||
|
||||
func drawText(text: NSString, rect: CGRect, withAttributes attributes: [NSAttributedString.Key : Any]? = nil) {
|
||||
let size = text.size(withAttributes: attributes)
|
||||
let centeredRect = CGRect(x: rect.origin.x + (rect.size.width - size.width) / 2.0, y: rect.origin.y + (rect.size.height - size.height) / 2.0, width: size.width, height: size.height)
|
||||
text.draw(in: centeredRect, withAttributes: attributes)
|
||||
}
|
||||
}
|
||||
@@ -141,3 +141,34 @@ extension NSBezierPath {
|
||||
self.line(to: arrowLine2)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSColor {
|
||||
|
||||
convenience init(hexString: String, alpha: CGFloat = 1.0) {
|
||||
let hexString: String = hexString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
|
||||
let scanner = Scanner(string: hexString)
|
||||
if (hexString.hasPrefix("#")) {
|
||||
scanner.scanLocation = 1
|
||||
}
|
||||
var color: UInt32 = 0
|
||||
scanner.scanHexInt32(&color)
|
||||
let mask = 0x000000FF
|
||||
let r = Int(color >> 16) & mask
|
||||
let g = Int(color >> 8) & mask
|
||||
let b = Int(color) & mask
|
||||
let red = CGFloat(r) / 255.0
|
||||
let green = CGFloat(g) / 255.0
|
||||
let blue = CGFloat(b) / 255.0
|
||||
self.init(red:red, green:green, blue:blue, alpha:alpha)
|
||||
}
|
||||
|
||||
func toHexString() -> String {
|
||||
var r:CGFloat = 0
|
||||
var g:CGFloat = 0
|
||||
var b:CGFloat = 0
|
||||
var a:CGFloat = 0
|
||||
getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||
let rgb:Int = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
|
||||
return String(format:"#%06x", rgb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ protocol ObservableProtocol {
|
||||
var value: T { get set }
|
||||
func subscribe(observer: AnyObject, block: @escaping (_ newValue: T, _ oldValue: T) -> ())
|
||||
func unsubscribe(observer: AnyObject)
|
||||
func userDefaults(key: String)
|
||||
}
|
||||
|
||||
public final class Observable<T>: ObservableProtocol {
|
||||
@@ -34,7 +33,6 @@ public final class Observable<T>: ObservableProtocol {
|
||||
let (_, block) = entry
|
||||
block(value, oldValue)
|
||||
}
|
||||
updateUserDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +49,6 @@ public final class Observable<T>: ObservableProtocol {
|
||||
|
||||
observers = filtered
|
||||
}
|
||||
|
||||
func userDefaults(key: String) {
|
||||
self.userDefaultsKey = key
|
||||
}
|
||||
|
||||
func updateUserDefaults() {
|
||||
self.defaults.set(self.value, forKey: self.userDefaultsKey)
|
||||
}
|
||||
}
|
||||
|
||||
func <<<T>(observable: Observable<T>, value: T) {
|
||||
|
||||
Reference in New Issue
Block a user