mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 07:57:40 +00:00
fix(macos): show sessions after controls in tray menu (#38079)
* fix(macos): show sessions after controls in tray menu When many sessions are active, the injected session rows push the toggles, action buttons, and settings items off-screen, requiring a scroll to reach them. Change findInsertIndex and findNodesInsertIndex to anchor just before the separator above 'Settings…' instead of before 'Send Heartbeats'. This ensures the controls section is always immediately visible on menu open, with sessions appearing below. * refactor: extract findAnchoredInsertIndex to eliminate duplication findInsertIndex and findNodesInsertIndex shared identical logic. Extract into a single private helper so any future anchor change (e.g. Settings item title) only needs one edit. * macOS: use structural tray menu anchor --------- Co-authored-by: Brian Ernesto <bernesto@users.noreply.github.com> Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
This commit is contained in:
@@ -1099,38 +1099,33 @@ extension MenuSessionsInjector {
|
||||
// MARK: - Width + placement
|
||||
|
||||
private func findInsertIndex(in menu: NSMenu) -> Int? {
|
||||
// Insert right before the separator above "Send Heartbeats".
|
||||
if let idx = menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }) {
|
||||
if let sepIdx = menu.items[..<idx].lastIndex(where: { $0.isSeparatorItem }) {
|
||||
return sepIdx
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
if let sepIdx = menu.items.firstIndex(where: { $0.isSeparatorItem }) {
|
||||
return sepIdx
|
||||
}
|
||||
|
||||
if menu.items.count >= 1 { return 1 }
|
||||
return menu.items.count
|
||||
self.findDynamicSectionInsertIndex(in: menu)
|
||||
}
|
||||
|
||||
private func findNodesInsertIndex(in menu: NSMenu) -> Int? {
|
||||
if let idx = menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }) {
|
||||
if let sepIdx = menu.items[..<idx].lastIndex(where: { $0.isSeparatorItem }) {
|
||||
return sepIdx
|
||||
}
|
||||
return idx
|
||||
self.findDynamicSectionInsertIndex(in: menu)
|
||||
}
|
||||
|
||||
private func findDynamicSectionInsertIndex(in menu: NSMenu) -> Int? {
|
||||
// Keep controls and action buttons visible by inserting dynamic rows at the
|
||||
// built-in footer boundary, not by matching localized menu item titles.
|
||||
if let footerSeparatorIndex = menu.items.lastIndex(where: { item in
|
||||
item.isSeparatorItem && !self.isInjectedItem(item)
|
||||
}) {
|
||||
return footerSeparatorIndex
|
||||
}
|
||||
|
||||
if let sepIdx = menu.items.firstIndex(where: { $0.isSeparatorItem }) {
|
||||
return sepIdx
|
||||
if let firstBaseItemIndex = menu.items.firstIndex(where: { !self.isInjectedItem($0) }) {
|
||||
return min(firstBaseItemIndex + 1, menu.items.count)
|
||||
}
|
||||
|
||||
if menu.items.count >= 1 { return 1 }
|
||||
return menu.items.count
|
||||
}
|
||||
|
||||
private func isInjectedItem(_ item: NSMenuItem) -> Bool {
|
||||
item.tag == self.tag || item.tag == self.nodesTag
|
||||
}
|
||||
|
||||
private func initialWidth(for menu: NSMenu) -> CGFloat {
|
||||
if let openWidth = self.menuOpenWidth {
|
||||
return max(300, openWidth)
|
||||
@@ -1236,5 +1231,13 @@ extension MenuSessionsInjector {
|
||||
func injectForTesting(into menu: NSMenu) {
|
||||
self.inject(into: menu)
|
||||
}
|
||||
|
||||
func testingFindInsertIndex(in menu: NSMenu) -> Int? {
|
||||
self.findInsertIndex(in: menu)
|
||||
}
|
||||
|
||||
func testingFindNodesInsertIndex(in menu: NSMenu) -> Int? {
|
||||
self.findNodesInsertIndex(in: menu)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user