├── .gitignore
├── OptiMac
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Icon-macOS-Dark-1024x1024@1x.png
│ │ └── Contents.json
│ ├── MenubarPhoenix.imageset
│ │ ├── menu_bar_icon-removebg-preview 2.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── OptiMacApp.swift
├── StatusBarController.swift
└── ContentView.swift
├── OptiMac.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── lukeedgar.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── lukeedgar.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── LICENSE
├── .github
└── workflows
│ └── build-release.yml
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | *.dmg
4 | *.pkg
5 | __pycache__/
6 | .DS_Store
7 |
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/AppIcon.appiconset/Icon-macOS-Dark-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VonKleistL/OptiMac/HEAD/OptiMac/Assets.xcassets/AppIcon.appiconset/Icon-macOS-Dark-1024x1024@1x.png
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/MenubarPhoenix.imageset/menu_bar_icon-removebg-preview 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VonKleistL/OptiMac/HEAD/OptiMac/Assets.xcassets/MenubarPhoenix.imageset/menu_bar_icon-removebg-preview 2.png
--------------------------------------------------------------------------------
/OptiMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/OptiMac.xcodeproj/project.xcworkspace/xcuserdata/lukeedgar.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VonKleistL/OptiMac/HEAD/OptiMac.xcodeproj/project.xcworkspace/xcuserdata/lukeedgar.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/OptiMac.xcodeproj/xcuserdata/lukeedgar.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | OptiMac.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/MenubarPhoenix.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "menu_bar_icon-removebg-preview 2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "localizable" : true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 DR LEVONK
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OptiMac/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "filename" : "Icon-macOS-Dark-1024x1024@1x.png",
50 | "idiom" : "mac",
51 | "scale" : "2x",
52 | "size" : "512x512"
53 | }
54 | ],
55 | "info" : {
56 | "author" : "xcode",
57 | "version" : 1
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/OptiMac/OptiMacApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OptiMacApp.swift
3 | // OptiMac
4 | //
5 | // Created by Luke Edgar on 27/10/2025.
6 | //
7 |
8 | import SwiftUI
9 | import AppKit
10 |
11 | // AppDelegate to help activate app and bring windows to front.
12 | final class AppDelegate: NSObject, NSApplicationDelegate {
13 | func applicationDidFinishLaunching(_ notification: Notification) {
14 | // Nothing special here; StatusBarController will be set up by the App.
15 | }
16 |
17 | func openMainAppWindow() {
18 | // Activate the app and bring the main window to front
19 | NSApp.activate(ignoringOtherApps: true)
20 | // If there’s no key window yet, SwiftUI will create one from the WindowGroup
21 | }
22 | }
23 |
24 | @main
25 | struct OptiMacApp: App {
26 | // Single shared monitor for both menu bar and main UI
27 | @StateObject private var systemMonitor: SystemMonitor
28 |
29 | // AppKit delegate
30 | @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
31 |
32 | // Keep the status bar controller alive for the app lifetime
33 | @State private var statusBarController: StatusBarController?
34 |
35 | init() {
36 | let monitor = SystemMonitor()
37 | _systemMonitor = StateObject(wrappedValue: monitor)
38 | _statusBarController = State(initialValue: nil)
39 | }
40 |
41 | var body: some Scene {
42 | WindowGroup {
43 | ContentView(systemMonitor: systemMonitor)
44 | .onAppear {
45 | if statusBarController == nil {
46 | statusBarController = StatusBarController(
47 | systemMonitor: systemMonitor,
48 | openMainApp: { [weak appDelegate] in
49 | appDelegate?.openMainAppWindow()
50 | }
51 | )
52 | }
53 | }
54 | }
55 | .commands {
56 | CommandGroup(after: .appInfo) {
57 | Button("Open OptiMac") {
58 | openMainApp()
59 | }
60 | .keyboardShortcut("o", modifiers: [.command, .shift])
61 | }
62 | }
63 | }
64 |
65 | private func openMainApp() {
66 | appDelegate.openMainAppWindow()
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/.github/workflows/build-release.yml:
--------------------------------------------------------------------------------
1 | name: Build and Release OptiMac Enhanced
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*' # Trigger on version tags like v2.0.0
7 | workflow_dispatch: # Allow manual triggers
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-latest
12 |
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v4
16 |
17 | - name: Set up Python
18 | uses: actions/setup-python@v4
19 | with:
20 | python-version: '3.11'
21 |
22 | - name: Install dependencies
23 | run: |
24 | python -m pip install --upgrade pip
25 | pip install -r requirements.txt
26 | brew install create-dmg
27 |
28 | - name: Build app bundle
29 | run: |
30 | python setup.py py2app
31 |
32 | - name: Create DMG
33 | run: |
34 | chmod +x build_dmg.sh
35 | ./build_dmg.sh
36 |
37 | - name: Get version from tag
38 | id: get_version
39 | run: |
40 | if [[ $GITHUB_REF == refs/tags/* ]]; then
41 | echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
42 | else
43 | echo "VERSION=dev-$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT
44 | fi
45 |
46 | - name: Upload DMG artifact
47 | uses: actions/upload-artifact@v4
48 | with:
49 | name: OptiMac-Enhanced-${{ steps.get_version.outputs.VERSION }}
50 | path: '*.dmg'
51 |
52 | - name: Create Release
53 | if: startsWith(github.ref, 'refs/tags/')
54 | uses: softprops/action-gh-release@v1
55 | with:
56 | tag_name: ${{ github.ref }}
57 | name: OptiMac Enhanced v${{ steps.get_version.outputs.VERSION }}
58 | body: |
59 | # OptiMac Enhanced v${{ steps.get_version.outputs.VERSION }}
60 |
61 | ## What's New
62 | 🎉 **Enhanced OptiMac with exciting new features!**
63 |
64 | ### ✨ New Features
65 | - 🍎 **Menu Bar Integration** - Quick access from your menu bar
66 | - 👤 **User Profiles** - Save and switch between optimization profiles
67 | - 🔍 **Spotlight Re-indexing** - Rebuild Spotlight index for better search
68 | - 🔄 **Auto-Updates** - Automatic update checking and notifications
69 |
70 | ### 🛠️ Improvements
71 | - Enhanced GUI with better organization
72 | - Improved performance and stability
73 | - Better error handling and logging
74 | - Streamlined user experience
75 |
76 | ### 📦 Installation
77 | 1. Download the DMG file below
78 | 2. Open the DMG and drag OptiMac Enhanced to Applications
79 | 3. Launch from Applications or enable menu bar mode
80 |
81 | ### 🔧 System Requirements
82 | - macOS 10.15 (Catalina) or later
83 | - Apple Silicon (M1/M2/M3) or Intel Mac
84 | - Administrator privileges for system optimizations
85 |
86 | ### ⚠️ Important Notes
87 | - Always backup your system before running optimizations
88 | - Some optimizations may require a restart to take effect
89 | - Use advanced options with caution
90 |
91 | **Full Changelog**: https://github.com/VonKleistL/OptiMac/compare/v1.0.0...v${{ steps.get_version.outputs.VERSION }}
92 | files: '*.dmg'
93 | draft: false
94 | prerelease: false
95 | env:
96 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
97 |
98 | - name: Update latest release info
99 | if: startsWith(github.ref, 'refs/tags/')
100 | run: |
101 | echo "Release created successfully!"
102 | echo "Users will now be notified of the update through the app."
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |
4 |
5 | # OptiMac v3.0 - Advanced MacOS Optimization Suite (Now in SwiftUI)
6 |
7 | **MacOS optimisation tool written in native swiftUI. Clean, easy to use and most importantly incredibly minimal on resources.
8 | ## What's New in v3.0
9 |
10 | ## Key Features
11 |
12 | ### Memory & Performance
13 | - **Purge inactive memory** - Instantly free up RAM for better responsiveness
14 | - **Clear system caches** - Remove accumulated cache files eating up storage
15 | - **Optimize swap settings** - Fine-tune virtual memory for your specific hardware
16 | - **Disable/Enable Spotlight indexing** - Control resource-heavy background indexing
17 | - **Re-index Spotlight** - Rebuild search index for better performance
18 | - **Reduce system animations** - Eliminate UI lag for snappier interactions
19 |
20 | ### System Tweaks
21 | - **Remove Dock animations** - Instant Dock show/hide for faster workflow
22 | - **Disable Finder animations** - Speed up file browser operations
23 | - **Optimize Launchpad** - Eliminate delays when accessing applications
24 | - **Disable Dashboard** - Free up system resources from unused features
25 | - **Enable SSD TRIM** - Maintain optimal SSD performance and longevity
26 |
27 | ### Network Optimizations
28 | - **DNS cache flushing** - Resolve connectivity issues and speed up browsing
29 | - **TCP/IP optimization** - Fine-tune network stack for better performance
30 | - **Wi-Fi enhancements** - Optimize wireless connectivity settings
31 | - **IPv6 management** - Disable if causing network conflicts
32 |
33 | ### Developer Environment
34 | - **Python/Conda optimization** - Perfect setup for Apple Silicon development
35 | - **Git performance tuning** - Speed up version control operations
36 | - **Homebrew cleanup** - Optimize package manager for better performance
37 | - **Node.js configuration** - Native Apple Silicon setup for web development
38 |
39 | ## Installation Options
40 |
41 | ### Option 1: DMG Installer (Recommended)
42 | 1. **Download** the latest `OptiMac-DMG Installer from [Releases](https://github.com/VonKleistL/OptiMac/releases)
43 | 2. **Open** the DMG file
44 | 3. **Drag** OptiMac to your Applications folder
45 | 4. **Launch** from Applications
46 |
47 | ## Option 2: Build from source
48 |
49 | ```bash
50 | git clone https://github.com/VonKleistL/OptiMac.git
51 | cd OptiMac
52 | ### Building DMG
53 | ```bash
54 | chmod +x build_dmg.sh
55 | ./build_dmg.sh
56 | ```
57 |
58 | ## Usage Modes
59 |
60 | ### **Full GUI Mode**
61 | - Complete interface with all optimization options
62 | - Profile management and advanced settings
63 | - Detailed logging and progress tracking
64 | - Perfect for thorough system optimization
65 |
66 | ### **Menu Bar Mode**
67 | - Lightweight system tray integration
68 | - Quick access to common optimizations
69 | - Profile execution with one click
70 | - Ideal for daily maintenance tasks
71 |
72 | ## Safety First
73 |
74 | OptiMac Enhanced prioritizes system stability:
75 | - **Non-destructive changes** - All optimizations are reversible
76 | - **Backup integration** - Automatic Time Machine backups before major changes
77 | - **Confirmation dialogs** - Prevent accidental system modifications
78 | - **Detailed logging** - Track exactly what changes were made
79 | - **Safe defaults** - Conservative settings that work for everyone
80 | - **Profile validation** - Ensure safe profile configurations
81 |
82 | ## System Requirements
83 |
84 | - **macOS 15+ +** (Sequoia or later)
85 | - **Apple Silicon Mac** (M1, M1 Pro/Max, M2, M2 Pro/Max, M3, M3 Pro/Max)
86 | - **Python 3.8+** (pre-installed on macOS)
87 | - **Administrator privileges** (for system-level optimizations)
88 | - **Internet connection** (for update checking)
89 |
90 | ## Building from Source
91 |
92 | This creates a distributable DMG file ready for sharing!
93 |
94 | ## Contributing
95 |
96 | OptiMac is open source and welcomes contributions!
97 |
98 | - ** Bug Reports** - Help me improve stability
99 | - ** Feature Requests** - Share optimization ideas
100 | - ** Code Contributions** - Add new optimizations or improve the UI
101 | - ** Documentation** - Help other users get the most out of OptiMac
102 | - ** UI/UX Improvements** - Make the interface even better
103 |
104 | ## Support & Community
105 |
106 | - ** Bug Reports**: [GitHub Issues](https://github.com/VonKleistL/OptiMac/issues)
107 | - ** Discussions**: [GitHub Discussions](https://github.com/VonKleistL/OptiMac/discussions)
108 | - ** Direct Contact**: Open an issue for personalized support
109 | - ** Feature Requests**: Use GitHub Issues with the "enhancement" label
110 |
111 | ## License
112 |
113 | OptiMac is released under the [MIT License](LICENSE), making it free to use, modify, and distribute.
114 |
115 | ## Support the Project
116 |
117 | If OptiMac helped speed up your Mac:
118 | - ** Star the repository** to help others discover it
119 | - ** Share on social media** - Spread the word to fellow Mac users
120 | - ** Contribute code** - Help make OptiMac even better
121 | - ** Buy me a coffee** - Support continued development
122 |
123 | ---
124 |
125 |
126 | *Built for the Apple Silicon Mac community by [VonKleistL](https://github.com/VonKleistL)*
127 |
128 | 
129 | 
130 |
--------------------------------------------------------------------------------
/OptiMac/StatusBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StatusBarController.swift
3 | // OptiMac
4 | //
5 | // Creates the NSStatusItem with a Phoenix icon and quick actions.
6 | //
7 |
8 | import AppKit
9 | import SwiftUI
10 |
11 | final class StatusBarController {
12 | private let statusItem: NSStatusItem
13 | private let menu = NSMenu()
14 | private weak var systemMonitor: SystemMonitor?
15 | private let openMainApp: () -> Void
16 |
17 | init(systemMonitor: SystemMonitor, openMainApp: @escaping () -> Void) {
18 | self.systemMonitor = systemMonitor
19 | self.openMainApp = openMainApp
20 |
21 | // Use a fixed length so the item doesn't collapse if the image fails to load
22 | self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
23 |
24 | configureButtonImage()
25 |
26 | constructMenu()
27 | statusItem.menu = menu
28 | }
29 |
30 | private func configureButtonImage() {
31 | guard let button = statusItem.button else { return }
32 |
33 | if let img = NSImage(named: "MenubarPhoenix") {
34 | // Full-color asset
35 | img.isTemplate = false
36 | button.image = img
37 | button.imageScaling = .scaleProportionallyDown
38 | button.appearsDisabled = false
39 | } else {
40 | // Fallback: programmatic template icon so it's never invisible
41 | #if DEBUG
42 | print("Warning: MenubarPhoenix asset not found. Falling back to template icon.")
43 | #endif
44 | let fallback = Self.phoenixIcon(isTemplate: true)
45 | button.image = fallback
46 | button.imageScaling = .scaleProportionallyDown
47 | button.appearsDisabled = false
48 | }
49 | }
50 |
51 | private func constructMenu() {
52 | menu.items.removeAll()
53 |
54 | // Five quick actions
55 | menu.addItem(withTitle: "Purge Inactive Memory", action: #selector(purgeMemory), keyEquivalent: "")
56 | menu.addItem(withTitle: "Flush DNS Cache", action: #selector(flushDNS), keyEquivalent: "")
57 | menu.addItem(withTitle: "Clear System Caches", action: #selector(clearCaches), keyEquivalent: "")
58 | menu.addItem(withTitle: "Clean Homebrew", action: #selector(cleanHomebrew), keyEquivalent: "")
59 | menu.addItem(withTitle: "Rebuild Spotlight Index", action: #selector(rebuildSpotlight), keyEquivalent: "")
60 |
61 | menu.addItem(NSMenuItem.separator())
62 |
63 | // Open main app
64 | let openItem = NSMenuItem(title: "Open OptiMac", action: #selector(openApp), keyEquivalent: "")
65 | menu.addItem(openItem)
66 |
67 | // Quit
68 | let quitItem = NSMenuItem(title: "Quit", action: #selector(quitApp), keyEquivalent: "q")
69 | menu.addItem(quitItem)
70 |
71 | // Target
72 | for item in menu.items {
73 | item.target = self
74 | }
75 | }
76 |
77 | // MARK: - Actions (wired to SystemMonitor quick task ids)
78 | @objc private func purgeMemory() { runTasks(ids: ["purge_memory"]) }
79 | @objc private func flushDNS() { runTasks(ids: ["flush_dns"]) }
80 | @objc private func clearCaches() { runTasks(ids: ["clear_caches"]) }
81 | @objc private func cleanHomebrew() { runTasks(ids: ["optimize_homebrew"]) }
82 | @objc private func rebuildSpotlight() { runTasks(ids: ["reindex_spotlight"]) }
83 |
84 | @objc private func openApp() {
85 | openMainApp()
86 | }
87 |
88 | @objc private func quitApp() {
89 | NSApp.terminate(nil)
90 | }
91 |
92 | private func runTasks(ids: [String]) {
93 | guard let monitor = systemMonitor else { return }
94 | monitor.selectedTasks = Set(ids)
95 | monitor.runOptimization()
96 | }
97 |
98 | // MARK: - Phoenix Icon (template fallback)
99 | static func phoenixIcon(isTemplate: Bool) -> NSImage {
100 | let size = NSSize(width: 18, height: 18)
101 | let image = NSImage(size: size)
102 | image.lockFocus()
103 |
104 | let bounds = NSRect(origin: .zero, size: size)
105 | let center = CGPoint(x: bounds.midX, y: bounds.midY)
106 |
107 | let primary = NSColor.white
108 | let secondary = NSColor.white.withAlphaComponent(0.9)
109 |
110 | let body = NSBezierPath()
111 | body.move(to: CGPoint(x: center.x, y: 2))
112 | body.curve(to: CGPoint(x: 2, y: center.y),
113 | controlPoint1: CGPoint(x: center.x - 5, y: 2),
114 | controlPoint2: CGPoint(x: 2, y: center.y - 4))
115 | body.curve(to: CGPoint(x: center.x, y: size.height - 2),
116 | controlPoint1: CGPoint(x: 2, y: center.y + 6),
117 | controlPoint2: CGPoint(x: center.x - 3, y: size.height - 2))
118 | body.curve(to: CGPoint(x: size.width - 2, y: center.y),
119 | controlPoint1: CGPoint(x: center.x + 3, y: size.height - 2),
120 | controlPoint2: CGPoint(x: size.width - 2, y: center.y + 6))
121 | body.curve(to: CGPoint(x: center.x, y: 2),
122 | controlPoint1: CGPoint(x: size.width - 2, y: center.y - 4),
123 | controlPoint2: CGPoint(x: center.x + 5, y: 2))
124 | primary.setFill()
125 | body.fill()
126 |
127 | let leftWing = NSBezierPath()
128 | leftWing.move(to: CGPoint(x: center.x - 2, y: center.y + 2))
129 | leftWing.curve(to: CGPoint(x: 1, y: center.y + 1),
130 | controlPoint1: CGPoint(x: center.x - 7, y: center.y + 6),
131 | controlPoint2: CGPoint(x: 2, y: center.y + 4))
132 | leftWing.curve(to: CGPoint(x: center.x - 1, y: center.y - 1),
133 | controlPoint1: CGPoint(x: 0, y: center.y),
134 | controlPoint2: CGPoint(x: center.x - 4, y: center.y - 2))
135 | secondary.setFill()
136 | leftWing.fill()
137 |
138 | let rightWing = NSBezierPath()
139 | rightWing.move(to: CGPoint(x: center.x + 2, y: center.y + 2))
140 | rightWing.curve(to: CGPoint(x: size.width - 1, y: center.y + 1),
141 | controlPoint1: CGPoint(x: center.x + 7, y: center.y + 6),
142 | controlPoint2: CGPoint(x: size.width - 2, y: center.y + 4))
143 | rightWing.curve(to: CGPoint(x: center.x + 1, y: center.y - 1),
144 | controlPoint1: CGPoint(x: size.width, y: center.y),
145 | controlPoint2: CGPoint(x: center.x + 4, y: center.y - 2))
146 | secondary.setFill()
147 | rightWing.fill()
148 |
149 | image.unlockFocus()
150 | image.isTemplate = isTemplate
151 | return image
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/OptiMac.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXFileReference section */
10 | 75D219372EAF4D4200824356 /* OptiMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OptiMac.app; sourceTree = BUILT_PRODUCTS_DIR; };
11 | /* End PBXFileReference section */
12 |
13 | /* Begin PBXFileSystemSynchronizedRootGroup section */
14 | 75D219392EAF4D4200824356 /* OptiMac */ = {
15 | isa = PBXFileSystemSynchronizedRootGroup;
16 | path = OptiMac;
17 | sourceTree = "";
18 | };
19 | /* End PBXFileSystemSynchronizedRootGroup section */
20 |
21 | /* Begin PBXFrameworksBuildPhase section */
22 | 75D219342EAF4D4200824356 /* Frameworks */ = {
23 | isa = PBXFrameworksBuildPhase;
24 | buildActionMask = 2147483647;
25 | files = (
26 | );
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXFrameworksBuildPhase section */
30 |
31 | /* Begin PBXGroup section */
32 | 75D2192E2EAF4D4200824356 = {
33 | isa = PBXGroup;
34 | children = (
35 | 75D219392EAF4D4200824356 /* OptiMac */,
36 | 75D219382EAF4D4200824356 /* Products */,
37 | );
38 | sourceTree = "";
39 | };
40 | 75D219382EAF4D4200824356 /* Products */ = {
41 | isa = PBXGroup;
42 | children = (
43 | 75D219372EAF4D4200824356 /* OptiMac.app */,
44 | );
45 | name = Products;
46 | sourceTree = "";
47 | };
48 | /* End PBXGroup section */
49 |
50 | /* Begin PBXNativeTarget section */
51 | 75D219362EAF4D4200824356 /* OptiMac */ = {
52 | isa = PBXNativeTarget;
53 | buildConfigurationList = 75D219422EAF4D4400824356 /* Build configuration list for PBXNativeTarget "OptiMac" */;
54 | buildPhases = (
55 | 75D219332EAF4D4200824356 /* Sources */,
56 | 75D219342EAF4D4200824356 /* Frameworks */,
57 | 75D219352EAF4D4200824356 /* Resources */,
58 | );
59 | buildRules = (
60 | );
61 | dependencies = (
62 | );
63 | fileSystemSynchronizedGroups = (
64 | 75D219392EAF4D4200824356 /* OptiMac */,
65 | );
66 | name = OptiMac;
67 | packageProductDependencies = (
68 | );
69 | productName = OptiMac;
70 | productReference = 75D219372EAF4D4200824356 /* OptiMac.app */;
71 | productType = "com.apple.product-type.application";
72 | };
73 | /* End PBXNativeTarget section */
74 |
75 | /* Begin PBXProject section */
76 | 75D2192F2EAF4D4200824356 /* Project object */ = {
77 | isa = PBXProject;
78 | attributes = {
79 | BuildIndependentTargetsInParallel = 1;
80 | LastSwiftUpdateCheck = 2610;
81 | LastUpgradeCheck = 2610;
82 | TargetAttributes = {
83 | 75D219362EAF4D4200824356 = {
84 | CreatedOnToolsVersion = 26.1;
85 | };
86 | };
87 | };
88 | buildConfigurationList = 75D219322EAF4D4200824356 /* Build configuration list for PBXProject "OptiMac" */;
89 | developmentRegion = en;
90 | hasScannedForEncodings = 0;
91 | knownRegions = (
92 | en,
93 | Base,
94 | );
95 | mainGroup = 75D2192E2EAF4D4200824356;
96 | minimizedProjectReferenceProxies = 1;
97 | preferredProjectObjectVersion = 77;
98 | productRefGroup = 75D219382EAF4D4200824356 /* Products */;
99 | projectDirPath = "";
100 | projectRoot = "";
101 | targets = (
102 | 75D219362EAF4D4200824356 /* OptiMac */,
103 | );
104 | };
105 | /* End PBXProject section */
106 |
107 | /* Begin PBXResourcesBuildPhase section */
108 | 75D219352EAF4D4200824356 /* Resources */ = {
109 | isa = PBXResourcesBuildPhase;
110 | buildActionMask = 2147483647;
111 | files = (
112 | );
113 | runOnlyForDeploymentPostprocessing = 0;
114 | };
115 | /* End PBXResourcesBuildPhase section */
116 |
117 | /* Begin PBXSourcesBuildPhase section */
118 | 75D219332EAF4D4200824356 /* Sources */ = {
119 | isa = PBXSourcesBuildPhase;
120 | buildActionMask = 2147483647;
121 | files = (
122 | );
123 | runOnlyForDeploymentPostprocessing = 0;
124 | };
125 | /* End PBXSourcesBuildPhase section */
126 |
127 | /* Begin XCBuildConfiguration section */
128 | 75D219402EAF4D4400824356 /* Debug */ = {
129 | isa = XCBuildConfiguration;
130 | buildSettings = {
131 | ALWAYS_SEARCH_USER_PATHS = NO;
132 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
133 | CLANG_ANALYZER_NONNULL = YES;
134 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
135 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
136 | CLANG_ENABLE_MODULES = YES;
137 | CLANG_ENABLE_OBJC_ARC = YES;
138 | CLANG_ENABLE_OBJC_WEAK = YES;
139 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
140 | CLANG_WARN_BOOL_CONVERSION = YES;
141 | CLANG_WARN_COMMA = YES;
142 | CLANG_WARN_CONSTANT_CONVERSION = YES;
143 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
144 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
145 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
146 | CLANG_WARN_EMPTY_BODY = YES;
147 | CLANG_WARN_ENUM_CONVERSION = YES;
148 | CLANG_WARN_INFINITE_RECURSION = YES;
149 | CLANG_WARN_INT_CONVERSION = YES;
150 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
151 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
152 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
153 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
154 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
155 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
156 | CLANG_WARN_STRICT_PROTOTYPES = YES;
157 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
158 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
159 | CLANG_WARN_UNREACHABLE_CODE = YES;
160 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
161 | COPY_PHASE_STRIP = NO;
162 | DEBUG_INFORMATION_FORMAT = dwarf;
163 | DEVELOPMENT_TEAM = DYUP26D449;
164 | ENABLE_STRICT_OBJC_MSGSEND = YES;
165 | ENABLE_TESTABILITY = YES;
166 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
167 | GCC_C_LANGUAGE_STANDARD = gnu17;
168 | GCC_DYNAMIC_NO_PIC = NO;
169 | GCC_NO_COMMON_BLOCKS = YES;
170 | GCC_OPTIMIZATION_LEVEL = 0;
171 | GCC_PREPROCESSOR_DEFINITIONS = (
172 | "DEBUG=1",
173 | "$(inherited)",
174 | );
175 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
176 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
177 | GCC_WARN_UNDECLARED_SELECTOR = YES;
178 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
179 | GCC_WARN_UNUSED_FUNCTION = YES;
180 | GCC_WARN_UNUSED_VARIABLE = YES;
181 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
182 | MACOSX_DEPLOYMENT_TARGET = 26.1;
183 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
184 | MTL_FAST_MATH = YES;
185 | ONLY_ACTIVE_ARCH = YES;
186 | SDKROOT = macosx;
187 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
188 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
189 | };
190 | name = Debug;
191 | };
192 | 75D219412EAF4D4400824356 /* Release */ = {
193 | isa = XCBuildConfiguration;
194 | buildSettings = {
195 | ALWAYS_SEARCH_USER_PATHS = NO;
196 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
197 | CLANG_ANALYZER_NONNULL = YES;
198 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
200 | CLANG_ENABLE_MODULES = YES;
201 | CLANG_ENABLE_OBJC_ARC = YES;
202 | CLANG_ENABLE_OBJC_WEAK = YES;
203 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
204 | CLANG_WARN_BOOL_CONVERSION = YES;
205 | CLANG_WARN_COMMA = YES;
206 | CLANG_WARN_CONSTANT_CONVERSION = YES;
207 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
208 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
209 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
210 | CLANG_WARN_EMPTY_BODY = YES;
211 | CLANG_WARN_ENUM_CONVERSION = YES;
212 | CLANG_WARN_INFINITE_RECURSION = YES;
213 | CLANG_WARN_INT_CONVERSION = YES;
214 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
215 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
216 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
217 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
218 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
220 | CLANG_WARN_STRICT_PROTOTYPES = YES;
221 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
223 | CLANG_WARN_UNREACHABLE_CODE = YES;
224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
225 | COPY_PHASE_STRIP = NO;
226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
227 | DEVELOPMENT_TEAM = DYUP26D449;
228 | ENABLE_NS_ASSERTIONS = NO;
229 | ENABLE_STRICT_OBJC_MSGSEND = YES;
230 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
231 | GCC_C_LANGUAGE_STANDARD = gnu17;
232 | GCC_NO_COMMON_BLOCKS = YES;
233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
235 | GCC_WARN_UNDECLARED_SELECTOR = YES;
236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
237 | GCC_WARN_UNUSED_FUNCTION = YES;
238 | GCC_WARN_UNUSED_VARIABLE = YES;
239 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
240 | MACOSX_DEPLOYMENT_TARGET = 26.1;
241 | MTL_ENABLE_DEBUG_INFO = NO;
242 | MTL_FAST_MATH = YES;
243 | SDKROOT = macosx;
244 | SWIFT_COMPILATION_MODE = wholemodule;
245 | };
246 | name = Release;
247 | };
248 | 75D219432EAF4D4400824356 /* Debug */ = {
249 | isa = XCBuildConfiguration;
250 | buildSettings = {
251 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
252 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
253 | CODE_SIGN_STYLE = Automatic;
254 | COMBINE_HIDPI_IMAGES = YES;
255 | CURRENT_PROJECT_VERSION = 1;
256 | DEVELOPMENT_TEAM = DYUP26D449;
257 | ENABLE_APP_SANDBOX = YES;
258 | ENABLE_HARDENED_RUNTIME = YES;
259 | ENABLE_PREVIEWS = YES;
260 | ENABLE_USER_SELECTED_FILES = readonly;
261 | GENERATE_INFOPLIST_FILE = YES;
262 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
263 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
264 | LD_RUNPATH_SEARCH_PATHS = (
265 | "$(inherited)",
266 | "@executable_path/../Frameworks",
267 | );
268 | MARKETING_VERSION = 1.0;
269 | PRODUCT_BUNDLE_IDENTIFIER = com.vonkleistl.OptiMac.OptiMac;
270 | PRODUCT_NAME = "$(TARGET_NAME)";
271 | REGISTER_APP_GROUPS = YES;
272 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
273 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
274 | SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
275 | SWIFT_EMIT_LOC_STRINGS = YES;
276 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
277 | SWIFT_VERSION = 5.0;
278 | };
279 | name = Debug;
280 | };
281 | 75D219442EAF4D4400824356 /* Release */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
285 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
286 | CODE_SIGN_STYLE = Automatic;
287 | COMBINE_HIDPI_IMAGES = YES;
288 | CURRENT_PROJECT_VERSION = 1;
289 | DEVELOPMENT_TEAM = DYUP26D449;
290 | ENABLE_APP_SANDBOX = YES;
291 | ENABLE_HARDENED_RUNTIME = YES;
292 | ENABLE_PREVIEWS = YES;
293 | ENABLE_USER_SELECTED_FILES = readonly;
294 | GENERATE_INFOPLIST_FILE = YES;
295 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
296 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
297 | LD_RUNPATH_SEARCH_PATHS = (
298 | "$(inherited)",
299 | "@executable_path/../Frameworks",
300 | );
301 | MARKETING_VERSION = 1.0;
302 | PRODUCT_BUNDLE_IDENTIFIER = com.vonkleistl.OptiMac.OptiMac;
303 | PRODUCT_NAME = "$(TARGET_NAME)";
304 | REGISTER_APP_GROUPS = YES;
305 | STRING_CATALOG_GENERATE_SYMBOLS = YES;
306 | SWIFT_APPROACHABLE_CONCURRENCY = YES;
307 | SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
308 | SWIFT_EMIT_LOC_STRINGS = YES;
309 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
310 | SWIFT_VERSION = 5.0;
311 | };
312 | name = Release;
313 | };
314 | /* End XCBuildConfiguration section */
315 |
316 | /* Begin XCConfigurationList section */
317 | 75D219322EAF4D4200824356 /* Build configuration list for PBXProject "OptiMac" */ = {
318 | isa = XCConfigurationList;
319 | buildConfigurations = (
320 | 75D219402EAF4D4400824356 /* Debug */,
321 | 75D219412EAF4D4400824356 /* Release */,
322 | );
323 | defaultConfigurationIsVisible = 0;
324 | defaultConfigurationName = Release;
325 | };
326 | 75D219422EAF4D4400824356 /* Build configuration list for PBXNativeTarget "OptiMac" */ = {
327 | isa = XCConfigurationList;
328 | buildConfigurations = (
329 | 75D219432EAF4D4400824356 /* Debug */,
330 | 75D219442EAF4D4400824356 /* Release */,
331 | );
332 | defaultConfigurationIsVisible = 0;
333 | defaultConfigurationName = Release;
334 | };
335 | /* End XCConfigurationList section */
336 | };
337 | rootObject = 75D2192F2EAF4D4200824356 /* Project object */;
338 | }
339 |
--------------------------------------------------------------------------------
/OptiMac/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // OptiMac
4 | //
5 | // Real System Monitoring with Actual macOS System Calls
6 | //
7 |
8 | import SwiftUI
9 | import Charts
10 | import Foundation
11 | import Combine
12 | import Darwin
13 |
14 | // Fallback if the constant isn’t visible for some SDKs (Apple defines it as 4096)
15 | let PROC_PIDPATHINFO_MAXSIZE: Int32 = 4096
16 |
17 | // MARK: - Real System Data Models
18 | struct ProcessInfo: Identifiable {
19 | let id = UUID()
20 | let pid: Int32
21 | let name: String
22 | let cpuUsage: Double
23 | let memoryUsage: Double // in MB
24 | let color: Color
25 | }
26 |
27 | struct RealMemoryInfo {
28 | let totalMemory: Double // in GB
29 | let usedMemory: Double // in GB
30 | let freeMemory: Double // in GB
31 | let appMemoryUsage: [ProcessInfo]
32 | let swapUsed: Double // in GB
33 | }
34 |
35 | struct NetworkSpeed {
36 | let downloadBytesPerSec: Double
37 | let uploadBytesPerSec: Double
38 | let timestamp: Date
39 |
40 | var downloadMbps: Double {
41 | return (downloadBytesPerSec * 8) / (1024 * 1024) // Convert to Mbps
42 | }
43 |
44 | var uploadMbps: Double {
45 | return (uploadBytesPerSec * 8) / (1024 * 1024) // Convert to Mbps
46 | }
47 | }
48 |
49 | struct UrgentProcess: Identifiable {
50 | let id = UUID()
51 | let pid: Int32
52 | let name: String
53 | let issue: String
54 | let cpuUsage: Double
55 | let memoryUsage: Double
56 | let priority: UrgentPriority
57 | }
58 |
59 | enum UrgentPriority {
60 | case high, medium, low
61 |
62 | var color: Color {
63 | switch self {
64 | case .high: return Color(red: 1.00, green: 0.22, blue: 0.30) // crisper red
65 | case .medium: return Color(red: 1.00, green: 0.55, blue: 0.00) // vivid orange
66 | case .low: return Color(red: 1.00, green: 0.84, blue: 0.00) // bright yellow
67 | }
68 | }
69 | }
70 |
71 | // MARK: - Real System Monitor Class
72 | class RealSystemMonitor: ObservableObject {
73 | @Published var memoryInfo = RealMemoryInfo(totalMemory: 0, usedMemory: 0, freeMemory: 0, appMemoryUsage: [], swapUsed: 0)
74 | @Published var cpuProcesses: [ProcessInfo] = []
75 | @Published var networkHistory: [NetworkSpeed] = []
76 | @Published var urgentProcesses: [UrgentProcess] = []
77 | @Published var totalCPUUsage: Double = 0
78 |
79 | private var previousNetworkStats: (rx: UInt64, tx: UInt64) = (0, 0)
80 | private var lastNetworkUpdate = Date()
81 | private let appColors: [Color] = [
82 | Color(red: 0.20, green: 0.60, blue: 1.00),
83 | Color(red: 0.20, green: 0.85, blue: 0.50),
84 | Color(red: 1.00, green: 0.55, blue: 0.00),
85 | Color(red: 0.60, green: 0.40, blue: 1.00),
86 | Color(red: 1.00, green: 0.22, blue: 0.30),
87 | Color(red: 1.00, green: 0.40, blue: 0.70),
88 | Color(red: 0.10, green: 0.80, blue: 0.90),
89 | Color(red: 1.00, green: 0.84, blue: 0.00),
90 | Color(red: 0.60, green: 0.45, blue: 0.30),
91 | Color(red: 0.40, green: 0.40, blue: 1.00)
92 | ]
93 | private var processColorMap: [String: Color] = [:]
94 |
95 | // CPU sampling state
96 | private var lastCPUTimeStamp: TimeInterval = 0
97 | private var lastSystemCPUTicks: (user: UInt32, system: UInt32, nice: UInt32, idle: UInt32)?
98 | private var lastPerProcessCPUTimeNs: [Int32: UInt64] = [:] // pid -> total (user+system) ns
99 |
100 | private var updateTimer: Timer?
101 | private let numCores = Double(Foundation.ProcessInfo.processInfo.processorCount)
102 |
103 | init() {
104 | startRealTimeMonitoring()
105 | }
106 |
107 | private func startRealTimeMonitoring() {
108 | // Initial update
109 | updateAllSystemData()
110 |
111 | // Update every 2 seconds
112 | updateTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { _ in
113 | Task { @MainActor in
114 | self.updateAllSystemData()
115 | }
116 | }
117 | }
118 |
119 | private func updateAllSystemData() {
120 | updateMemoryInfo()
121 | updateCPUInfo()
122 | updateNetworkInfo()
123 | updateUrgentProcesses()
124 | }
125 |
126 | // MARK: - Real Memory Monitoring (Activity Monitor parity)
127 | private func updateMemoryInfo() {
128 | var stats = vm_statistics64()
129 | var count = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size)
130 |
131 | let result = withUnsafeMutablePointer(to: &stats) {
132 | $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
133 | host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
134 | }
135 | }
136 |
137 | if result == KERN_SUCCESS {
138 | let pageSize = Double(vm_kernel_page_size)
139 | let totalBytes = Double(Foundation.ProcessInfo.processInfo.physicalMemory)
140 |
141 | // Match “Memory Used” in Activity Monitor:
142 | // used = active + wired + compressed
143 | // free = free + inactive (as displayed in AM “Memory Pressure” details)
144 | let usedBytes = (Double(stats.active_count)
145 | + Double(stats.wire_count)
146 | + Double(stats.compressor_page_count)) * pageSize
147 | let freeBytes = (Double(stats.free_count) + Double(stats.inactive_count)) * pageSize
148 |
149 | let totalGB = totalBytes / (1024 * 1024 * 1024)
150 | let usedGB = max(usedBytes, 0) / (1024 * 1024 * 1024)
151 | let freeGB = max(freeBytes, 0) / (1024 * 1024 * 1024)
152 |
153 | // Get per-process memory via proc_pidinfo (resident size)
154 | let processes = getRealProcessList()
155 | let topMemoryProcesses = Array(processes.sorted { $0.memoryUsage > $1.memoryUsage }.prefix(6))
156 |
157 | memoryInfo = RealMemoryInfo(
158 | totalMemory: totalGB,
159 | usedMemory: usedGB,
160 | freeMemory: freeGB,
161 | appMemoryUsage: topMemoryProcesses,
162 | swapUsed: 0 // Could be added via sysctl vm.swapusage if desired
163 | )
164 | }
165 | }
166 |
167 | // MARK: - Real CPU Monitoring
168 | private func updateCPUInfo() {
169 | // Update total CPU from host_processor_info deltas
170 | totalCPUUsage = readSystemCPUPercentage()
171 |
172 | // Build process list with real per-process CPU and memory from proc_pidinfo
173 | let processes = getRealProcessList()
174 |
175 | // Get top CPU consuming processes
176 | cpuProcesses = Array(processes.sorted { $0.cpuUsage > $1.cpuUsage }.prefix(6))
177 | }
178 |
179 | // MARK: - System CPU via host_processor_info (delta-based)
180 | private func readSystemCPUPercentage() -> Double {
181 | var cpuInfo: processor_info_array_t?
182 | var cpuInfoCount: mach_msg_type_number_t = 0
183 | var numCPUU: natural_t = 0
184 |
185 | let result = host_processor_info(mach_host_self(),
186 | PROCESSOR_CPU_LOAD_INFO,
187 | &numCPUU,
188 | &cpuInfo,
189 | &cpuInfoCount)
190 | guard result == KERN_SUCCESS, let info = cpuInfo else {
191 | return totalCPUUsage // leave unchanged if failed
192 | }
193 | defer {
194 | let size = Int(cpuInfoCount) * MemoryLayout.size
195 | vm_deallocate(mach_task_self_, vm_address_t(bitPattern: info), vm_size_t(size))
196 | }
197 |
198 | var totalUser: UInt32 = 0
199 | var totalSystem: UInt32 = 0
200 | var totalNice: UInt32 = 0
201 | var totalIdle: UInt32 = 0
202 |
203 | let stride = Int(CPU_STATE_MAX)
204 | for cpu in 0.. 0 {
220 | let busy = Double(userDiff + sysDiff + niceDiff)
221 | let percent = (busy / totalTicks) * 100.0
222 | lastSystemCPUTicks = (totalUser, totalSystem, totalNice, totalIdle)
223 | return min(max(percent, 0), 100)
224 | }
225 | }
226 |
227 | lastSystemCPUTicks = (totalUser, totalSystem, totalNice, totalIdle)
228 | return totalCPUUsage // unchanged on first sample
229 | }
230 |
231 | // MARK: - Real Process List using kinfo_proc + proc_pidinfo
232 | private func getRealProcessList() -> [ProcessInfo] {
233 | var processes: [ProcessInfo] = []
234 | var buffer: UnsafeMutablePointer?
235 | var size: size_t = 0
236 |
237 | // Get process list size
238 | var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0]
239 | sysctl(&mib, u_int(mib.count), nil, &size, nil, 0)
240 |
241 | buffer = UnsafeMutablePointer.allocate(capacity: size / MemoryLayout.size)
242 | defer { buffer?.deallocate() }
243 |
244 | if sysctl(&mib, u_int(mib.count), buffer, &size, nil, 0) == 0 {
245 | let processCount = size / MemoryLayout.size
246 | let now = Date().timeIntervalSince1970
247 | let elapsed = lastCPUTimeStamp > 0 ? now - lastCPUTimeStamp : 0
248 | let elapsedNs = elapsed > 0 ? UInt64(elapsed * 1_000_000_000) : 0
249 |
250 | for i in 0.. 0 {
261 | let path = String(cString: pathBuffer)
262 | processName = URL(fileURLWithPath: path).lastPathComponent
263 | } else {
264 | // Fallback to kp_proc.p_comm if path not available
265 | withUnsafePointer(to: proc.kp_proc.p_comm) {
266 | processName = String(cString: UnsafeRawPointer($0).assumingMemoryBound(to: CChar.self))
267 | }
268 | }
269 | if processName.isEmpty { continue }
270 |
271 | // Read proc_taskinfo for the pid
272 | var tinfo = proc_taskinfo()
273 | let tinfoSize = MemoryLayout.stride
274 | let readSize = withUnsafeMutablePointer(to: &tinfo) { ptr in
275 | ptr.withMemoryRebound(to: UInt8.self, capacity: tinfoSize) { rawPtr in
276 | proc_pidinfo(pid, PROC_PIDTASKINFO, 0, rawPtr, Int32(tinfoSize))
277 | }
278 | }
279 | guard readSize == tinfoSize else {
280 | continue
281 | }
282 |
283 | // Memory (resident) in MB
284 | let memMB = Double(tinfo.pti_resident_size) / (1024.0 * 1024.0)
285 |
286 | // CPU: compute delta of total (user+system) time
287 | let totalNs = tinfo.pti_total_user + tinfo.pti_total_system
288 | let prevNs = lastPerProcessCPUTimeNs[pid] ?? totalNs
289 | let deltaNs = totalNs &- prevNs
290 | lastPerProcessCPUTimeNs[pid] = totalNs
291 |
292 | var cpuPercent: Double = 0.0
293 | if elapsedNs > 0 {
294 | // Normalize by elapsed time and core count
295 | let fraction = Double(deltaNs) / Double(elapsedNs)
296 | cpuPercent = (fraction / numCores) * 100.0
297 | }
298 |
299 | // Only include processes with noticeable usage (helps keep charts readable)
300 | if cpuPercent > 0.05 || memMB > 50 {
301 | let color = getColorForProcess(processName)
302 | processes.append(ProcessInfo(
303 | pid: pid,
304 | name: processName,
305 | cpuUsage: min(max(cpuPercent, 0), 100),
306 | memoryUsage: memMB,
307 | color: color
308 | ))
309 | }
310 | }
311 |
312 | lastCPUTimeStamp = now
313 | }
314 |
315 | return processes
316 | }
317 |
318 | // MARK: - Network parity with Activity Monitor
319 | private func updateNetworkInfo() {
320 | let currentStats = getPrimaryInterfaceCounters()
321 | let now = Date()
322 | let timeDiff = now.timeIntervalSince(lastNetworkUpdate)
323 |
324 | // If we have never recorded stats, seed previousNetworkStats and push a baseline sample
325 | if previousNetworkStats.rx == 0 && previousNetworkStats.tx == 0 {
326 | previousNetworkStats = currentStats
327 | lastNetworkUpdate = now
328 | // Seed one zero-rate sample so the UI can progress after next tick
329 | networkHistory.append(NetworkSpeed(downloadBytesPerSec: 0, uploadBytesPerSec: 0, timestamp: now))
330 | if networkHistory.count > 40 {
331 | networkHistory.removeFirst()
332 | }
333 | return
334 | }
335 |
336 | if timeDiff > 0 {
337 | let rxDiff = currentStats.rx > previousNetworkStats.rx ? currentStats.rx - previousNetworkStats.rx : 0
338 | let txDiff = currentStats.tx > previousNetworkStats.tx ? currentStats.tx - previousNetworkStats.tx : 0
339 |
340 | let downloadSpeed = Double(rxDiff) / timeDiff
341 | let uploadSpeed = Double(txDiff) / timeDiff
342 |
343 | let networkSpeed = NetworkSpeed(
344 | downloadBytesPerSec: downloadSpeed,
345 | uploadBytesPerSec: uploadSpeed,
346 | timestamp: now
347 | )
348 |
349 | networkHistory.append(networkSpeed)
350 | if networkHistory.count > 40 { // a bit more history for smoother chart
351 | networkHistory.removeFirst()
352 | }
353 | }
354 |
355 | previousNetworkStats = currentStats
356 | lastNetworkUpdate = now
357 | }
358 |
359 | // Resolve default-route interface by asking the kernel which local IP it would use to reach 8.8.8.8:53
360 | private func defaultRouteInterfaceName() -> String? {
361 | // 1) Create a UDP socket and "connect" to 8.8.8.8:53 (no packets sent)
362 | let sock = socket(AF_INET, SOCK_DGRAM, 0)
363 | if sock < 0 { return nil }
364 | defer { close(sock) }
365 |
366 | var addr = sockaddr_in()
367 | addr.sin_len = UInt8(MemoryLayout.size)
368 | addr.sin_family = sa_family_t(AF_INET)
369 | addr.sin_port = in_port_t(53).bigEndian
370 | inet_pton(AF_INET, "8.8.8.8", &addr.sin_addr)
371 |
372 | var dest = sockaddr()
373 | memcpy(&dest, &addr, MemoryLayout.size)
374 | let result = withUnsafePointer(to: &dest) {
375 | $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
376 | connect(sock, $0, socklen_t(MemoryLayout.size))
377 | }
378 | }
379 | if result < 0 {
380 | // Could not connect (offline), fall back to picking any UP|RUNNING en*
381 | return activeInterfaceNameFallback()
382 | }
383 |
384 | // 2) getsockname to learn the local IP chosen by kernel
385 | var localAddr = sockaddr_in()
386 | var len = socklen_t(MemoryLayout.size)
387 | let gsn = withUnsafeMutablePointer(to: &localAddr) {
388 | $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
389 | getsockname(sock, $0, &len)
390 | }
391 | }
392 | if gsn != 0 {
393 | return activeInterfaceNameFallback()
394 | }
395 |
396 | // 3) Map local IP to interface via getifaddrs
397 | var ifaddr: UnsafeMutablePointer?
398 | guard getifaddrs(&ifaddr) == 0, let first = ifaddr else {
399 | return activeInterfaceNameFallback()
400 | }
401 | defer { freeifaddrs(ifaddr) }
402 |
403 | var ptr: UnsafeMutablePointer? = first
404 | while let p = ptr?.pointee {
405 | if p.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
406 | let sa = UnsafeRawPointer(p.ifa_addr).assumingMemoryBound(to: sockaddr_in.self).pointee
407 | if sa.sin_addr.s_addr == localAddr.sin_addr.s_addr {
408 | return String(cString: p.ifa_name)
409 | }
410 | }
411 | ptr = p.ifa_next
412 | }
413 |
414 | return activeInterfaceNameFallback()
415 | }
416 |
417 | // Fallback: first UP|RUNNING en*, else any UP|RUNNING
418 | private func activeInterfaceNameFallback() -> String? {
419 | var ifaddr: UnsafeMutablePointer?
420 | guard getifaddrs(&ifaddr) == 0, let first = ifaddr else { return nil }
421 | defer { freeifaddrs(ifaddr) }
422 |
423 | var candidates: [String] = []
424 | var ptr: UnsafeMutablePointer? = first
425 | while let p = ptr?.pointee {
426 | let flags = Int32(p.ifa_flags)
427 | let isUp = (flags & IFF_UP) != 0
428 | let isRunning = (flags & IFF_RUNNING) != 0
429 | let name = String(cString: p.ifa_name)
430 | if isUp && isRunning {
431 | candidates.append(name)
432 | }
433 | ptr = p.ifa_next
434 | }
435 | if candidates.contains("en0") { return "en0" }
436 | if candidates.contains("en1") { return "en1" }
437 | if let en = candidates.first(where: { $0.hasPrefix("en") }) { return en }
438 | return candidates.first
439 | }
440 |
441 | // Read per-interface counters using sysctl NET_RT_IFLIST2 (if_msghdr2 -> if_data64)
442 | private func interfaceByteCounters(name: String) -> (rx: UInt64, tx: UInt64)? {
443 | // Build MIB: CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST2, 0
444 | var mib: [Int32] = [CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST2, 0]
445 | var len: size_t = 0
446 | // First call to get size
447 | if sysctl(&mib, u_int(mib.count), nil, &len, nil, 0) != 0 || len == 0 {
448 | return nil
449 | }
450 | let buf = UnsafeMutableRawPointer.allocate(byteCount: len, alignment: MemoryLayout.alignment)
451 | defer { buf.deallocate() }
452 | if sysctl(&mib, u_int(mib.count), buf, &len, nil, 0) != 0 {
453 | return nil
454 | }
455 |
456 | var rx: UInt64 = 0
457 | var tx: UInt64 = 0
458 |
459 | var next = buf
460 | let end = buf.advanced(by: len)
461 | while next < end {
462 | // All route messages are length-prefixed; read the header to know how far to advance
463 | let ifm = next.assumingMemoryBound(to: if_msghdr2.self).pointee
464 | let msgLen = Int(ifm.ifm_msglen)
465 |
466 | if ifm.ifm_type == UInt8(RTM_IFINFO2) {
467 | // The sockaddr_dl immediately follows the header
468 | let sdlPtr = next.advanced(by: MemoryLayout.size).assumingMemoryBound(to: sockaddr_dl.self)
469 | let sdl = sdlPtr.pointee
470 | let nameLen = Int(sdl.sdl_nlen)
471 |
472 | // The name bytes start at sdl_data within sockaddr_dl
473 | let sdlDataOffset = MemoryLayout.offset(of: \sockaddr_dl.sdl_data) ?? MemoryLayout.size
474 | let nameStart = UnsafeRawPointer(sdlPtr).advanced(by: sdlDataOffset)
475 | let nameBytes = nameStart.assumingMemoryBound(to: UInt8.self)
476 | let ifName = String(decoding: UnsafeBufferPointer(start: nameBytes, count: max(0, nameLen)), as: UTF8.self)
477 |
478 | if ifName == name {
479 | rx = ifm.ifm_data.ifi_ibytes
480 | tx = ifm.ifm_data.ifi_obytes
481 | break
482 | }
483 | }
484 |
485 | // Advance to the next message
486 | next = next.advanced(by: msgLen)
487 | }
488 |
489 | return (rx, tx)
490 | }
491 |
492 | private func getPrimaryInterfaceCounters() -> (rx: UInt64, tx: UInt64) {
493 | guard let iface = defaultRouteInterfaceName(),
494 | let counters = interfaceByteCounters(name: iface) else {
495 | // Fallback to zeros to avoid fake movement
496 | return (rx: 0, tx: 0)
497 | }
498 | return counters
499 | }
500 |
501 | // MARK: - Real Urgent Processes Detection
502 | private func updateUrgentProcesses() {
503 | let allProcesses = getRealProcessList()
504 | var urgent: [UrgentProcess] = []
505 |
506 | for process in allProcesses {
507 | var shouldAdd = false
508 | var issue = ""
509 | var priority = UrgentPriority.low
510 |
511 | if process.cpuUsage > 50 {
512 | issue = "High CPU usage (\(String(format: "%.1f", process.cpuUsage))%)"
513 | priority = .high
514 | shouldAdd = true
515 | } else if process.memoryUsage > 2048 {
516 | issue = "High memory usage (\(String(format: "%.0f", process.memoryUsage))MB)"
517 | priority = .medium
518 | shouldAdd = true
519 | } else if process.cpuUsage > 20 || process.memoryUsage > 1000 {
520 | issue = "Moderate resource usage"
521 | priority = .low
522 | shouldAdd = true
523 | }
524 |
525 | if shouldAdd && urgent.count < 5 {
526 | urgent.append(UrgentProcess(
527 | pid: process.pid,
528 | name: process.name,
529 | issue: issue,
530 | cpuUsage: process.cpuUsage,
531 | memoryUsage: process.memoryUsage,
532 | priority: priority
533 | ))
534 | }
535 | }
536 |
537 | urgentProcesses = urgent
538 | }
539 |
540 | // MARK: - Force Quit Process (REAL)
541 | func forceQuitProcess(pid: Int32) {
542 | let result = kill(pid, SIGTERM)
543 | if result != 0 {
544 | kill(pid, SIGKILL)
545 | }
546 |
547 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
548 | self.updateUrgentProcesses()
549 | }
550 | }
551 |
552 | private func getColorForProcess(_ processName: String) -> Color {
553 | if let existingColor = processColorMap[processName] {
554 | return existingColor
555 | }
556 |
557 | let colorIndex = processColorMap.count % appColors.count
558 | let color = appColors[colorIndex]
559 | processColorMap[processName] = color
560 | return color
561 | }
562 |
563 | deinit {
564 | updateTimer?.invalidate()
565 | }
566 | }
567 |
568 | // MARK: - System Data Models (keeping existing optimization task structure)
569 | struct OptimizationMetric: Identifiable {
570 | let id = UUID()
571 | let title: String
572 | let category: String
573 | let description: String
574 | var currentValue: Double
575 | var previousValue: Double
576 | var targetValue: Double
577 | var unit: String
578 | var status: MetricStatus
579 | var lastUpdated: Date
580 | }
581 |
582 | struct MetricDataPoint: Identifiable {
583 | let id = UUID()
584 | let timestamp: Date
585 | let value: Double
586 | }
587 |
588 | enum MetricStatus: String, CaseIterable {
589 | case excellent = "excellent"
590 | case good = "good"
591 | case warning = "warning"
592 | case critical = "critical"
593 |
594 | var color: Color {
595 | switch self {
596 | case .excellent: return Color(red: 0.10, green: 0.85, blue: 0.50)
597 | case .good: return Color(red: 0.20, green: 0.60, blue: 1.00)
598 | case .warning: return Color(red: 1.00, green: 0.55, blue: 0.00)
599 | case .critical: return Color(red: 1.00, green: 0.22, blue: 0.30)
600 | }
601 | }
602 |
603 | var icon: String {
604 | switch self {
605 | case .excellent: return "checkmark.circle.fill"
606 | case .good: return "arrow.up.circle.fill"
607 | case .warning: return "exclamationmark.triangle.fill"
608 | case .critical: return "xmark.circle.fill"
609 | }
610 | }
611 | }
612 |
613 | struct OptimizationTask: Identifiable {
614 | let id: String
615 | let title: String
616 | let description: String
617 | let category: String
618 | let command: String
619 | var isSelected: Bool = false
620 | }
621 |
622 | // MARK: - System Monitor (keeping optimization functionality)
623 | class SystemMonitor: ObservableObject {
624 | @Published var currentMetrics: [OptimizationMetric] = []
625 | @Published var isOptimizing = false
626 | @Published var optimizationTasks: [OptimizationTask] = []
627 | @Published var selectedTasks: Set = []
628 | @Published var realSystemMonitor = RealSystemMonitor()
629 |
630 | // Confirmation sheet
631 | @Published var showConfirmation = false
632 | @Published var lastRunTasks: [OptimizationTask] = []
633 | @Published var lastRunDate: Date?
634 |
635 | init() {
636 | initializeOptimizationTasks()
637 | setupMetrics()
638 | }
639 |
640 | private func setupMetrics() {
641 | currentMetrics = [
642 | OptimizationMetric(
643 | title: "Memory Usage",
644 | category: "System Resources",
645 | description: "Real-time RAM usage by applications",
646 | currentValue: 0,
647 | previousValue: 0,
648 | targetValue: 100,
649 | unit: "GB",
650 | status: .good,
651 | lastUpdated: Date()
652 | ),
653 | OptimizationMetric(
654 | title: "System Performance",
655 | category: "CPU & GPU",
656 | description: "Real-time processor usage",
657 | currentValue: 0,
658 | previousValue: 0,
659 | targetValue: 100,
660 | unit: "%",
661 | status: .good,
662 | lastUpdated: Date()
663 | ),
664 | OptimizationMetric(
665 | title: "Network Speed",
666 | category: "Connectivity",
667 | description: "Real-time network throughput (primary interface)",
668 | currentValue: 0,
669 | previousValue: 0,
670 | targetValue: 100,
671 | unit: "Mbps",
672 | status: .good,
673 | lastUpdated: Date()
674 | ),
675 | OptimizationMetric(
676 | title: "Urgent Attention",
677 | category: "Process Management",
678 | description: "Processes requiring attention",
679 | currentValue: 0,
680 | previousValue: 0,
681 | targetValue: 0,
682 | unit: " issues",
683 | status: .good,
684 | lastUpdated: Date()
685 | )
686 | ]
687 | }
688 |
689 | private func initializeOptimizationTasks() {
690 | optimizationTasks = [
691 | // Memory & Performance
692 | OptimizationTask(id: "purge_memory", title: "Purge inactive memory", description: "Free up inactive memory using purge command", category: "Memory & Performance", command: "sudo purge"),
693 | OptimizationTask(id: "clear_caches", title: "Clear system caches", description: "Clear user and system caches to free up space", category: "Memory & Performance", command: "sudo rm -rf ~/Library/Caches/* /Library/Caches/*"),
694 | OptimizationTask(id: "optimize_swap", title: "Optimize swap usage", description: "Configure swap settings for better performance", category: "Memory & Performance", command: "sudo purge"),
695 | OptimizationTask(id: "disable_spotlight", title: "Disable Spotlight indexing", description: "Turn off Spotlight indexing for better performance", category: "Memory & Performance", command: "sudo mdutil -i off /"),
696 | OptimizationTask(id: "reindex_spotlight", title: "Re-index Spotlight", description: "Rebuild Spotlight index for better search performance", category: "Memory & Performance", command: "sudo mdutil -E /"),
697 | OptimizationTask(id: "reduce_animations", title: "Reduce motion & animations", description: "Disable system animations for snappier performance", category: "Memory & Performance", command: "defaults write com.apple.universalaccess reduceMotion -bool true"),
698 |
699 | // System Tweaks
700 | OptimizationTask(id: "disable_dock_animation", title: "Disable Dock animations", description: "Remove Dock animations for faster response", category: "System Tweaks", command: "defaults write com.apple.dock autohide-time-modifier -int 0"),
701 | OptimizationTask(id: "disable_window_animations", title: "Disable window animations", description: "Remove window animations for snappier feel", category: "System Tweaks", command: "defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false"),
702 | OptimizationTask(id: "optimize_launchpad", title: "Optimize Launchpad", description: "Speed up Launchpad loading and animations", category: "System Tweaks", command: "defaults write com.apple.dock springboard-show-duration -int 0"),
703 | OptimizationTask(id: "disable_dashboard", title: "Disable Dashboard", description: "Turn off Dashboard to save memory", category: "System Tweaks", command: "defaults write com.apple.dashboard mcx-disabled -bool true"),
704 | OptimizationTask(id: "optimize_finder", title: "Optimize Finder", description: "Configure Finder for better performance", category: "System Tweaks", command: "defaults write com.apple.finder AppleShowAllFiles YES"),
705 | OptimizationTask(id: "disable_sudden_motion", title: "Disable Sudden Motion Sensor", description: "Turn off SMS for SSDs (M-Series Macs)", category: "System Tweaks", command: "sudo pmset -a sms 0"),
706 |
707 | // Network
708 | OptimizationTask(id: "flush_dns", title: "Flush DNS cache", description: "Clear DNS cache for faster lookups", category: "Network", command: "sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder"),
709 | OptimizationTask(id: "optimize_network", title: "Optimize network settings", description: "Configure network for better performance", category: "Network", command: "sudo sysctl -w net.inet.tcp.delayed_ack=0"),
710 | OptimizationTask(id: "disable_ipv6", title: "Disable IPv6", description: "Turn off IPv6 if not needed", category: "Network", command: "networksetup -setv6off Wi-Fi"),
711 | OptimizationTask(id: "optimize_wifi", title: "Optimize Wi-Fi", description: "Configure Wi-Fi settings for better performance", category: "Network", command: "sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport prefs DisconnectOnLogout=NO"),
712 |
713 | // Development
714 | OptimizationTask(id: "optimize_git", title: "Optimize Git performance", description: "Configure Git for better performance", category: "Development", command: "git config --global core.precomposeunicode true"),
715 | OptimizationTask(id: "optimize_homebrew", title: "Optimize Homebrew", description: "Clean and optimize Homebrew installation", category: "Development", command: "brew cleanup"),
716 | OptimizationTask(id: "optimize_node", title: "Optimize Node.js", description: "Clean Node.js and npm cache", category: "Development", command: "npm cache clean --force"),
717 | OptimizationTask(id: "optimize_python", title: "Optimize Python", description: "Clean Python cache and optimize", category: "Development", command: "python -m pip cache purge"),
718 | OptimizationTask(id: "optimize_docker", title: "Optimize Docker", description: "Clean Docker containers and images", category: "Development", command: "docker system prune -f"),
719 | OptimizationTask(id: "optimize_xcode", title: "Optimize Xcode", description: "Clean Xcode derived data and cache", category: "Development", command: "rm -rf ~/Library/Developer/Xcode/DerivedData/*"),
720 |
721 | // Advanced
722 | OptimizationTask(id: "rebuild_spotlight", title: "Rebuild Spotlight index", description: "Completely rebuild Spotlight search index", category: "Advanced", command: "sudo mdutil -i off / && sudo mdutil -i on /"),
723 | OptimizationTask(id: "reset_launchservices", title: "Reset Launch Services", description: "Fix 'Open With' menu problems", category: "Advanced", command: "sudo /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local"),
724 | OptimizationTask(id: "clear_font_cache", title: "Clear font cache", description: "Clear system font cache", category: "Advanced", command: "sudo atsutil databases -remove"),
725 | OptimizationTask(id: "optimize_ssd", title: "Optimize SSD settings", description: "Configure SSD-specific optimizations", category: "Advanced", command: "sudo trimforce enable"),
726 | OptimizationTask(id: "disable_crash_reporter", title: "Disable crash reporter", description: "Turn off automatic crash reporting", category: "Advanced", command: "defaults write com.apple.CrashReporter DialogType none"),
727 | OptimizationTask(id: "optimize_metal", title: "Optimize Metal performance", description: "Configure Metal graphics performance", category: "Advanced", command: "defaults write com.apple.CoreGraphics CGDirectDisplayID -bool true")
728 | ]
729 | }
730 |
731 | func runOptimization() {
732 | guard !selectedTasks.isEmpty else { return }
733 |
734 | isOptimizing = true
735 | lastRunTasks = optimizationTasks.filter { selectedTasks.contains($0.id) }
736 | lastRunDate = Date()
737 |
738 | DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
739 | self.isOptimizing = false
740 | self.showConfirmation = true
741 | }
742 | }
743 |
744 | func toggleTask(_ taskId: String) {
745 | if selectedTasks.contains(taskId) {
746 | selectedTasks.remove(taskId)
747 | } else {
748 | selectedTasks.insert(taskId)
749 | }
750 | }
751 |
752 | func getTasksByCategory(_ category: String) -> [OptimizationTask] {
753 | return optimizationTasks.filter { $0.category == category }
754 | }
755 |
756 | var categories: [String] {
757 | return Array(Set(optimizationTasks.map { $0.category })).sorted()
758 | }
759 | }
760 |
761 | // MARK: - Glass Card Component
762 | struct GlassCardView: View {
763 | let content: Content
764 |
765 | init(@ViewBuilder content: () -> Content) {
766 | self.content = content()
767 | }
768 |
769 | var body: some View {
770 | content
771 | .padding(20)
772 | .background(
773 | RoundedRectangle(cornerRadius: 16)
774 | .fill(.ultraThinMaterial)
775 | .overlay(
776 | RoundedRectangle(cornerRadius: 16)
777 | .stroke(Color.white.opacity(0.28), lineWidth: 1.2)
778 | )
779 | .shadow(color: Color.black.opacity(0.25), radius: 14, y: 7)
780 | )
781 | }
782 | }
783 |
784 | // MARK: - Real Memory Usage Chart
785 | struct RealMemoryUsageChart: View {
786 | @ObservedObject var realMonitor: RealSystemMonitor
787 |
788 | var body: some View {
789 | VStack(spacing: 8) {
790 | Chart {
791 | ForEach(Array(realMonitor.memoryInfo.appMemoryUsage.enumerated()), id: \.element.id) { _, app in
792 | BarMark(
793 | x: .value("App", app.name),
794 | y: .value("Memory", app.memoryUsage)
795 | )
796 | .foregroundStyle(app.color)
797 | .cornerRadius(4)
798 | }
799 | }
800 | .chartYAxis {
801 | AxisMarks(position: .leading) { value in
802 | AxisGridLine(stroke: StrokeStyle(lineWidth: 0.6))
803 | .foregroundStyle(Color.white.opacity(0.25))
804 | AxisValueLabel() {
805 | if let mb = value.as(Double.self) {
806 | Text("\(Int(mb))MB")
807 | .font(.caption2)
808 | .foregroundColor(.secondary)
809 | }
810 | }
811 | }
812 | }
813 | .chartXAxis(.hidden)
814 | .frame(height: 80)
815 |
816 | LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 4) {
817 | ForEach(realMonitor.memoryInfo.appMemoryUsage) { app in
818 | HStack(spacing: 4) {
819 | Circle()
820 | .fill(app.color)
821 | .frame(width: 8, height: 8)
822 | Text(app.name)
823 | .font(.caption2)
824 | .foregroundColor(.secondary)
825 | .lineLimit(1)
826 | }
827 | }
828 | }
829 | }
830 | }
831 | }
832 |
833 | // MARK: - Real CPU Usage Chart
834 | struct RealCPUUsageChart: View {
835 | @ObservedObject var realMonitor: RealSystemMonitor
836 |
837 | var body: some View {
838 | VStack(spacing: 8) {
839 | Chart {
840 | ForEach(realMonitor.cpuProcesses) { process in
841 | BarMark(
842 | x: .value("Process", process.name),
843 | y: .value("CPU", process.cpuUsage)
844 | )
845 | .foregroundStyle(process.color)
846 | .cornerRadius(4)
847 | }
848 | }
849 | .chartYAxis {
850 | AxisMarks(position: .leading) { value in
851 | AxisGridLine(stroke: StrokeStyle(lineWidth: 0.6))
852 | .foregroundStyle(Color.white.opacity(0.25))
853 | AxisValueLabel() {
854 | if let cpu = value.as(Double.self) {
855 | Text("\(Int(cpu))%")
856 | .font(.caption2)
857 | .foregroundColor(.secondary)
858 | }
859 | }
860 | }
861 | }
862 | .chartXAxis(.hidden)
863 | .frame(height: 80)
864 |
865 | LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 4) {
866 | ForEach(realMonitor.cpuProcesses) { process in
867 | HStack(spacing: 4) {
868 | Circle()
869 | .fill(process.color)
870 | .frame(width: 8, height: 8)
871 | Text(process.name)
872 | .font(.caption2)
873 | .foregroundColor(.secondary)
874 | .lineLimit(1)
875 | }
876 | }
877 | }
878 | }
879 | }
880 | }
881 |
882 | // MARK: - Real Network Speed Chart
883 | struct RealNetworkSpeedChart: View {
884 | @ObservedObject var realMonitor: RealSystemMonitor
885 |
886 | var body: some View {
887 | Chart {
888 | ForEach(realMonitor.networkHistory, id: \.timestamp) { speed in
889 | LineMark(
890 | x: .value("Time", speed.timestamp),
891 | y: .value("Download", speed.downloadMbps)
892 | )
893 | .foregroundStyle(Color(red: 0.20, green: 0.60, blue: 1.00))
894 | .lineStyle(StrokeStyle(lineWidth: 2))
895 |
896 | LineMark(
897 | x: .value("Time", speed.timestamp),
898 | y: .value("Upload", speed.uploadMbps)
899 | )
900 | .foregroundStyle(Color(red: 0.10, green: 0.85, blue: 0.50))
901 | .lineStyle(StrokeStyle(lineWidth: 2))
902 | }
903 | }
904 | .chartXAxis(.hidden)
905 | .chartYAxis {
906 | AxisMarks(position: .leading) { value in
907 | AxisGridLine(stroke: StrokeStyle(lineWidth: 0.6))
908 | .foregroundStyle(Color.white.opacity(0.25))
909 | AxisValueLabel() {
910 | if let mbps = value.as(Double.self) {
911 | Text("\(String(format: "%.2f", mbps))")
912 | .font(.caption2)
913 | .foregroundColor(.secondary)
914 | }
915 | }
916 | }
917 | }
918 | .frame(height: 60)
919 | .overlay(alignment: .bottomTrailing) {
920 | HStack(spacing: 12) {
921 | HStack(spacing: 4) {
922 | Circle().fill(Color(red: 0.20, green: 0.60, blue: 1.00)).frame(width: 8, height: 8)
923 | Text("Down")
924 | .font(.caption2)
925 | .foregroundColor(.secondary)
926 | }
927 | HStack(spacing: 4) {
928 | Circle().fill(Color(red: 0.10, green: 0.85, blue: 0.50)).frame(width: 8, height: 8)
929 | Text("Up")
930 | .font(.caption2)
931 | .foregroundColor(.secondary)
932 | }
933 | }
934 | }
935 | }
936 | }
937 |
938 | // MARK: - Real Urgent Processes List (with working Force Quit)
939 | struct RealUrgentProcessesList: View {
940 | @ObservedObject var realMonitor: RealSystemMonitor
941 |
942 | var body: some View {
943 | VStack(alignment: .leading, spacing: 8) {
944 | if realMonitor.urgentProcesses.isEmpty {
945 | Text("No urgent issues detected")
946 | .font(.caption)
947 | .foregroundColor(.green)
948 | .frame(maxWidth: .infinity, alignment: .center)
949 | .padding()
950 | } else {
951 | ForEach(realMonitor.urgentProcesses) { process in
952 | HStack(spacing: 12) {
953 | Circle()
954 | .fill(process.priority.color)
955 | .frame(width: 12, height: 12)
956 |
957 | VStack(alignment: .leading, spacing: 2) {
958 | Text(process.name)
959 | .font(.caption)
960 | .fontWeight(.medium)
961 | .foregroundColor(.primary)
962 |
963 | Text(process.issue)
964 | .font(.caption2)
965 | .foregroundColor(.secondary)
966 | }
967 |
968 | Spacer()
969 |
970 | Button("Force Quit") {
971 | realMonitor.forceQuitProcess(pid: process.pid)
972 | }
973 | .font(.caption2)
974 | .foregroundColor(.white)
975 | .padding(.horizontal, 8)
976 | .padding(.vertical, 4)
977 | .background(process.priority.color)
978 | .cornerRadius(6)
979 | }
980 | .padding(.horizontal, 8)
981 | .padding(.vertical, 6)
982 | .background(Color.black.opacity(0.25))
983 | .cornerRadius(8)
984 | }
985 | }
986 | }
987 | }
988 | }
989 |
990 | // MARK: - Enhanced Metric Card with Real System Data
991 | struct MetricCardView: View {
992 | let metric: OptimizationMetric
993 | @ObservedObject var realSystemMonitor: RealSystemMonitor
994 | @State private var isAnimating = false
995 |
996 | // New: popover for the top-right badge
997 | @State private var showDetails = false
998 |
999 | var body: some View {
1000 | GlassCardView {
1001 | VStack(alignment: .leading, spacing: 16) {
1002 | HStack {
1003 | VStack(alignment: .leading, spacing: 4) {
1004 | Text(metric.title)
1005 | .font(.system(.title2, design: .rounded, weight: .bold))
1006 | .foregroundStyle(
1007 | LinearGradient(
1008 | colors: [Color.white, Color.white.opacity(0.92)],
1009 | startPoint: .leading,
1010 | endPoint: .trailing
1011 | )
1012 | )
1013 |
1014 | Text(metric.category)
1015 | .font(.system(.subheadline, design: .rounded, weight: .medium))
1016 | .foregroundColor(.secondary)
1017 | }
1018 |
1019 | Spacer()
1020 |
1021 | // Make the badge actionable
1022 | Button {
1023 | showDetails.toggle()
1024 | } label: {
1025 | ZStack {
1026 | Circle()
1027 | .fill(getStatusColor().opacity(0.22))
1028 | .frame(width: 40, height: 40)
1029 |
1030 | Image(systemName: getStatusIcon())
1031 | .font(.system(.subheadline, weight: .bold))
1032 | .foregroundColor(getStatusColor())
1033 | }
1034 | }
1035 | .buttonStyle(.plain)
1036 | .popover(isPresented: $showDetails) {
1037 | detailsView
1038 | .padding(16)
1039 | .frame(minWidth: 260)
1040 | }
1041 | }
1042 |
1043 | VStack(alignment: .leading, spacing: 12) {
1044 | HStack {
1045 | switch metric.title {
1046 | case "Memory Usage":
1047 | Text("Used: \(String(format: "%.1f", realSystemMonitor.memoryInfo.usedMemory))GB / \(String(format: "%.1f", realSystemMonitor.memoryInfo.totalMemory))GB")
1048 | .font(.system(.headline, design: .monospaced, weight: .bold))
1049 | .foregroundColor(.primary)
1050 |
1051 | case "System Performance":
1052 | Text("CPU Usage: \(String(format: "%.1f", realSystemMonitor.totalCPUUsage))%")
1053 | .font(.system(.headline, design: .monospaced, weight: .bold))
1054 | .foregroundColor(.primary)
1055 |
1056 | case "Network Speed":
1057 | if let latest = realSystemMonitor.networkHistory.last, realSystemMonitor.networkHistory.count > 1 {
1058 | VStack(alignment: .leading, spacing: 2) {
1059 | Text("↓ \(String(format: "%.2f", latest.downloadMbps)) Mbps")
1060 | .font(.system(.subheadline, design: .monospaced, weight: .bold))
1061 | .foregroundColor(Color(red: 0.20, green: 0.60, blue: 1.00))
1062 | Text("↑ \(String(format: "%.2f", latest.uploadMbps)) Mbps")
1063 | .font(.system(.subheadline, design: .monospaced, weight: .bold))
1064 | .foregroundColor(Color(red: 0.10, green: 0.85, blue: 0.50))
1065 | }
1066 | } else {
1067 | Text("Measuring...")
1068 | .font(.system(.headline, design: .rounded))
1069 | .foregroundColor(.secondary)
1070 | }
1071 |
1072 | case "Urgent Attention":
1073 | Text("\(realSystemMonitor.urgentProcesses.count) issues need attention")
1074 | .font(.system(.headline, design: .rounded, weight: .bold))
1075 | .foregroundColor(getStatusColor())
1076 |
1077 | default:
1078 | Text("Monitoring...")
1079 | .font(.system(.headline, design: .monospaced, weight: .bold))
1080 | .foregroundColor(.primary)
1081 | }
1082 |
1083 | Spacer()
1084 | }
1085 |
1086 | // Real system data visualization
1087 | switch metric.title {
1088 | case "Memory Usage":
1089 | RealMemoryUsageChart(realMonitor: realSystemMonitor)
1090 |
1091 | case "System Performance":
1092 | RealCPUUsageChart(realMonitor: realSystemMonitor)
1093 |
1094 | case "Network Speed":
1095 | RealNetworkSpeedChart(realMonitor: realSystemMonitor)
1096 |
1097 | case "Urgent Attention":
1098 | RealUrgentProcessesList(realMonitor: realSystemMonitor)
1099 |
1100 | default:
1101 | EmptyView()
1102 | }
1103 | }
1104 | }
1105 | }
1106 | .frame(minWidth: 320, maxWidth: .infinity, minHeight: 280)
1107 | .scaleEffect(isAnimating ? 1.0 : 0.95)
1108 | .opacity(isAnimating ? 1.0 : 0.0)
1109 | .onAppear {
1110 | withAnimation(.easeInOut(duration: 0.8)) {
1111 | isAnimating = true
1112 | }
1113 | }
1114 | }
1115 |
1116 | private var detailsView: some View {
1117 | VStack(alignment: .leading, spacing: 10) {
1118 | Text(metric.title)
1119 | .font(.headline)
1120 | switch metric.title {
1121 | case "Memory Usage":
1122 | if realSystemMonitor.memoryInfo.appMemoryUsage.isEmpty {
1123 | Text("Collecting memory data…")
1124 | .foregroundColor(.secondary)
1125 | } else {
1126 | ForEach(realSystemMonitor.memoryInfo.appMemoryUsage) { p in
1127 | HStack {
1128 | Circle().fill(p.color).frame(width: 6, height: 6)
1129 | Text(p.name).lineLimit(1)
1130 | Spacer()
1131 | Text("\(Int(p.memoryUsage)) MB")
1132 | .font(.system(.caption, design: .monospaced))
1133 | .foregroundColor(.secondary)
1134 | }
1135 | }
1136 | }
1137 | case "System Performance":
1138 | if realSystemMonitor.cpuProcesses.isEmpty {
1139 | Text("Collecting CPU data…").foregroundColor(.secondary)
1140 | } else {
1141 | ForEach(realSystemMonitor.cpuProcesses) { p in
1142 | HStack {
1143 | Circle().fill(p.color).frame(width: 6, height: 6)
1144 | Text(p.name).lineLimit(1)
1145 | Spacer()
1146 | Text("\(String(format: "%.1f", p.cpuUsage))%")
1147 | .font(.system(.caption, design: .monospaced))
1148 | .foregroundColor(.secondary)
1149 | }
1150 | }
1151 | }
1152 | case "Network Speed":
1153 | if let s = realSystemMonitor.networkHistory.last, realSystemMonitor.networkHistory.count > 1 {
1154 | Text("Down: \(String(format: "%.2f", s.downloadMbps)) Mbps")
1155 | Text("Up: \(String(format: "%.2f", s.uploadMbps)) Mbps")
1156 | } else {
1157 | Text("Measuring…").foregroundColor(.secondary)
1158 | }
1159 | case "Urgent Attention":
1160 | Button {
1161 | realSystemMonitor.forceQuitProcess(pid: -1) // harmless refresh
1162 | } label: {
1163 | Label("Refresh List", systemImage: "arrow.clockwise")
1164 | }
1165 | default:
1166 | Text("No actions available.")
1167 | }
1168 | }
1169 | .frame(maxWidth: .infinity, alignment: .leading)
1170 | }
1171 |
1172 | private func getStatusColor() -> Color {
1173 | switch metric.title {
1174 | case "Urgent Attention":
1175 | let count = realSystemMonitor.urgentProcesses.count
1176 | if count == 0 { return Color(red: 0.10, green: 0.85, blue: 0.50) }
1177 | else if count <= 2 { return Color(red: 1.00, green: 0.84, blue: 0.00) }
1178 | else if count <= 4 { return Color(red: 1.00, green: 0.55, blue: 0.00) }
1179 | else { return Color(red: 1.00, green: 0.22, blue: 0.30) }
1180 | case "Memory Usage":
1181 | let total = max(realSystemMonitor.memoryInfo.totalMemory, 0.0001)
1182 | let percentUsed = (realSystemMonitor.memoryInfo.usedMemory / total) * 100
1183 | if percentUsed < 60 { return Color(red: 0.10, green: 0.85, blue: 0.50) }
1184 | else if percentUsed < 80 { return Color(red: 1.00, green: 0.84, blue: 0.00) }
1185 | else { return Color(red: 1.00, green: 0.22, blue: 0.30) }
1186 | default:
1187 | return Color(red: 0.20, green: 0.60, blue: 1.00)
1188 | }
1189 | }
1190 |
1191 | private func getStatusIcon() -> String {
1192 | let color = getStatusColor()
1193 | switch color {
1194 | case Color(red: 0.10, green: 0.85, blue: 0.50): return "checkmark.circle.fill"
1195 | case Color(red: 1.00, green: 0.84, blue: 0.00): return "exclamationmark.triangle.fill"
1196 | case Color(red: 1.00, green: 0.55, blue: 0.00): return "exclamationmark.triangle.fill"
1197 | case Color(red: 1.00, green: 0.22, blue: 0.30): return "xmark.circle.fill"
1198 | default: return "info.circle.fill"
1199 | }
1200 | }
1201 | }
1202 |
1203 | // MARK: - Clickable Optimization Task Row
1204 | struct OptimizationTaskRow: View {
1205 | let task: OptimizationTask
1206 | let isSelected: Bool
1207 | let onToggle: () -> Void
1208 |
1209 | var body: some View {
1210 | Button(action: onToggle) {
1211 | HStack(spacing: 16) {
1212 | ZStack {
1213 | RoundedRectangle(cornerRadius: 8)
1214 | .fill(isSelected ? Color(red: 0.20, green: 0.60, blue: 1.00) : Color.clear)
1215 | .stroke(Color(red: 0.20, green: 0.60, blue: 1.00), lineWidth: 2)
1216 | .frame(width: 24, height: 24)
1217 |
1218 | if isSelected {
1219 | Image(systemName: "checkmark")
1220 | .font(.system(.subheadline, weight: .bold))
1221 | .foregroundColor(.white)
1222 | }
1223 | }
1224 |
1225 | VStack(alignment: .leading, spacing: 6) {
1226 | Text(task.title)
1227 | .font(.system(.title3, design: .rounded, weight: .semibold))
1228 | .foregroundStyle(
1229 | LinearGradient(
1230 | colors: [Color.white, Color.white.opacity(0.92)],
1231 | startPoint: .leading,
1232 | endPoint: .trailing
1233 | )
1234 | )
1235 |
1236 | Text(task.description)
1237 | .font(.system(.subheadline, design: .rounded))
1238 | .foregroundColor(.secondary)
1239 | .multilineTextAlignment(.leading)
1240 | }
1241 |
1242 | Spacer()
1243 | }
1244 | .padding(.horizontal, 20)
1245 | .padding(.vertical, 16)
1246 | .background(
1247 | RoundedRectangle(cornerRadius: 12)
1248 | .fill(isSelected ? Color(red: 0.20, green: 0.60, blue: 1.00).opacity(0.18) : Color.clear)
1249 | .stroke(isSelected ? Color(red: 0.20, green: 0.60, blue: 1.00).opacity(0.45) : Color.clear, lineWidth: 2)
1250 | )
1251 | .contentShape(Rectangle())
1252 | }
1253 | .buttonStyle(.plain)
1254 | }
1255 | }
1256 |
1257 | // MARK: - Enhanced Optimization Category View
1258 | struct OptimizationCategoryView: View {
1259 | let category: String
1260 | @ObservedObject var systemMonitor: SystemMonitor
1261 |
1262 | var body: some View {
1263 | ZStack {
1264 | LinearGradient(
1265 | colors: [
1266 | Color(red: 0.04, green: 0.05, blue: 0.16),
1267 | Color(red: 0.10, green: 0.05, blue: 0.22),
1268 | Color(red: 0.18, green: 0.12, blue: 0.28)
1269 | ],
1270 | startPoint: .topLeading,
1271 | endPoint: .bottomTrailing
1272 | )
1273 | .ignoresSafeArea()
1274 |
1275 | ScrollView {
1276 | VStack(spacing: 24) {
1277 | HStack {
1278 | Text(category)
1279 | .font(.system(.largeTitle, design: .rounded, weight: .bold))
1280 | .foregroundStyle(
1281 | LinearGradient(
1282 | colors: [Color.white, Color.white.opacity(0.86)],
1283 | startPoint: .leading,
1284 | endPoint: .trailing
1285 | )
1286 | )
1287 |
1288 | Spacer()
1289 |
1290 | Text("\(systemMonitor.getTasksByCategory(category).filter { systemMonitor.selectedTasks.contains($0.id) }.count) selected")
1291 | .font(.system(.headline, design: .rounded, weight: .medium))
1292 | .foregroundColor(.secondary)
1293 | }
1294 | .padding(.horizontal, 24)
1295 | .padding(.top, 24)
1296 |
1297 | GlassCardView {
1298 | VStack(spacing: 12) {
1299 | ForEach(systemMonitor.getTasksByCategory(category)) { task in
1300 | OptimizationTaskRow(
1301 | task: task,
1302 | isSelected: systemMonitor.selectedTasks.contains(task.id)
1303 | ) {
1304 | systemMonitor.toggleTask(task.id)
1305 | }
1306 |
1307 | if task.id != systemMonitor.getTasksByCategory(category).last?.id {
1308 | Divider()
1309 | .padding(.horizontal, 20)
1310 | }
1311 | }
1312 | }
1313 | }
1314 | .padding(.horizontal, 24)
1315 |
1316 | Spacer(minLength: 100)
1317 | }
1318 | }
1319 | }
1320 | }
1321 | }
1322 |
1323 | // MARK: - Enhanced Dashboard View
1324 | struct DashboardView: View {
1325 | @ObservedObject var systemMonitor: SystemMonitor
1326 |
1327 | var body: some View {
1328 | ZStack {
1329 | LinearGradient(
1330 | colors: [
1331 | Color(red: 0.04, green: 0.05, blue: 0.16),
1332 | Color(red: 0.10, green: 0.05, blue: 0.22),
1333 | Color(red: 0.18, green: 0.12, blue: 0.28)
1334 | ],
1335 | startPoint: .topLeading,
1336 | endPoint: .bottomTrailing
1337 | )
1338 | .ignoresSafeArea()
1339 |
1340 | ScrollView(showsIndicators: false) {
1341 | VStack(spacing: 32) {
1342 | VStack(spacing: 16) {
1343 | Text("OptiMac by VonKleistL")
1344 | .font(.system(.largeTitle, design: .rounded, weight: .heavy))
1345 | .foregroundStyle(
1346 | LinearGradient(
1347 | colors: [
1348 | Color.white,
1349 | Color(red: 0.80, green: 0.92, blue: 1.00),
1350 | Color.white.opacity(0.92)
1351 | ],
1352 | startPoint: .leading,
1353 | endPoint: .trailing
1354 | )
1355 | )
1356 |
1357 | Text("M-Series Performance Suite • Real-Time System Monitor")
1358 | .font(.system(.title2, design: .rounded, weight: .medium))
1359 | .foregroundStyle(
1360 | LinearGradient(
1361 | colors: [Color.white.opacity(0.88), Color.white.opacity(0.66)],
1362 | startPoint: .leading,
1363 | endPoint: .trailing
1364 | )
1365 | )
1366 | }
1367 | .padding(.top, 24)
1368 |
1369 | GlassCardView {
1370 | HStack {
1371 | VStack(alignment: .leading, spacing: 8) {
1372 | Text("Quick Optimization")
1373 | .font(.system(.title2, design: .rounded, weight: .bold))
1374 | .foregroundStyle(
1375 | LinearGradient(
1376 | colors: [Color.white, Color.white.opacity(0.92)],
1377 | startPoint: .leading,
1378 | endPoint: .trailing
1379 | )
1380 | )
1381 |
1382 | Text("\(systemMonitor.selectedTasks.count) optimizations selected")
1383 | .font(.system(.subheadline, design: .rounded, weight: .medium))
1384 | .foregroundColor(.secondary)
1385 | }
1386 |
1387 | Spacer()
1388 |
1389 | Button(action: {
1390 | systemMonitor.runOptimization()
1391 | }) {
1392 | HStack(spacing: 10) {
1393 | if systemMonitor.isOptimizing {
1394 | ProgressView()
1395 | .progressViewStyle(CircularProgressViewStyle(tint: .white))
1396 | .scaleEffect(0.9)
1397 | } else {
1398 | Image(systemName: "bolt.fill")
1399 | .font(.system(.subheadline, weight: .bold))
1400 | }
1401 |
1402 | Text(systemMonitor.isOptimizing ? "Optimizing..." : "Run Boost")
1403 | .font(.system(.headline, design: .rounded, weight: .bold))
1404 | }
1405 | .foregroundColor(.white)
1406 | .padding(.horizontal, 24)
1407 | .padding(.vertical, 14)
1408 | .background(
1409 | LinearGradient(
1410 | colors: [Color(red: 0.20, green: 0.60, blue: 1.00), Color(red: 0.60, green: 0.40, blue: 1.00)],
1411 | startPoint: .leading,
1412 | endPoint: .trailing
1413 | )
1414 | )
1415 | .clipShape(Capsule())
1416 | .shadow(color: Color(red: 0.20, green: 0.60, blue: 1.00).opacity(0.35), radius: 10, y: 5)
1417 | }
1418 | .buttonStyle(.plain)
1419 | .disabled(systemMonitor.isOptimizing || systemMonitor.selectedTasks.isEmpty)
1420 | }
1421 | }
1422 |
1423 | LazyVGrid(columns: [
1424 | GridItem(.flexible(), spacing: 20),
1425 | GridItem(.flexible(), spacing: 20)
1426 | ], spacing: 20) {
1427 | ForEach(systemMonitor.currentMetrics) { metric in
1428 | MetricCardView(metric: metric, realSystemMonitor: systemMonitor.realSystemMonitor)
1429 | }
1430 | }
1431 |
1432 | Spacer(minLength: 50)
1433 | }
1434 | .padding(.horizontal, 24)
1435 | }
1436 | }
1437 | // Confirmation sheet after optimizations complete
1438 | .sheet(isPresented: $systemMonitor.showConfirmation) {
1439 | VStack(alignment: .leading, spacing: 16) {
1440 | HStack {
1441 | Image(systemName: "checkmark.seal.fill")
1442 | .foregroundColor(.green)
1443 | Text("Optimizations Completed")
1444 | .font(.title2).bold()
1445 | }
1446 | if let date = systemMonitor.lastRunDate {
1447 | Text("Finished at \(date.formatted(date: .abbreviated, time: .standard))")
1448 | .foregroundColor(.secondary)
1449 | }
1450 | if systemMonitor.lastRunTasks.isEmpty {
1451 | Text("No tasks were executed.")
1452 | } else {
1453 | Text("Tasks run:")
1454 | .font(.headline)
1455 | ScrollView {
1456 | VStack(alignment: .leading, spacing: 8) {
1457 | ForEach(systemMonitor.lastRunTasks) { task in
1458 | HStack {
1459 | Image(systemName: "bolt.fill").foregroundColor(Color(red: 0.20, green: 0.60, blue: 1.00))
1460 | Text(task.title)
1461 | Spacer()
1462 | }
1463 | }
1464 | }
1465 | }
1466 | .frame(minHeight: 120, maxHeight: 240)
1467 | }
1468 | HStack {
1469 | Spacer()
1470 | Button("Done") { systemMonitor.showConfirmation = false }
1471 | .keyboardShortcut(.defaultAction)
1472 | }
1473 | }
1474 | .padding(24)
1475 | .frame(minWidth: 420)
1476 | }
1477 | }
1478 | }
1479 |
1480 | // MARK: - Main Content View
1481 | struct ContentView: View {
1482 | // Injected shared SystemMonitor instead of owning our own
1483 | @ObservedObject var systemMonitor: SystemMonitor
1484 |
1485 | init(systemMonitor: SystemMonitor) {
1486 | self.systemMonitor = systemMonitor
1487 | }
1488 |
1489 | var body: some View {
1490 | TabView {
1491 | DashboardView(systemMonitor: systemMonitor)
1492 | .tabItem {
1493 | Image(systemName: "chart.bar.fill")
1494 | Text("Dashboard")
1495 | }
1496 |
1497 | OptimizationCategoryView(category: "Memory & Performance", systemMonitor: systemMonitor)
1498 | .tabItem {
1499 | Image(systemName: "memorychip.fill")
1500 | Text("Memory")
1501 | }
1502 |
1503 | OptimizationCategoryView(category: "System Tweaks", systemMonitor: systemMonitor)
1504 | .tabItem {
1505 | Image(systemName: "gearshape.2.fill")
1506 | Text("System")
1507 | }
1508 |
1509 | OptimizationCategoryView(category: "Network", systemMonitor: systemMonitor)
1510 | .tabItem {
1511 | Image(systemName: "wifi")
1512 | Text("Network")
1513 | }
1514 |
1515 | OptimizationCategoryView(category: "Development", systemMonitor: systemMonitor)
1516 | .tabItem {
1517 | Image(systemName: "hammer.fill")
1518 | Text("Development")
1519 | }
1520 |
1521 | OptimizationCategoryView(category: "Advanced", systemMonitor: systemMonitor)
1522 | .tabItem {
1523 | Image(systemName: "cpu.fill")
1524 | Text("Advanced")
1525 | }
1526 | }
1527 | .preferredColorScheme(.dark)
1528 | .accentColor(Color(red: 0.20, green: 0.60, blue: 1.00))
1529 | }
1530 | }
1531 |
1532 | #Preview {
1533 | ContentView(systemMonitor: SystemMonitor())
1534 | .frame(width: 1200, height: 800)
1535 | }
1536 |
--------------------------------------------------------------------------------