From ab13b91d20ca16d8465a8638c833cfca7fda6c5c Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Wed, 13 Aug 2025 23:37:44 +0530 Subject: [PATCH 1/2] Updates WOrking --- DynamicIsland/ContentView.swift | 10 ++- .../components/Notch/NotchStatsView.swift | 72 +++++++++++++++---- DynamicIsland/managers/StatsManager.swift | 8 +-- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/DynamicIsland/ContentView.swift b/DynamicIsland/ContentView.swift index d194707..8760a57 100644 --- a/DynamicIsland/ContentView.swift +++ b/DynamicIsland/ContentView.swift @@ -125,7 +125,15 @@ struct ContentView: View { // Only close if mouse leaves and the notch is open and no popovers are active if !hovering && vm.notchState == .open && !vm.isBatteryPopoverActive { - vm.close() + // Add slight delay for stats tab to prevent accidental closure during layout changes + let delay: Double = (coordinator.currentView == .stats) ? 0.2 : 0.0 + + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + // Double-check conditions after delay + if !isHovering && vm.notchState == .open && !vm.isBatteryPopoverActive { + vm.close() + } + } } } .onTapGesture { diff --git a/DynamicIsland/components/Notch/NotchStatsView.swift b/DynamicIsland/components/Notch/NotchStatsView.swift index 6deac34..94e81e5 100644 --- a/DynamicIsland/components/Notch/NotchStatsView.swift +++ b/DynamicIsland/components/Notch/NotchStatsView.swift @@ -118,25 +118,71 @@ struct NotchStatsView: View { return graphs } - // Simplified and more consistent layout system + // Smart grid layout system for different graph counts @ViewBuilder var statsGridLayout: some View { let graphCount = availableGraphs.count - // Use LazyVGrid for all cases - more predictable layout behavior - LazyVGrid( - columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: min(graphCount, 3)), - spacing: 12 - ) { - ForEach(0.. 0.1 && previousNetworkStats.bytesIn > 0 && previousNetworkStats.bytesOut > 0 { + // Only calculate speeds if we have a reasonable time interval and this isn't the first run + if timeInterval > 0.1 && (previousNetworkStats.bytesIn > 0 || previousNetworkStats.bytesOut > 0) { let bytesDownloaded = currentNetworkStats.bytesIn > previousNetworkStats.bytesIn ? currentNetworkStats.bytesIn - previousNetworkStats.bytesIn : 0 let bytesUploaded = currentNetworkStats.bytesOut > previousNetworkStats.bytesOut ? @@ -136,8 +136,8 @@ class StatsManager: ObservableObject { var readSpeed: Double = 0.0 var writeSpeed: Double = 0.0 - // Only calculate speeds if we have a reasonable time interval and previous data - if timeInterval > 0.1 && previousDiskStats.bytesRead > 0 && previousDiskStats.bytesWritten > 0 { + // Only calculate speeds if we have a reasonable time interval and this isn't the first run + if timeInterval > 0.1 && (previousDiskStats.bytesRead > 0 || previousDiskStats.bytesWritten > 0) { let bytesRead = currentDiskStats.bytesRead > previousDiskStats.bytesRead ? currentDiskStats.bytesRead - previousDiskStats.bytesRead : 0 let bytesWritten = currentDiskStats.bytesWritten > previousDiskStats.bytesWritten ? From eac9f69977a16e8a7a7f5effd8315f9049af5d4d Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Wed, 13 Aug 2025 23:45:04 +0530 Subject: [PATCH 2/2] BugFix --- DynamicIsland/Localizable.xcstrings | 4 +- .../components/Clipboard/ClipboardPanel.swift | 39 ++++++++++++++++++- .../components/Settings/SettingsView.swift | 36 +++++++++++------ 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/DynamicIsland/Localizable.xcstrings b/DynamicIsland/Localizable.xcstrings index 44fd617..46713a8 100644 --- a/DynamicIsland/Localizable.xcstrings +++ b/DynamicIsland/Localizable.xcstrings @@ -327,7 +327,7 @@ "CPU Usage" : { }, - "Current custom timer: %@" : { + "Current custom timer:" : { }, "Current History" : { @@ -1219,7 +1219,7 @@ "unmuted" : { }, - "Update" : { + "Update Timer" : { }, "Upgrade to Pro" : { diff --git a/DynamicIsland/components/Clipboard/ClipboardPanel.swift b/DynamicIsland/components/Clipboard/ClipboardPanel.swift index 2576e0a..eb2318c 100644 --- a/DynamicIsland/components/Clipboard/ClipboardPanel.swift +++ b/DynamicIsland/components/Clipboard/ClipboardPanel.swift @@ -75,13 +75,48 @@ class ClipboardPanel: NSPanel { let screenFrame = screen.visibleFrame let panelFrame = frame - // Position at top center of screen (near where the notch would be) + // Check if we have a saved position + if let savedPosition = getSavedPosition() { + // Validate saved position is still on screen + let savedFrame = NSRect(origin: savedPosition, size: panelFrame.size) + if screenFrame.intersects(savedFrame) { + setFrameOrigin(savedPosition) + return + } + } + + // Default to center of screen (not top center) let xPosition = (screenFrame.width - panelFrame.width) / 2 + screenFrame.minX - let yPosition = screenFrame.maxY - panelFrame.height - 10 // 10px from top + let yPosition = (screenFrame.height - panelFrame.height) / 2 + screenFrame.minY setFrameOrigin(NSPoint(x: xPosition, y: yPosition)) } + private func getSavedPosition() -> NSPoint? { + let defaults = UserDefaults.standard + let x = defaults.double(forKey: "clipboardPanelPositionX") + let y = defaults.double(forKey: "clipboardPanelPositionY") + + // Check if we have valid saved coordinates (not default 0.0) + if x != 0.0 || y != 0.0 { + return NSPoint(x: x, y: y) + } + return nil + } + + private func saveCurrentPosition() { + let currentOrigin = frame.origin + let defaults = UserDefaults.standard + defaults.set(currentOrigin.x, forKey: "clipboardPanelPositionX") + defaults.set(currentOrigin.y, forKey: "clipboardPanelPositionY") + } + + override func setFrameOrigin(_ point: NSPoint) { + super.setFrameOrigin(point) + // Save position whenever it changes (user dragging) + saveCurrentPosition() + } + func positionNearMouse() { let mouseLocation = NSEvent.mouseLocation let panelFrame = frame diff --git a/DynamicIsland/components/Settings/SettingsView.swift b/DynamicIsland/components/Settings/SettingsView.swift index 75084ff..0471beb 100644 --- a/DynamicIsland/components/Settings/SettingsView.swift +++ b/DynamicIsland/components/Settings/SettingsView.swift @@ -1324,8 +1324,8 @@ struct TimerSettings: View { Text("Custom Timer Duration") .font(.headline) - HStack(spacing: 16) { - VStack { + HStack(spacing: 20) { + VStack(alignment: .center, spacing: 8) { Text("Minutes") .font(.system(size: 14, weight: .medium)) .foregroundStyle(.secondary) @@ -1336,10 +1336,10 @@ struct TimerSettings: View { } } .pickerStyle(.menu) - .frame(width: 80, height: 40) + .frame(width: 100) } - VStack { + VStack(alignment: .center, spacing: 8) { Text("Seconds") .font(.system(size: 14, weight: .medium)) .foregroundStyle(.secondary) @@ -1350,20 +1350,32 @@ struct TimerSettings: View { } } .pickerStyle(.menu) - .frame(width: 80, height: 40) + .frame(width: 100) } } + .frame(maxWidth: .infinity) - HStack { - Text("Current custom timer: \(customTimerDisplayText)") - .foregroundStyle(.secondary) - Spacer() - Button("Update") { - customTimerDuration = Double(customMinutes * 60 + customSeconds) + VStack(alignment: .leading, spacing: 8) { + HStack { + Text("Current custom timer:") + .foregroundStyle(.secondary) + Text(customTimerDisplayText) + .foregroundStyle(.primary) + .fontWeight(.medium) + Spacer() + } + + HStack { + Spacer() + Button("Update Timer") { + customTimerDuration = Double(customMinutes * 60 + customSeconds) + } + .disabled(customMinutes == 0 && customSeconds == 0) + .buttonStyle(.borderedProminent) } - .disabled(customMinutes == 0 && customSeconds == 0) } } + .padding(.vertical, 8) } header: { Text("Custom Timer") } footer: {