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/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/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 ?