From b0bc6bc6eeb7d038282fb6cbc2ce0540c2a49b3b Mon Sep 17 00:00:00 2001 From: ra1028 Date: Thu, 16 May 2024 17:55:18 +0900 Subject: [PATCH] Refactoring --- .../PlaybookExample.xcodeproj/project.pbxproj | 24 ++++------ Example/SampleApp/AppDelegate.swift | 8 ---- Example/SampleApp/SampleApp.swift | 12 +++++ Example/SampleApp/SceneDelegate.swift | 16 ------- Example/SamplePlaybook/AppDelegate.swift | 13 ------ .../SamplePlaybook/SamplePlaybookApp.swift | 37 +++++++++++++++ Example/SamplePlaybook/SceneDelegate.swift | 45 ------------------- Example/SampleSnapshot/SnapshotTests.swift | 10 ++++- Tests/SnapshotTests.swift | 10 ++++- 9 files changed, 75 insertions(+), 100 deletions(-) delete mode 100644 Example/SampleApp/AppDelegate.swift create mode 100644 Example/SampleApp/SampleApp.swift delete mode 100644 Example/SampleApp/SceneDelegate.swift delete mode 100644 Example/SamplePlaybook/AppDelegate.swift create mode 100644 Example/SamplePlaybook/SamplePlaybookApp.swift delete mode 100644 Example/SamplePlaybook/SceneDelegate.swift diff --git a/Example/PlaybookExample.xcodeproj/project.pbxproj b/Example/PlaybookExample.xcodeproj/project.pbxproj index 31242bb..ccd30cb 100644 --- a/Example/PlaybookExample.xcodeproj/project.pbxproj +++ b/Example/PlaybookExample.xcodeproj/project.pbxproj @@ -25,13 +25,10 @@ 33A29BC1583DA6CE1EDD2594 /* SampleComponent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 802EE057DE943B8FD99F7159 /* SampleComponent.framework */; }; 343FF44603432D918D8010DF /* chincoteague.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F5340487504EF97878690618 /* chincoteague.jpg */; }; 39BA1BC86174B2510BCF468B /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9BCBC75F3CDA58F556FFD4F6 /* LICENSE.txt */; }; - 422B2E8BBE8F5E846E5BED22 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 205F01EE8189B8061B86AFE6 /* SceneDelegate.swift */; }; - 4A36F69B4A2D71EE48F035ED /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CCF6C39F07F560470DB160 /* SceneDelegate.swift */; }; 4C4E8DE7B7BD2D664D3EF142 /* HikeGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2009D3129A8AE87CC9C487 /* HikeGraph.swift */; }; 53076BBA69A2F07A31DEF069 /* ProfileSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4261FFCE72EA7177DD8AAB04 /* ProfileSummary.swift */; }; 5AA1FDE26E5A92BD3279285B /* PlaybookSnapshot.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F7E213C737B9841E563D7E2A /* PlaybookSnapshot.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 6AF458958D42E48FC67E4139 /* Home.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE02FE9D07ABA0A8E18AA5F /* Home.swift */; }; - 6E3A8440E87F5F1AA429E221 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 931EB6CF426817D6DA7DC87A /* AppDelegate.swift */; }; 755C557D941D16F1A5866019 /* stmarylake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E7980DB51A1EB6129121C5D6 /* stmarylake.jpg */; }; 789D10062010CF2025E7CCD9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 17BBF319282057CB0EDF5771 /* Preview Assets.xcassets */; }; 7C7DC8A8ED8B023DF230784A /* Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21C5FED0D815648EB02D6C75 /* Stubs.swift */; }; @@ -39,7 +36,6 @@ 7EA3709C5E6CB95FF44B94C2 /* HikeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 484534BAAFC74B2B8E662666 /* HikeView.swift */; }; 830C2CEB3646863325B61A22 /* charleyrivers.jpg in Resources */ = {isa = PBXBuildFile; fileRef = FDC78245A1D82930D4681993 /* charleyrivers.jpg */; }; 8541D69B45364B394EA96EB0 /* icybay.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7B580B6526E763D4EF39BCA3 /* icybay.jpg */; }; - 8A20BC3C4CA21E04018975F8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2EF24DF841DE1AF0D13E9C /* AppDelegate.swift */; }; 8E2FB4D2C7A1222EDFFAB73E /* PlaybookSnapshot.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7E213C737B9841E563D7E2A /* PlaybookSnapshot.framework */; }; 8F5CC609A5E91A2A7CE37C1F /* Landmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB791DC91AC218875BEC261B /* Landmark.swift */; }; 95225FB354D6B0D7F08C5B97 /* silversalmoncreek.jpg in Resources */ = {isa = PBXBuildFile; fileRef = C191D6BDDA8CC5E91BD3D2E2 /* silversalmoncreek.jpg */; }; @@ -60,7 +56,9 @@ CC3C9380122ED1D16DF026F8 /* rainbowlake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2496A95B98D6099F1FB173CD /* rainbowlake.jpg */; }; CF50C9E3A7EAC7EF06DC45C6 /* ProfileHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69803A7B28BE35CF63EB7D29 /* ProfileHost.swift */; }; CF9EB7737B7614C3C50C1AE3 /* GraphCapsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EDFD424C343AC301DB0F234 /* GraphCapsule.swift */; }; + D463E72F10A847CBFCDAB091 /* SampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7C1FC6F257946E415AEEBF5 /* SampleApp.swift */; }; D5D7843B0C4D8283D6C9FE0C /* twinlake.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 3CC78902D970A9EC960165D6 /* twinlake.jpg */; }; + D9B02818BC60E3FA87BC3786 /* SamplePlaybookApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72EAF4F711E12ABE5A35679C /* SamplePlaybookApp.swift */; }; E09DD48E3FF59F49BFE27F9E /* PlaybookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA18B8BA6AA03488B078FEDF /* PlaybookUI.framework */; }; E0B46F41D197DD8A964865A2 /* LandmarkList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D1383BDBC69288B92C18310 /* LandmarkList.swift */; }; E6F911A5AE8805A9049A3D80 /* SnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54634E63D9F598E50BFEE94E /* SnapshotTests.swift */; }; @@ -182,7 +180,6 @@ /* Begin PBXFileReference section */ 0143289ABDCF133AE1FE6FBF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 17BBF319282057CB0EDF5771 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 205F01EE8189B8061B86AFE6 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 21C5FED0D815648EB02D6C75 /* Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stubs.swift; sourceTree = ""; }; 2496A95B98D6099F1FB173CD /* rainbowlake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = rainbowlake.jpg; sourceTree = ""; }; 2F47ACD6FB441ECE829B1C68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; @@ -199,13 +196,12 @@ 54634E63D9F598E50BFEE94E /* SnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTests.swift; sourceTree = ""; }; 54A62FB73D841AF632775CDB /* chilkoottrail.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = chilkoottrail.jpg; sourceTree = ""; }; 5AE02FE9D07ABA0A8E18AA5F /* Home.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Home.swift; sourceTree = ""; }; - 5B2EF24DF841DE1AF0D13E9C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 5D1383BDBC69288B92C18310 /* LandmarkList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandmarkList.swift; sourceTree = ""; }; 5D4607676B6D47E4F88EE157 /* AllScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllScenarios.swift; sourceTree = ""; }; 69803A7B28BE35CF63EB7D29 /* ProfileHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHost.swift; sourceTree = ""; }; 6B22197BF1CB4F213B1A0A74 /* LandmarkRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandmarkRow.swift; sourceTree = ""; }; 6EDFD424C343AC301DB0F234 /* GraphCapsule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphCapsule.swift; sourceTree = ""; }; - 78CCF6C39F07F560470DB160 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 72EAF4F711E12ABE5A35679C /* SamplePlaybookApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SamplePlaybookApp.swift; sourceTree = ""; }; 7B580B6526E763D4EF39BCA3 /* icybay.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = icybay.jpg; sourceTree = ""; }; 7D1DB2006C4C3195D49D9B27 /* Playbook */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Playbook; path = ../Playbook.xcodeproj; sourceTree = ""; }; 7D311553C1081C70DEE41E21 /* BadgeSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeSymbol.swift; sourceTree = ""; }; @@ -213,7 +209,6 @@ 802EE057DE943B8FD99F7159 /* SampleComponent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SampleComponent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 86B3BE160CAA6EA63D0EE41C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 889E33DF654D7927431CE42B /* ProfilesScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilesScenarios.swift; sourceTree = ""; }; - 931EB6CF426817D6DA7DC87A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 932B441579D6EF86C49A5568 /* hiddenlake.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = hiddenlake.jpg; sourceTree = ""; }; 9BCBC75F3CDA58F556FFD4F6 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 9FD58DD89E0885F4B031832B /* SupportingViewsScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportingViewsScenarios.swift; sourceTree = ""; }; @@ -225,6 +220,7 @@ B1C9731D0286CD995E40C994 /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = ""; }; B4447572897C5E2490BE2766 /* ProfileEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditor.swift; sourceTree = ""; }; B733775B65E98E7837F3D253 /* turtlerock.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = turtlerock.jpg; sourceTree = ""; }; + B7C1FC6F257946E415AEEBF5 /* SampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleApp.swift; sourceTree = ""; }; BF570FCA8F1BAD787DBF2478 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; C09BDB1DA55B761350F6CCD6 /* hikeData.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = hikeData.json; sourceTree = ""; }; C191D6BDDA8CC5E91BD3D2E2 /* silversalmoncreek.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = silversalmoncreek.jpg; sourceTree = ""; }; @@ -360,11 +356,10 @@ 5F827EEB63647EAD64D384BD /* SamplePlaybook */ = { isa = PBXGroup; children = ( - 931EB6CF426817D6DA7DC87A /* AppDelegate.swift */, CD1E2464BE1A9847D81EA9E0 /* Assets.xcassets */, 2F47ACD6FB441ECE829B1C68 /* Info.plist */, 7EFDE9E4395F888AFC93E883 /* LaunchScreen.storyboard */, - 205F01EE8189B8061B86AFE6 /* SceneDelegate.swift */, + 72EAF4F711E12ABE5A35679C /* SamplePlaybookApp.swift */, 21C5FED0D815648EB02D6C75 /* Stubs.swift */, 4456CE868E6FD7B688FCC0A5 /* Preview Content */, CD062903B73FDEEE91F50B59 /* Scenarios */, @@ -397,11 +392,10 @@ B9A55EDF9D853A1F58106480 /* SampleApp */ = { isa = PBXGroup; children = ( - 5B2EF24DF841DE1AF0D13E9C /* AppDelegate.swift */, AE57203A490F0D29D50C0BF3 /* Assets.xcassets */, BF570FCA8F1BAD787DBF2478 /* Info.plist */, D6FCA2C4E87CF627BD99290A /* LaunchScreen.storyboard */, - 78CCF6C39F07F560470DB160 /* SceneDelegate.swift */, + B7C1FC6F257946E415AEEBF5 /* SampleApp.swift */, 1E1C8AE035F9FE2E6E6CFE13 /* Preview Content */, ); path = SampleApp; @@ -672,10 +666,9 @@ buildActionMask = 2147483647; files = ( ECB94EEC9015DA35DF840C85 /* AllScenarios.swift in Sources */, - 6E3A8440E87F5F1AA429E221 /* AppDelegate.swift in Sources */, 0C1124533ABE0565B314A44F /* HomeScenarios.swift in Sources */, 2BC2750C9D283AD4EA17CC2E /* ProfilesScenarios.swift in Sources */, - 422B2E8BBE8F5E846E5BED22 /* SceneDelegate.swift in Sources */, + D9B02818BC60E3FA87BC3786 /* SamplePlaybookApp.swift in Sources */, 7C7DC8A8ED8B023DF230784A /* Stubs.swift in Sources */, ACA84D231A0FE3C398D866EA /* SupportingViewsScenarios.swift in Sources */, ); @@ -685,8 +678,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8A20BC3C4CA21E04018975F8 /* AppDelegate.swift in Sources */, - 4A36F69B4A2D71EE48F035ED /* SceneDelegate.swift in Sources */, + D463E72F10A847CBFCDAB091 /* SampleApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/SampleApp/AppDelegate.swift b/Example/SampleApp/AppDelegate.swift deleted file mode 100644 index 2e3eb4b..0000000 --- a/Example/SampleApp/AppDelegate.swift +++ /dev/null @@ -1,8 +0,0 @@ -import UIKit - -@UIApplicationMain -final class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } -} diff --git a/Example/SampleApp/SampleApp.swift b/Example/SampleApp/SampleApp.swift new file mode 100644 index 0000000..9f1f08e --- /dev/null +++ b/Example/SampleApp/SampleApp.swift @@ -0,0 +1,12 @@ +import SwiftUI +import SampleComponent + +@main +struct SampleApp: App { + var body: some Scene { + WindowGroup { + CategoryHome() + .environmentObject(UserData()) + } + } +} diff --git a/Example/SampleApp/SceneDelegate.swift b/Example/SampleApp/SceneDelegate.swift deleted file mode 100644 index 665bf3b..0000000 --- a/Example/SampleApp/SceneDelegate.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI -import SampleComponent - -final class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - if let windowScene = scene as? UIWindowScene { - let window = UIWindow(windowScene: windowScene) - let rootView = CategoryHome().environmentObject(UserData()) - window.rootViewController = UIHostingController(rootView: rootView) - self.window = window - window.makeKeyAndVisible() - } - } -} diff --git a/Example/SamplePlaybook/AppDelegate.swift b/Example/SamplePlaybook/AppDelegate.swift deleted file mode 100644 index b404890..0000000 --- a/Example/SamplePlaybook/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Playbook -import UIKit - -@UIApplicationMain -final class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } -} diff --git a/Example/SamplePlaybook/SamplePlaybookApp.swift b/Example/SamplePlaybook/SamplePlaybookApp.swift new file mode 100644 index 0000000..ed6bd2d --- /dev/null +++ b/Example/SamplePlaybook/SamplePlaybookApp.swift @@ -0,0 +1,37 @@ +import PlaybookUI +import SwiftUI + +@main +struct SamplePlaybookApp: App { + enum Tab { + case catalog + case gallery + } + + @State + var tab = Tab.gallery + + init() { + Playbook.default.add(AllScenarios.self) + } + + var body: some Scene { + WindowGroup { + TabView(selection: $tab) { + PlaybookGallery() + .tag(Tab.gallery) + .tabItem { + Image(systemName: "rectangle.grid.3x2") + Text("Gallery") + } + + PlaybookCatalog() + .tag(Tab.catalog) + .tabItem { + Image(systemName: "doc.text.magnifyingglass") + Text("Catalog") + } + } + } + } +} diff --git a/Example/SamplePlaybook/SceneDelegate.swift b/Example/SamplePlaybook/SceneDelegate.swift deleted file mode 100644 index a9b943d..0000000 --- a/Example/SamplePlaybook/SceneDelegate.swift +++ /dev/null @@ -1,45 +0,0 @@ -import PlaybookUI -import SwiftUI - -struct PlaybookView: View { - enum Tab { - case catalog - case gallery - } - - @State - var tab = Tab.gallery - - var body: some View { - TabView(selection: $tab) { - PlaybookGallery() - .tag(Tab.gallery) - .tabItem { - Image(systemName: "rectangle.grid.3x2") - Text("Gallery") - } - - PlaybookCatalog() - .tag(Tab.catalog) - .tabItem { - Image(systemName: "doc.text.magnifyingglass") - Text("Catalog") - } - } - } -} - -final class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = scene as? UIWindowScene else { return } - Playbook.default.add(AllScenarios.self) - - let window = UIWindow(windowScene: windowScene) - window.rootViewController = UIHostingController(rootView: PlaybookView()) - - self.window = window - window.makeKeyAndVisible() - } -} diff --git a/Example/SampleSnapshot/SnapshotTests.swift b/Example/SampleSnapshot/SnapshotTests.swift index 76f6c49..4187fed 100644 --- a/Example/SampleSnapshot/SnapshotTests.swift +++ b/Example/SampleSnapshot/SnapshotTests.swift @@ -13,9 +13,17 @@ final class SnapshotTests: XCTestCase { clean: true, format: .png, scale: 1, - keyWindow: UIApplication.shared.windows.first { $0.isKeyWindow }, + keyWindow: getKeyWindow(), devices: [.iPhone11Pro(.portrait)] ) ) } + + func getKeyWindow() -> UIWindow? { + UIApplication.shared.connectedScenes + .lazy + .compactMap { $0 as? UIWindowScene } + .flatMap(\.windows) + .first(where: \.isKeyWindow) + } } diff --git a/Tests/SnapshotTests.swift b/Tests/SnapshotTests.swift index 1114c9b..15b75d7 100644 --- a/Tests/SnapshotTests.swift +++ b/Tests/SnapshotTests.swift @@ -15,7 +15,7 @@ final class SnapshotTests: XCTestCase { clean: true, format: .png, scale: 1, - keyWindow: UIApplication.shared.windows.first { $0.isKeyWindow }, + keyWindow: getKeyWindow(), devices: [ .iPhone11Pro(.portrait), .iPhone11Pro(.landscape).style(.dark), @@ -29,4 +29,12 @@ final class SnapshotTests: XCTestCase { ) ) } + + func getKeyWindow() -> UIWindow? { + UIApplication.shared.connectedScenes + .lazy + .compactMap { $0 as? UIWindowScene } + .flatMap(\.windows) + .first(where: \.isKeyWindow) + } }