Merge pull request #1401 from manaflow-ai/task-cmd-shift-u-exits-cmd-shift-enter-mode
Exit split zoom when jumping to unread
This commit is contained in:
commit
5dd93a8ab1
4 changed files with 87 additions and 5 deletions
|
|
@ -9980,7 +9980,20 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
|
|||
|
||||
context.sidebarSelectionState.selection = .tabs
|
||||
bringToFront(window)
|
||||
context.tabManager.focusTabFromNotification(tabId, surfaceId: surfaceId)
|
||||
guard context.tabManager.focusTabFromNotification(tabId, surfaceId: surfaceId) else {
|
||||
#if DEBUG
|
||||
recordMultiWindowNotificationOpenFailureIfNeeded(
|
||||
tabId: tabId,
|
||||
surfaceId: surfaceId,
|
||||
notificationId: notificationId,
|
||||
reason: "focus_failed"
|
||||
)
|
||||
if ProcessInfo.processInfo.environment["CMUX_UI_TEST_JUMP_UNREAD_SETUP"] == "1" {
|
||||
writeJumpUnreadTestData(["jumpUnreadOpenResult": "0"])
|
||||
}
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// UI test support: Jump-to-unread asserts that the correct workspace/panel is focused.
|
||||
|
|
@ -10045,7 +10058,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
|
|||
|
||||
sidebarSelectionState?.selection = .tabs
|
||||
bringToFront(window)
|
||||
tabManager.focusTabFromNotification(tabId, surfaceId: surfaceId)
|
||||
guard tabManager.focusTabFromNotification(tabId, surfaceId: surfaceId) else {
|
||||
#if DEBUG
|
||||
if ProcessInfo.processInfo.environment["CMUX_UI_TEST_JUMP_UNREAD_SETUP"] == "1" {
|
||||
writeJumpUnreadTestData([
|
||||
"jumpUnreadFallbackFail": "focus_failed",
|
||||
"jumpUnreadOpenResult": "0",
|
||||
])
|
||||
}
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
recordJumpUnreadFocusFromModelIfNeeded(
|
||||
|
|
|
|||
|
|
@ -2214,14 +2214,33 @@ class TabManager: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func focusTabFromNotification(_ tabId: UUID, surfaceId: UUID? = nil) {
|
||||
@discardableResult
|
||||
func focusTabFromNotification(_ tabId: UUID, surfaceId: UUID? = nil) -> Bool {
|
||||
let wasSelected = selectedTabId == tabId
|
||||
let desiredPanelId = surfaceId ?? tabs.first(where: { $0.id == tabId })?.focusedPanelId
|
||||
guard let tab = tabs.first(where: { $0.id == tabId }) else {
|
||||
#if DEBUG
|
||||
dlog("notification.focus.fail tab=\(tabId.uuidString.prefix(5)) reason=missingTab")
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
if let surfaceId, tab.panels[surfaceId] == nil {
|
||||
#if DEBUG
|
||||
dlog(
|
||||
"notification.focus.fail tab=\(tabId.uuidString.prefix(5)) " +
|
||||
"panel=\(surfaceId.uuidString.prefix(5)) reason=missingPanel"
|
||||
)
|
||||
#endif
|
||||
return false
|
||||
}
|
||||
let desiredPanelId = surfaceId ?? tab.focusedPanelId
|
||||
#if DEBUG
|
||||
if let desiredPanelId {
|
||||
AppDelegate.shared?.armJumpUnreadFocusRecord(tabId: tabId, surfaceId: desiredPanelId)
|
||||
}
|
||||
#endif
|
||||
// Jump-to-unread should reveal the destination pane instead of keeping an old split-zoom
|
||||
// state active around it.
|
||||
tab.clearSplitZoom()
|
||||
suppressFocusFlash = true
|
||||
focusTab(tabId, surfaceId: desiredPanelId, suppressFlash: true)
|
||||
if wasSelected {
|
||||
|
|
@ -2239,6 +2258,7 @@ class TabManager: ObservableObject {
|
|||
tab.triggerNotificationFocusFlash(panelId: targetPanelId, requiresSplit: false, shouldFocus: true)
|
||||
notificationStore.markRead(forTabId: tabId, surfaceId: targetPanelId)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func focusSurface(tabId: UUID, surfaceId: UUID) {
|
||||
|
|
|
|||
|
|
@ -11142,7 +11142,9 @@ class TerminalController {
|
|||
result = "ERROR: Surface not found"
|
||||
return
|
||||
}
|
||||
tabManager.focusTabFromNotification(tab.id, surfaceId: surfaceId)
|
||||
if !tabManager.focusTabFromNotification(tab.id, surfaceId: surfaceId) {
|
||||
result = "ERROR: Focus failed"
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5589,6 +5589,43 @@ final class TabManagerCloseCurrentPanelTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class TabManagerNotificationFocusTests: XCTestCase {
|
||||
func testFocusTabFromNotificationClearsSplitZoomBeforeFocusingTargetPanel() {
|
||||
let manager = TabManager()
|
||||
guard let workspace = manager.selectedWorkspace,
|
||||
let leftPanelId = workspace.focusedPanelId,
|
||||
let rightPanel = workspace.newTerminalSplit(from: leftPanelId, orientation: .horizontal) else {
|
||||
XCTFail("Expected split setup to succeed")
|
||||
return
|
||||
}
|
||||
|
||||
workspace.focusPanel(leftPanelId)
|
||||
XCTAssertTrue(workspace.toggleSplitZoom(panelId: leftPanelId), "Expected split zoom to enable")
|
||||
XCTAssertTrue(workspace.bonsplitController.isSplitZoomed, "Expected workspace to start zoomed")
|
||||
|
||||
XCTAssertTrue(manager.focusTabFromNotification(workspace.id, surfaceId: rightPanel.id))
|
||||
drainMainQueue()
|
||||
drainMainQueue()
|
||||
|
||||
XCTAssertFalse(
|
||||
workspace.bonsplitController.isSplitZoomed,
|
||||
"Expected notification focus to exit split zoom so the target pane becomes visible"
|
||||
)
|
||||
XCTAssertEqual(workspace.focusedPanelId, rightPanel.id, "Expected notification target panel to be focused")
|
||||
}
|
||||
|
||||
func testFocusTabFromNotificationReturnsFalseForMissingPanel() {
|
||||
let manager = TabManager()
|
||||
guard let workspace = manager.selectedWorkspace else {
|
||||
XCTFail("Expected selected workspace")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertFalse(manager.focusTabFromNotification(workspace.id, surfaceId: UUID()))
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class TabManagerPendingUnfocusPolicyTests: XCTestCase {
|
||||
func testDoesNotUnfocusWhenPendingTabIsCurrentlySelected() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue