@@ -23,6 +23,7 @@ public struct WidgetFeature: ReducerProtocol {
2323 }
2424
2525 public struct State : Equatable {
26+ var focusingDocumentURL : URL ?
2627 public var colorScheme : ColorScheme = . light
2728
2829 // MARK: Panels
@@ -107,6 +108,7 @@ public struct WidgetFeature: ReducerProtocol {
107108
108109 case updateWindowLocation( animated: Bool )
109110 case updateWindowOpacity
111+ case updateFocusingDocumentURL
110112
111113 case panel( PanelFeature . Action )
112114 case chatPanel( ChatPanelFeature . Action )
@@ -121,6 +123,11 @@ public struct WidgetFeature: ReducerProtocol {
121123 @Dependency ( \. suggestionWidgetControllerDependency) var suggestionWidgetControllerDependency
122124 @Dependency ( \. activeApplicationMonitor) var activeApplicationMonitor
123125 @Dependency ( \. xcodeInspector) var xcodeInspector
126+ @Dependency ( \. mainQueue) var mainQueue
127+
128+ public enum DebounceKey : Hashable {
129+ case updateWindowOpacity
130+ }
124131
125132 public init ( ) { }
126133
@@ -301,6 +308,8 @@ public struct WidgetFeature: ReducerProtocol {
301308 case . observeWindowChange:
302309 guard let app = activeApplicationMonitor. activeApplication else { return . none }
303310 guard app. isXcode else { return . none }
311+
312+ let documentURL = state. focusingDocumentURL
304313
305314 return . run { send in
306315 await send ( . observeEditorChange)
@@ -319,17 +328,31 @@ public struct WidgetFeature: ReducerProtocol {
319328 kAXWindowMiniaturizedNotification,
320329 kAXWindowDeminiaturizedNotification
321330 )
331+
322332 for await notification in notifications {
323333 try Task . checkCancellation ( )
324334
335+ // Hide the widgets before switching to another window/editor
336+ // so the transition looks better.
337+ if [
338+ kAXFocusedUIElementChangedNotification,
339+ kAXFocusedWindowChangedNotification,
340+ ] . contains ( notification. name) {
341+ let newDocumentURL = xcodeInspector. realtimeActiveDocumentURL
342+ if documentURL != newDocumentURL {
343+ await send ( . panel( . removeDisplayedContent) )
344+ await hidePanelWindows ( )
345+ }
346+ await send ( . updateFocusingDocumentURL)
347+ }
348+
349+ // update widgets.
325350 if [
326351 kAXFocusedUIElementChangedNotification,
327352 kAXApplicationActivatedNotification,
328353 kAXMainWindowChangedNotification,
329354 kAXFocusedWindowChangedNotification,
330355 ] . contains ( notification. name) {
331- await hidePanelWindows ( )
332- await send ( . panel( . removeDisplayedContent) )
333356 await send ( . updateWindowLocation( animated: false ) )
334357 await send ( . updateWindowOpacity)
335358 await send ( . observeEditorChange)
@@ -421,6 +444,10 @@ public struct WidgetFeature: ReducerProtocol {
421444 state. panelState. suggestionPanelState. colorScheme = scheme
422445 state. chatPanelState. colorScheme = scheme
423446 return . none
447+
448+ case . updateFocusingDocumentURL:
449+ state. focusingDocumentURL = xcodeInspector. realtimeActiveDocumentURL
450+ return . none
424451
425452 case let . updateWindowLocation( animated) :
426453 guard let widgetLocation = generateWidgetLocation ( ) else { return . none }
@@ -486,8 +513,8 @@ public struct WidgetFeature: ReducerProtocol {
486513 case . updateWindowOpacity:
487514 let isChatPanelDetached = state. chatPanelState. chatPanelInASeparateWindow
488515 let hasChat = !state. chatPanelState. chatTabGroup. tabInfo. isEmpty
489-
490516 return . run { _ in
517+ try await mainQueue. sleep ( for: . seconds( 0.2 ) )
491518 Task { @MainActor in
492519 if let app = activeApplicationMonitor. activeApplication, app. isXcode {
493520 let application = AXUIElementCreateApplication ( app. processIdentifier)
@@ -538,6 +565,7 @@ public struct WidgetFeature: ReducerProtocol {
538565 }
539566 }
540567 }
568+ . cancellable ( id: DebounceKey . updateWindowOpacity, cancelInFlight: true )
541569
542570 case . circularWidget:
543571 return . none
0 commit comments