fix(macos): fix split view layout so panels are visible and VoiceOver-reachable

The main window's NSSplitView panels (channel list, user list, chat,
activity log) were collapsing to zero size because:

1. The scroll views inside the split views were missing
   translatesAutoresizingMaskIntoConstraints = false, so Auto Layout
   couldn't manage their sizes.
2. The inner split views were also missing it.
3. The voice panel had no height constraint, so it expanded to fill
   all available space (539px of the 600px window), starving the
   outer split view down to 1px tall.
4. The split views had no initial divider positions, so panels
   collapsed to zero even when the split view had space.

Add translatesAutoresizingMaskIntoConstraints = false to all four
scroll views and both inner split views, give the voice panel a
96px height constraint, and set initial divider positions after the
window is on screen. The panels now get reasonable space, are
visible on screen, and are reachable by VoiceOver.
This commit is contained in:
2026-06-18 17:35:14 +02:00
parent c684824b10
commit 75c2782860

View File

@@ -125,6 +125,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
let innerSplit = NSSplitView() let innerSplit = NSSplitView()
innerSplit.isVertical = false innerSplit.isVertical = false
innerSplit.dividerStyle = .thin innerSplit.dividerStyle = .thin
innerSplit.translatesAutoresizingMaskIntoConstraints = false
let channelPanel = buildChannelPanel() let channelPanel = buildChannelPanel()
let userPanel = buildUserPanel() let userPanel = buildUserPanel()
@@ -137,6 +138,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
let rightSplit = NSSplitView() let rightSplit = NSSplitView()
rightSplit.isVertical = false rightSplit.isVertical = false
rightSplit.dividerStyle = .thin rightSplit.dividerStyle = .thin
rightSplit.translatesAutoresizingMaskIntoConstraints = false
let chatPanel = buildChatPanel() let chatPanel = buildChatPanel()
let activityPanel = buildActivityPanel() let activityPanel = buildActivityPanel()
rightSplit.addArrangedSubview(chatPanel) rightSplit.addArrangedSubview(chatPanel)
@@ -178,6 +180,17 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
composeBar.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), composeBar.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
composeBar.heightAnchor.constraint(equalToConstant: 36), composeBar.heightAnchor.constraint(equalToConstant: 36),
]) ])
// Set initial divider positions so panels get reasonable space instead of
// collapsing to zero. These are applied after the window is on screen.
DispatchQueue.main.async { [weak self, weak outerSplit, weak innerSplit, weak rightSplit] in
// outerSplit is vertical (left|right): divide at 40% from left
outerSplit?.setPosition(360, ofDividerAt: 0)
// innerSplit is horizontal (channels on top, users below): divide at 60% from top
innerSplit?.setPosition(260, ofDividerAt: 0)
// rightSplit is horizontal (chat on top, activity below): divide at 70% from top
rightSplit?.setPosition(280, ofDividerAt: 0)
}
} }
private func buildChannelPanel() -> NSView { private func buildChannelPanel() -> NSView {
@@ -195,6 +208,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
sv.documentView = channelOutlineView sv.documentView = channelOutlineView
sv.hasVerticalScroller = true sv.hasVerticalScroller = true
sv.borderType = .noBorder sv.borderType = .noBorder
sv.translatesAutoresizingMaskIntoConstraints = false
let menu = NSMenu() let menu = NSMenu()
menu.delegate = self menu.delegate = self
@@ -221,6 +235,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
sv.documentView = userTableView sv.documentView = userTableView
sv.hasVerticalScroller = true sv.hasVerticalScroller = true
sv.borderType = .noBorder sv.borderType = .noBorder
sv.translatesAutoresizingMaskIntoConstraints = false
return sv return sv
} }
@@ -233,6 +248,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
sv.documentView = chatTextView sv.documentView = chatTextView
sv.hasVerticalScroller = true sv.hasVerticalScroller = true
sv.borderType = .noBorder sv.borderType = .noBorder
sv.translatesAutoresizingMaskIntoConstraints = false
return sv return sv
} }
@@ -248,6 +264,7 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
sv.documentView = activityTableView sv.documentView = activityTableView
sv.hasVerticalScroller = true sv.hasVerticalScroller = true
sv.borderType = .noBorder sv.borderType = .noBorder
sv.translatesAutoresizingMaskIntoConstraints = false
return sv return sv
} }
@@ -365,6 +382,8 @@ final class MainWindowController: NSWindowController, NSWindowDelegate {
levelMeter.widthAnchor.constraint(equalToConstant: 100), levelMeter.widthAnchor.constraint(equalToConstant: 100),
devicePicker.widthAnchor.constraint(greaterThanOrEqualToConstant: 160), devicePicker.widthAnchor.constraint(greaterThanOrEqualToConstant: 160),
panel.heightAnchor.constraint(equalToConstant: 96),
]) ])
return panel return panel
} }