diff --git a/Sources/OpenSwiftUI/App/App/App.swift b/Sources/OpenSwiftUI/App/App/App.swift index 8d7b2b870..fa32e6036 100644 --- a/Sources/OpenSwiftUI/App/App/App.swift +++ b/Sources/OpenSwiftUI/App/App/App.swift @@ -6,6 +6,10 @@ // Status: Complete // ID: 20E520D074F8AF54E6253E3E22B86490 (SwiftUI) +import OpenSwiftUICore + +// MARK: - App + /// A type that represents the structure and behavior of an app. /// /// Create an app by declaring a structure that conforms to the `App` protocol. @@ -140,6 +144,25 @@ extension App { } } +// MARK: - AppRootModifier + +private var appRootViewWrappers: [(AnyView) -> AnyView] = [] + +@_spi(Private) +public func registerAppRootModifier(_ modifier: M) where M: ViewModifier { + appRootViewWrappers.append({ AnyView($0.modifier(modifier)) }) +} + +func applyAppRootModifier(_ view: AnyView) -> AnyView { + var result = view + for modifier in appRootViewWrappers { + result = modifier(result) + } + return result +} + +// MARK: - Platform implementation + #if os(iOS) || os(visionOS) import UIKit typealias DelegateBaseClass = UIResponder @@ -165,5 +188,3 @@ func runTestingApp(rootView: V1, comparisonView: V2, didLaunch: @escapin _openSwiftUIPlatformUnimplementedFailure() } #endif - -/*private*/ var appRootViewWrappers: [(AnyView) -> AnyView] = [] diff --git a/Sources/OpenSwiftUI/App/App/UIKit/UIKitAppDelegate.swift b/Sources/OpenSwiftUI/App/App/UIKit/UIKitAppDelegate.swift index dc9e4e14a..0a1bf74c6 100644 --- a/Sources/OpenSwiftUI/App/App/UIKit/UIKitAppDelegate.swift +++ b/Sources/OpenSwiftUI/App/App/UIKit/UIKitAppDelegate.swift @@ -7,7 +7,14 @@ // ID: 4475FD12FD59DEBA453321BD91F6EA04 (SwiftUI) #if os(iOS) || os(visionOS) -import UIKit +import OpenAttributeGraphShims +package import OpenSwiftUICore +public import UIKit +#if OPENSWIFTUI_OPENCOMBINE +import OpenCombine +#else +import Combine +#endif // MARK: - AppDelegate [TODO] @@ -136,45 +143,144 @@ class AppSceneDelegate: UIResponder, UIWindowSceneDelegate { super.init() } -// private var rootModifier: RootModifier { -// -// } -// -// private func makeRootView(_ view: AnyView) -> ModifiedContent { -// // for each appRootViewWrappers and then rootModifier -// } + private var rootModifier: RootModifier { + guard let sceneBridge else { + preconditionFailure("Application configuration error.") + } + guard let sceneStorageValues else { + preconditionFailure("State restoration error.") + } + return RootModifier( + sceneBridge: sceneBridge, + sceneDelegateBox: sceneDelegateBox, + sceneStorageValues: sceneStorageValues, + presentationDataValue: presentationDataValue, + scenePhase: scenePhase, + sceneID: sceneItemID + ) + } + + private func makeRootView(_ view: AnyView) -> ModifiedContent { + applyAppRootModifier(view).modifier(rootModifier) + } } -//struct SwiftUI.RootModifier { -// weak var sceneBridge: Swift.Optional -// weak var sceneDelegateBox: Swift.Optional -// weak var sceneStorageValues: Swift.Optional -// var presentationDataValue: Swift.Optional -// var scenePhase: SwiftUI.ScenePhase -// var sceneID: Swift.Optional -// var _rootFocusScope: SwiftUI.Namespace -//} -//struct SwiftUI.(SceneSessionKey in _4475FD12FD59DEBA453321BD91F6EA04) { -// /* Static Stored Variable */ -// static SwiftUI.(SceneSessionKey in _4475FD12FD59DEBA453321BD91F6EA04).defaultValue : Swift.Optional> -//} -//struct SwiftUI.(RootEnvironmentModifier in _4475FD12FD59DEBA453321BD91F6EA04) { -// weak var sceneBridge: Swift.Optional -// weak var sceneDelegateBox: Swift.Optional -// weak var sceneStorageValues: Swift.Optional -// var scenePhase: SwiftUI.ScenePhase -// var sceneID: Swift.Optional -//} -//struct SwiftUI.(RootEnvironmentModifier in _4475FD12FD59DEBA453321BD91F6EA04).Child { -// var _modifier: AttributeGraph.Attribute -// var _env: AttributeGraph.Attribute -// var oldModifier: Swift.Optional -// -// /* Function */ -// SwiftUI.(RootEnvironmentModifier in _4475FD12FD59DEBA453321BD91F6EA04).Child.updateValue() -> () -//} +// MARK: - RootModifier + +struct RootModifier: ViewModifier { + weak var sceneBridge: SceneBridge? + weak var sceneDelegateBox: AnyFallbackDelegateBox? + weak var sceneStorageValues: SceneStorageValues? + var presentationDataValue: AnyHashable? + var scenePhase: ScenePhase + var sceneID: SceneID? + @Namespace var rootFocusScope + + func body(content: Content) -> some View { + content + .rootEnvironment( + sceneBridge: sceneBridge, + sceneDelegateBox: sceneDelegateBox, + sceneStorageValues: sceneStorageValues, + scenePhase: scenePhase, + sceneID: sceneID + ) + .presentedSceneValue(presentationDataValue) + } +} + +// MARK: - EnvironmentValues + sceneSession + +private struct SceneSessionKey: EnvironmentKey { + static let defaultValue: WeakBox? = nil +} + +@_spi(Private) +@available(OpenSwiftUI_v2_0, *) +@available(macOS, unavailable) +@available(watchOS, unavailable) +extension EnvironmentValues { + public var sceneSession: UISceneSession? { + get { self[SceneSessionKey.self]?.base } + set { self[SceneSessionKey.self] = newValue.map(WeakBox.init) } + } +} + +// MARK: - RootEnvironmentModifier + +extension View { + func rootEnvironment( + sceneBridge: SceneBridge? = nil, + sceneDelegateBox: AnyFallbackDelegateBox? = nil, + sceneStorageValues: SceneStorageValues? = nil, + scenePhase: ScenePhase = .background, + sceneID: SceneID? = nil + ) -> some View { + modifier(RootEnvironmentModifier( + sceneBridge: sceneBridge, + sceneDelegateBox: sceneDelegateBox, + sceneStorageValues: sceneStorageValues, + scenePhase: scenePhase, + sceneID: sceneID + )) + } +} + +private struct RootEnvironmentModifier: PrimitiveViewModifier, _GraphInputsModifier { + weak var sceneBridge: SceneBridge? + weak var sceneDelegateBox: AnyFallbackDelegateBox? + weak var sceneStorageValues: SceneStorageValues? + var scenePhase: ScenePhase + var sceneID: SceneID? + + static func _makeInputs( + modifier: _GraphValue, + inputs: inout _GraphInputs + ) { + inputs.environment = Attribute( + Child( + modifier: modifier.value, + env: inputs.environment + ) + ) + } -// TODO -class SceneStorageValues {} + struct Child: StatefulRule { + @Attribute var modifier: RootEnvironmentModifier + @Attribute var env: EnvironmentValues + var oldModifier: RootEnvironmentModifier? + typealias Value = EnvironmentValues + + mutating func updateValue() { + let (modifier, modifierChanged) = $modifier.changedValue() + let (environment, environmentChanged) = $env.changedValue() + let shouldUpdate: Bool + if environmentChanged { + shouldUpdate = true + } else if modifierChanged && oldModifier.map({ compareValues($0, modifier) }) != false { + shouldUpdate = true + } else if !hasValue { + shouldUpdate = true + } else { + shouldUpdate = false + } + guard shouldUpdate else { + return + } + var result = environment + result[keyPath: SceneBridge.environmentStore] = modifier.sceneBridge + result.sceneStorageValues = modifier.sceneStorageValues + result.scenePhase = modifier.scenePhase + result.sceneID = modifier.sceneID + if modifier.scenePhase != .active { + result.redactionReasons.formUnion(.privacy) + } + modifier.sceneDelegateBox?.addDelegate(to: &result) + AppGraph.delegateBox?.addDelegate(to: &result) + value = result + oldModifier = modifier + } + } +} #endif diff --git a/Sources/OpenSwiftUI/App/Scene/ScenePhase.swift b/Sources/OpenSwiftUI/App/Scene/ScenePhase.swift index 3864cf188..e7bbf6c58 100644 --- a/Sources/OpenSwiftUI/App/Scene/ScenePhase.swift +++ b/Sources/OpenSwiftUI/App/Scene/ScenePhase.swift @@ -6,6 +6,8 @@ // Status: Complete // ID: 130BB08D98602D712FD59CAC6992C14A (SwiftUI) +// MARK: - ScenePhase + /// An indication of a scene's operational state. /// /// The system moves your app's ``Scene`` instances through phases that reflect @@ -96,6 +98,8 @@ public enum ScenePhase: Comparable { case active } +// MARK: - EnvironmentValues + scenePhase + private struct ScenePhaseKey: EnvironmentKey { static let defaultValue: ScenePhase = .background } diff --git a/Sources/OpenSwiftUI/App/Scene/SceneStorage.swift b/Sources/OpenSwiftUI/App/Scene/SceneStorage.swift new file mode 100644 index 000000000..048aea65b --- /dev/null +++ b/Sources/OpenSwiftUI/App/Scene/SceneStorage.swift @@ -0,0 +1,26 @@ +// +// SceneStorage.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: TODO +// ID: 1700ED20D4EA891B02973E899ABDB425 (SwiftUI) + +import OpenSwiftUICore + +// MARK: - SceneStorageValues [WIP] + +class SceneStorageValues {} + +// MARK: - EnvironmentValues + sceneStorageValues + +private struct SceneStorageValuesKey: EnvironmentKey { + static let defaultValue: WeakBox? = nil +} + +extension EnvironmentValues { + var sceneStorageValues: SceneStorageValues? { + get { self[SceneStorageValuesKey.self]?.base } + set { self[SceneStorageValuesKey.self] = newValue.map(WeakBox.init) } + } +} diff --git a/Sources/OpenSwiftUI/Modifier/ViewModifier/PresentedSceneValueInputModifier.swift b/Sources/OpenSwiftUI/Modifier/ViewModifier/PresentedSceneValueInputModifier.swift new file mode 100644 index 000000000..4ff0c57ca --- /dev/null +++ b/Sources/OpenSwiftUI/Modifier/ViewModifier/PresentedSceneValueInputModifier.swift @@ -0,0 +1,44 @@ +// +// PresentedSceneValueInputModifier.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: TODO +// ID: 16926B370582AC5E886A9B0FCFCEA0ED (SwiftUI?) + +import OpenAttributeGraphShims +import OpenSwiftUICore + +extension WindowGroup { + // TODO +} + +// TODO +public struct PresentedWindowContent {} + +// MARK: - PresentedSceneValueInput + +private struct PresentedSceneValueInput: ViewInput { + static var defaultValue: OptionalAttribute { .init() } +} + +// MARK: - PresentedSceneValueInputModifier + +extension View { + func presentedSceneValue( + _ value: AnyHashable? + ) -> some View { + modifier(PresentedSceneValueInputModifier(presentedValue: value)) + } +} + +private struct PresentedSceneValueInputModifier: ViewInputsModifier { + var presentedValue: AnyHashable? + + static func _makeViewInputs( + modifier: _GraphValue, + inputs: inout _ViewInputs + ) { + inputs[PresentedSceneValueInput.self] = .init(modifier.value.presentedValue) + } +}