4.9 KiB
Dynamic Island Alignment Logic Analysis
Problem Statement
The Dynamic Island window sometimes gets misaligned (moves to the left) when switching between tabs, especially when going from stats tab (with 4+ graphs that make the window wider) back to other tabs.
Current Implementation Analysis
When Window is Created
createDynamicIslandWindow()creates window withopenNotchSize(fixed size)positionWindow()centers it using current window width- Window is perfectly centered initially
When User Switches to Stats Tab (4+ graphs)
coordinator.$currentViewtriggersupdateWindowSizeIfNeeded()calculateRequiredNotchSize()returns larger size (openNotchSize.width + extraWidth)updateWindowSizeIfNeeded()resizes window and re-centers using new width- Window should stay centered with new larger size
When User Switches Away from Stats Tab
coordinator.$currentViewtriggersupdateWindowSizeIfNeeded()againcalculateRequiredNotchSize()returns normalopenNotchSizeupdateWindowSizeIfNeeded()resizes window back and re-centers using normal width- THIS IS WHERE THE PROBLEM OCCURS
Root Cause Analysis
The Issue: Timing and State Mismatch
The problem is likely that coordinator.currentView and the actual UI state are not perfectly synchronized. Here's what probably happens:
- User clicks another tab
coordinator.$currentViewfires immediatelyupdateWindowSizeIfNeeded()calculates size as if we're NOT on stats tab- BUT the ContentView might still be showing stats content (transition not complete)
- Window gets resized to small size while content is still large
- This causes misalignment because content and window size don't match
Why It Sometimes Works
- When the UI transition is fast enough, everything stays in sync
- When there's any delay or animation, they get out of sync
Potential Solutions
Option 1: Delay the Window Resize
Add a small delay to ensure UI transition is complete before resizing window.
Option 2: Remove Window Resizing, Use Content Clipping
Let the window stay large and let the content handle its own sizing internally.
Option 3: Better State Synchronization
Make sure window resizing only happens when we're 100% sure the content has updated.
Option 4: Use ContentView's dynamicNotchSize Instead
The ContentView already has dynamicNotchSize logic. Maybe the window should use that instead of having its own calculation.
Recommended Approach
Option 2 seems safest: Remove dynamic window resizing entirely and let the content handle sizing.
The ContentView already has:
var dynamicNotchSize: CGSize {
// calculation logic
}
And uses it in:
.frame(maxWidth: dynamicNotchSize.width, maxHeight: dynamicNotchSize.height)
This means the content already knows how to size itself. The window can stay at the maximum possible size, and the content will center itself within that space.
Test Plan
- Remove all dynamic window resizing logic
- Set window to maximum possible size (openNotchSize.width + max extra width)
- Let ContentView handle all dynamic sizing internally
- Test alignment stays perfect
This eliminates the timing issue completely because the window never changes size after initial creation.
REAL ROOT CAUSE FOUND AND FIXED
The ACTUAL Problem: Window Creation with Wrong Size
The issue was NOT positioning logic - it was that createDynamicIslandWindow() always created windows with openNotchSize instead of the current required size!
When This Caused Problems:
- "Show on all displays" toggle: Creates new window with default
openNotchSize, losing dynamic sizing - Screen changes:
adjustWindowPosition()creates new windows with wrong size - App restarts/other events: Any time a new window is created, it ignores current dynamic sizing needs
The Wrong Code:
// OLD - ALWAYS used openNotchSize
let window = DynamicIslandWindow(
contentRect: NSRect(x: 0, y: 0, width: openNotchSize.width, height: openNotchSize.height),
...
The Fix:
// NEW - Uses current required size
let requiredSize = calculateRequiredNotchSize()
let window = DynamicIslandWindow(
contentRect: NSRect(x: 0, y: 0, width: requiredSize.width, height: requiredSize.height),
...
Why This Fixes Everything:
✅ "Show on all displays" toggle: New windows created with correct size
✅ Tab switching: No more size mismatch when repositioning
✅ Screen changes: New windows respect current graph settings
✅ Consistent behavior: All window creation uses same sizing logic
The Real Issue Was:
- Windows created with wrong size, then positioned correctly = misalignment
- Content expecting larger window, but window is small = positioning errors
- Dynamic sizing only worked if you never triggered window recreation
Result:
Perfect alignment in ALL scenarios - no more window size/content size mismatches!