Introduce support for multiple windows on mac and iPad OS

Once the app starts the WindowManager is configured with SwiftUI's environment OpenWindowAction. It can then be used to register coordinators (that provide the toPresentable view) and an optional flow coordinator (as most of the screens are part of a flow, especially rooms).
Once a coordinator is registed, the WindowManager invokes the OpenWindowAction which in turn makes the Application call its newly introduced WindowManagerWindowType WindowGroup's block to instantiate a new visual window rooting that view.

The WindowManager is also responsible for wrapping the presentable in a disappearance block and clean up the coordinator stack.

# Conflicts:
#	ElementX/Sources/Application/AppCoordinator.swift
This commit is contained in:
Stefan Ceriu
2026-03-26 20:28:50 +02:00
committed by Stefan Ceriu
parent 91a10f4d51
commit f1ef968975
16 changed files with 231 additions and 63 deletions
@@ -21358,6 +21358,47 @@ class WindowManagerMock: WindowManagerProtocol, @unchecked Sendable {
var alternateWindow: UIWindow!
var windows: [UIWindow] = []
//MARK: - registerCoordinator
var registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount = 0
var registerCoordinatorFlowCoordinatorForWindowTypeCallsCount: Int {
get {
if Thread.isMainThread {
return registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
registerCoordinatorFlowCoordinatorForWindowTypeUnderlyingCallsCount = newValue
}
}
}
}
var registerCoordinatorFlowCoordinatorForWindowTypeCalled: Bool {
return registerCoordinatorFlowCoordinatorForWindowTypeCallsCount > 0
}
var registerCoordinatorFlowCoordinatorForWindowTypeReceivedArguments: (coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, type: WindowManagerWindowType)?
var registerCoordinatorFlowCoordinatorForWindowTypeReceivedInvocations: [(coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, type: WindowManagerWindowType)] = []
var registerCoordinatorFlowCoordinatorForWindowTypeClosure: ((CoordinatorProtocol, FlowCoordinatorProtocol?, WindowManagerWindowType) -> Void)?
func registerCoordinator(_ coordinator: CoordinatorProtocol, flowCoordinator: FlowCoordinatorProtocol?, forWindowType type: WindowManagerWindowType) {
registerCoordinatorFlowCoordinatorForWindowTypeCallsCount += 1
registerCoordinatorFlowCoordinatorForWindowTypeReceivedArguments = (coordinator: coordinator, flowCoordinator: flowCoordinator, type: type)
DispatchQueue.main.async {
self.registerCoordinatorFlowCoordinatorForWindowTypeReceivedInvocations.append((coordinator: coordinator, flowCoordinator: flowCoordinator, type: type))
}
registerCoordinatorFlowCoordinatorForWindowTypeClosure?(coordinator, flowCoordinator, type)
}
//MARK: - showGlobalSearch
var showGlobalSearchUnderlyingCallsCount = 0