From 2b2b926fdc18f0bcb49b830b510e06de4e8b4c26 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 30 Mar 2026 14:27:31 +0300 Subject: [PATCH] Clean up the window manager and its protocols --- .../Application/Windowing/WindowManager.swift | 54 ++++---- .../Windowing/WindowManagerProtocol.swift | 22 ++- .../Mocks/Generated/GeneratedMocks.swift | 130 +++++++++++------- 3 files changed, 128 insertions(+), 78 deletions(-) diff --git a/ElementX/Sources/Application/Windowing/WindowManager.swift b/ElementX/Sources/Application/Windowing/WindowManager.swift index 40b846212..0154ced18 100644 --- a/ElementX/Sources/Application/Windowing/WindowManager.swift +++ b/ElementX/Sources/Application/Windowing/WindowManager.swift @@ -74,31 +74,6 @@ class WindowManager: SecureWindowManagerProtocol { self.dismissWindowAction = dismissWindowAction } - func registerCoordinator(_ coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, forWindowType type: WindowManagerWindowType) { - coordinators[type] = (coordinator, flowCoordinator) - openWindowAction(value: type) - } - - func closeAllAuxiliaryWindows() { - for key in coordinators.keys { - dismissWindowAction(value: key) - } - - coordinators.removeAll() - } - - func windowForType(_ type: WindowManagerWindowType) -> AnyView { - guard let coordinator = coordinators[type]?.coordinator else { - return AnyView(InstantlyDismissingWindow()) - } - - // This behaves strangely and gets called late but cleans up enough - // and is self contained enough to be just good .. enough - return AnyView(coordinator.toPresentable().onDisappear { [weak self] in - self?.coordinators[type] = nil - }) - } - func handleRoute(_ appRoute: AppRoute, windowType: WindowManagerWindowType) { if let flowCoordinator = coordinators[windowType]?.flowCoordinator { flowCoordinator.handleAppRoute(appRoute, animated: true) @@ -167,6 +142,8 @@ class WindowManager: SecureWindowManagerProtocol { mainWindow.makeKey() } + // MARK: - OrientationManager + func setOrientation(_ orientation: UIInterfaceOrientationMask) { mainScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientation)) } @@ -175,9 +152,36 @@ class WindowManager: SecureWindowManagerProtocol { appDelegate.orientationLock = orientation } + // MARK: - Auxiliary window support + + func windowForType(_ type: WindowManagerWindowType) -> AnyView { + guard let coordinator = coordinators[type]?.coordinator else { + return AnyView(InstantlyDismissingWindow()) + } + + // This behaves strangely and gets called late but cleans up enough + // and is self contained enough to be just good .. enough + return AnyView(coordinator.toPresentable().onDisappear { [weak self] in + self?.coordinators[type] = nil + }) + } + + func registerCoordinator(_ coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, forWindowType type: WindowManagerWindowType) { + coordinators[type] = (coordinator, flowCoordinator) + openWindowAction(value: type) + } + func closeAuxiliaryWindow(forType type: WindowManagerWindowType) { dismissWindowAction(value: type) } + + func closeAllAuxiliaryWindows() { + for key in coordinators.keys { + dismissWindowAction(value: key) + } + + coordinators.removeAll() + } } private class PassthroughWindow: UIWindow { diff --git a/ElementX/Sources/Application/Windowing/WindowManagerProtocol.swift b/ElementX/Sources/Application/Windowing/WindowManagerProtocol.swift index 7a3b1b27e..85aa37e7b 100644 --- a/ElementX/Sources/Application/Windowing/WindowManagerProtocol.swift +++ b/ElementX/Sources/Application/Windowing/WindowManagerProtocol.swift @@ -29,13 +29,16 @@ protocol SecureWindowManagerProtocol: WindowManagerProtocol { func handleRoute(_ appRoute: AppRoute, windowType: WindowManagerWindowType) - func windowForType(_ type: WindowManagerWindowType) -> AnyView - /// Shows the main and overlay window combo, hiding the alternate window. func switchToMain() /// Shows the alternate window, hiding the main and overlay combo. func switchToAlternate() + + // MARK: - Auxiliary window support + + /// Used by the Application to retrieve the root view for an auxiliary window + func windowForType(_ type: WindowManagerWindowType) -> AnyView } /// A window manager that supports switching between a main app window with an overlay and @@ -54,15 +57,22 @@ protocol WindowManagerProtocol: AnyObject, OrientationManagerProtocol { /// All the windows being managed var windows: [UIWindow] { get } - func registerCoordinator(_ coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, forWindowType type: WindowManagerWindowType) - - func closeAllAuxiliaryWindows() - /// Makes the global search window key. Used to get automatic text field focus. func showGlobalSearch() func hideGlobalSearch() + // MARK: - Auxiliary window support + + /// Register a coordinator and it's respective flow (if any) within the WindowManager which in turn + /// invokes the Application's `OpenWindowAction` + func registerCoordinator(_ coordinator: CoordinatorProtocol, + flowCoordinator: FlowCoordinatorProtocol?, + forWindowType type: WindowManagerWindowType) + + /// Closes any window previously opened by registering a coordinator + func closeAllAuxiliaryWindows() + /// Closes a previously opened window for the given type. func closeAuxiliaryWindow(forType type: WindowManagerWindowType) } diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 63ac9834c..dd4f4d8ad 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -21358,6 +21358,76 @@ class WindowManagerMock: WindowManagerProtocol, @unchecked Sendable { var alternateWindow: UIWindow! var windows: [UIWindow] = [] + //MARK: - showGlobalSearch + + var showGlobalSearchUnderlyingCallsCount = 0 + var showGlobalSearchCallsCount: Int { + get { + if Thread.isMainThread { + return showGlobalSearchUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = showGlobalSearchUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + showGlobalSearchUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + showGlobalSearchUnderlyingCallsCount = newValue + } + } + } + } + var showGlobalSearchCalled: Bool { + return showGlobalSearchCallsCount > 0 + } + var showGlobalSearchClosure: (() -> Void)? + + func showGlobalSearch() { + showGlobalSearchCallsCount += 1 + showGlobalSearchClosure?() + } + //MARK: - hideGlobalSearch + + var hideGlobalSearchUnderlyingCallsCount = 0 + var hideGlobalSearchCallsCount: Int { + get { + if Thread.isMainThread { + return hideGlobalSearchUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = hideGlobalSearchUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + hideGlobalSearchUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + hideGlobalSearchUnderlyingCallsCount = newValue + } + } + } + } + var hideGlobalSearchCalled: Bool { + return hideGlobalSearchCallsCount > 0 + } + var hideGlobalSearchClosure: (() -> Void)? + + func hideGlobalSearch() { + hideGlobalSearchCallsCount += 1 + hideGlobalSearchClosure?() + } //MARK: - registerCoordinator var registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount = 0 @@ -21434,17 +21504,17 @@ class WindowManagerMock: WindowManagerProtocol, @unchecked Sendable { closeAllAuxiliaryWindowsCallsCount += 1 closeAllAuxiliaryWindowsClosure?() } - //MARK: - showGlobalSearch + //MARK: - closeAuxiliaryWindow - var showGlobalSearchUnderlyingCallsCount = 0 - var showGlobalSearchCallsCount: Int { + var closeAuxiliaryWindowForTypeUnderlyingCallsCount = 0 + var closeAuxiliaryWindowForTypeCallsCount: Int { get { if Thread.isMainThread { - return showGlobalSearchUnderlyingCallsCount + return closeAuxiliaryWindowForTypeUnderlyingCallsCount } else { var returnValue: Int? = nil DispatchQueue.main.sync { - returnValue = showGlobalSearchUnderlyingCallsCount + returnValue = closeAuxiliaryWindowForTypeUnderlyingCallsCount } return returnValue! @@ -21452,62 +21522,28 @@ class WindowManagerMock: WindowManagerProtocol, @unchecked Sendable { } set { if Thread.isMainThread { - showGlobalSearchUnderlyingCallsCount = newValue + closeAuxiliaryWindowForTypeUnderlyingCallsCount = newValue } else { DispatchQueue.main.sync { - showGlobalSearchUnderlyingCallsCount = newValue + closeAuxiliaryWindowForTypeUnderlyingCallsCount = newValue } } } } - var showGlobalSearchCalled: Bool { - return showGlobalSearchCallsCount > 0 var closeAuxiliaryWindowForTypeCalled: Bool { return closeAuxiliaryWindowForTypeCallsCount > 0 } - var showGlobalSearchClosure: (() -> Void)? var closeAuxiliaryWindowForTypeReceivedType: WindowManagerWindowType? var closeAuxiliaryWindowForTypeReceivedInvocations: [WindowManagerWindowType] = [] var closeAuxiliaryWindowForTypeClosure: ((WindowManagerWindowType) -> Void)? - func showGlobalSearch() { - showGlobalSearchCallsCount += 1 - showGlobalSearchClosure?() - } - //MARK: - hideGlobalSearch - - var hideGlobalSearchUnderlyingCallsCount = 0 - var hideGlobalSearchCallsCount: Int { - get { - if Thread.isMainThread { - return hideGlobalSearchUnderlyingCallsCount - } else { - var returnValue: Int? = nil - DispatchQueue.main.sync { - returnValue = hideGlobalSearchUnderlyingCallsCount - } - - return returnValue! - } + func closeAuxiliaryWindow(forType type: WindowManagerWindowType) { + closeAuxiliaryWindowForTypeCallsCount += 1 + closeAuxiliaryWindowForTypeReceivedType = type + DispatchQueue.main.async { + self.closeAuxiliaryWindowForTypeReceivedInvocations.append(type) } - set { - if Thread.isMainThread { - hideGlobalSearchUnderlyingCallsCount = newValue - } else { - DispatchQueue.main.sync { - hideGlobalSearchUnderlyingCallsCount = newValue - } - } - } - } - var hideGlobalSearchCalled: Bool { - return hideGlobalSearchCallsCount > 0 - } - var hideGlobalSearchClosure: (() -> Void)? - - func hideGlobalSearch() { - hideGlobalSearchCallsCount += 1 - hideGlobalSearchClosure?() + closeAuxiliaryWindowForTypeClosure?(type) } //MARK: - setOrientation