mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
124 lines
4.9 KiB
Markdown
124 lines
4.9 KiB
Markdown
# 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
|
|
1. `createDynamicIslandWindow()` creates window with `openNotchSize` (fixed size)
|
|
2. `positionWindow()` centers it using current window width
|
|
3. Window is perfectly centered initially
|
|
|
|
### When User Switches to Stats Tab (4+ graphs)
|
|
1. `coordinator.$currentView` triggers `updateWindowSizeIfNeeded()`
|
|
2. `calculateRequiredNotchSize()` returns larger size (openNotchSize.width + extraWidth)
|
|
3. `updateWindowSizeIfNeeded()` resizes window and re-centers using new width
|
|
4. Window should stay centered with new larger size
|
|
|
|
### When User Switches Away from Stats Tab
|
|
1. `coordinator.$currentView` triggers `updateWindowSizeIfNeeded()` again
|
|
2. `calculateRequiredNotchSize()` returns normal `openNotchSize`
|
|
3. `updateWindowSizeIfNeeded()` resizes window back and re-centers using normal width
|
|
4. **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:
|
|
|
|
1. User clicks another tab
|
|
2. `coordinator.$currentView` fires immediately
|
|
3. `updateWindowSizeIfNeeded()` calculates size as if we're NOT on stats tab
|
|
4. BUT the ContentView might still be showing stats content (transition not complete)
|
|
5. Window gets resized to small size while content is still large
|
|
6. 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:
|
|
```swift
|
|
var dynamicNotchSize: CGSize {
|
|
// calculation logic
|
|
}
|
|
```
|
|
|
|
And uses it in:
|
|
```swift
|
|
.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
|
|
|
|
1. Remove all dynamic window resizing logic
|
|
2. Set window to maximum possible size (openNotchSize.width + max extra width)
|
|
3. Let ContentView handle all dynamic sizing internally
|
|
4. 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:
|
|
|
|
1. **"Show on all displays" toggle**: Creates new window with default `openNotchSize`, losing dynamic sizing
|
|
2. **Screen changes**: `adjustWindowPosition()` creates new windows with wrong size
|
|
3. **App restarts/other events**: Any time a new window is created, it ignores current dynamic sizing needs
|
|
|
|
#### The Wrong Code:
|
|
```swift
|
|
// OLD - ALWAYS used openNotchSize
|
|
let window = DynamicIslandWindow(
|
|
contentRect: NSRect(x: 0, y: 0, width: openNotchSize.width, height: openNotchSize.height),
|
|
...
|
|
```
|
|
|
|
#### The Fix:
|
|
```swift
|
|
// 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!
|