88 lines
3.0 KiB
Swift
88 lines
3.0 KiB
Swift
import Foundation
|
|
import Shared
|
|
import UIKit
|
|
|
|
final class WindowScenesManager {
|
|
static let shared = WindowScenesManager()
|
|
private(set) var windowSizeObservers: [WindowSizeObserver] = []
|
|
|
|
func sceneDidBecomeActive(_ scene: UIWindowScene) {
|
|
guard scene.userActivity == nil else { return }
|
|
configureSceneSize(scene)
|
|
startObservingScene(scene)
|
|
}
|
|
|
|
func sceneWillResignActive(_ scene: UIScene) {
|
|
stopObservingScene(scene)
|
|
}
|
|
|
|
func didDiscardScene(_ scene: UIScene) {
|
|
stopObservingScene(scene)
|
|
}
|
|
|
|
private func startObservingScene(_ scene: UIWindowScene) {
|
|
let observer = WindowSizeObserver(windowScene: scene)
|
|
windowSizeObservers.append(observer)
|
|
}
|
|
|
|
private func stopObservingScene(_ scene: UIScene) {
|
|
windowSizeObservers.first { observer in
|
|
observer.observedScene == scene
|
|
}?.stopObserving()
|
|
windowSizeObservers.removeAll { $0.observedScene == scene }
|
|
}
|
|
|
|
private func sceneFrameIsValid(_ sceneFrame: CGRect, screenSize: CGSize) -> Bool {
|
|
sceneFrame.height <= screenSize.height && sceneFrame.width <= screenSize.width
|
|
}
|
|
|
|
// Create cascade effect so windows don't overlap
|
|
func adjustedSystemFrame(
|
|
_ systemFrame: CGRect,
|
|
for screenSize: CGSize,
|
|
numberOfConnectedScenes: Int
|
|
) -> CGRect {
|
|
guard numberOfConnectedScenes > 1 else { return systemFrame }
|
|
var adjustedFrame = systemFrame
|
|
|
|
// Inset from the already presented scene
|
|
// 29 is used by default by the system
|
|
adjustedFrame = adjustedFrame.offsetBy(dx: 29, dy: 29)
|
|
|
|
// Move to the top if we are out of the screen's bottom
|
|
if adjustedFrame.origin.y + adjustedFrame.height > screenSize.height - 80 {
|
|
adjustedFrame.origin.y = 80
|
|
}
|
|
|
|
// Move to left if we are out of the screen's right side
|
|
if adjustedFrame.origin.x + adjustedFrame.width > screenSize.width - 20 {
|
|
adjustedFrame.origin.x = 20
|
|
}
|
|
|
|
return adjustedFrame
|
|
}
|
|
|
|
private func configureSceneSize(_ scene: UIWindowScene) {
|
|
// Check is scene has a restoring state before proceeding
|
|
guard #available(macCatalyst 16.0, *),
|
|
let preferredSystemFrame = ScenesWindowSizeConfig.defaultSceneLatestSystemFrame,
|
|
preferredSystemFrame != .zero else { return }
|
|
|
|
let screenSize = scene.screen.bounds.size
|
|
guard sceneFrameIsValid(preferredSystemFrame, screenSize: screenSize) else { return }
|
|
|
|
let numberOfConnectedScenes = UIApplication.shared.connectedScenes.count
|
|
let adjustedSystemFrame = adjustedSystemFrame(
|
|
preferredSystemFrame,
|
|
for: screenSize,
|
|
numberOfConnectedScenes: numberOfConnectedScenes
|
|
)
|
|
|
|
#if targetEnvironment(macCatalyst)
|
|
scene.requestGeometryUpdate(.Mac(systemFrame: adjustedSystemFrame)) { error in
|
|
Current.Log.info(userInfo: ["Failed to request mac geometry": error.localizedDescription])
|
|
}
|
|
#endif
|
|
}
|
|
}
|