diff --git a/AudioPriorityBar/Views/DeviceListView.swift b/AudioPriorityBar/Views/DeviceListView.swift index 4077372..150c0a3 100644 --- a/AudioPriorityBar/Views/DeviceListView.swift +++ b/AudioPriorityBar/Views/DeviceListView.swift @@ -145,14 +145,15 @@ struct DraggableDeviceRow: View { } private func calculateTarget(offset: CGFloat) -> Int? { - let rowsOffset = Int(round(offset / rowHeight)) - var newTarget = index + rowsOffset - newTarget = max(0, min(deviceCount, newTarget)) - - if newTarget == index || newTarget == index + 1 { - return nil - } - return newTarget + let pitch = rowHeight + 4 // row height + VStack spacing + // Flip as soon as the dragged centre crosses a neighbour's midpoint, + // rather than requiring a ~1.5-row overshoot before reordering. + let rowsMoved = Int((offset / pitch).rounded()) + if rowsMoved == 0 { return nil } + // Dragging down inserts *after* the rows crossed, hence the +1. + let raw = rowsMoved > 0 ? index + rowsMoved + 1 : index + rowsMoved + let target = max(0, min(deviceCount, raw)) + return (target == index || target == index + 1) ? nil : target } var body: some View { diff --git a/AudioPriorityBar/Views/MenuBarView.swift b/AudioPriorityBar/Views/MenuBarView.swift index 3ad55c2..d87461e 100644 --- a/AudioPriorityBar/Views/MenuBarView.swift +++ b/AudioPriorityBar/Views/MenuBarView.swift @@ -82,7 +82,6 @@ struct MenuBarView: View { .padding(.horizontal, 16) .padding(.vertical, 14) } - .frame(maxHeight: 420) Divider() .padding(.horizontal, 12) @@ -133,6 +132,12 @@ struct MenuBarView: View { .animation(.easeInOut(duration: 0.2), value: audioManager.isEditMode) } .frame(width: 340) + // macOS 26 (Tahoe): a ScrollView reports 0 ideal height, so a plain + // maxHeight on it collapses the fit-to-content MenuBarExtra window down + // to just the header and footer. Size the window to its content instead, + // capped so a long device list scrolls rather than running off-screen. + .fixedSize(horizontal: false, vertical: true) + .frame(maxHeight: 650) } }