Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Sources/OpenSwiftUI/App/App/FinishLaunchTestAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Blocked by SceneModifier
// Status: Complete
// ID: 71E21E30634D2453CAA80C5CA9EF3E2C (SwiftUI?)

#if os(iOS) || os(visionOS)
Expand All @@ -23,8 +23,10 @@ import OpenSwiftUICore
@available(OpenSwiftUI_v3_0, *)
extension Scene {
nonisolated public func extendedLaunchTestName(_ name: String?) -> some Scene {
// TODO: _PreferenceWritingModifier
self
preference(
key: ExtendedLaunchTestNameKey.self,
value: name
)
}
}

Expand Down
33 changes: 26 additions & 7 deletions Sources/OpenSwiftUI/App/Commands/Commands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Blocked by MainMenuItem and Scene
// Status: Complete - Blocked by MainMenuItem
// ID: 0E12E75FDDFA412408873260803B3C8B (SwiftUI)

import OpenAttributeGraphShims
import COpenSwiftUI
@_spi(ForOpenSwiftUIOnly)
@_spi(Private)
public import OpenSwiftUICore

Expand Down Expand Up @@ -180,7 +181,7 @@ public struct _ResolvedCommands {
@available(*, unavailable)
extension _ResolvedCommands: Sendable {}

// MARK: - Scene + commands [WIP]
// MARK: - Scene + commands

@available(OpenSwiftUI_v2_0, *)
@available(tvOS, unavailable)
Expand All @@ -201,9 +202,7 @@ extension Scene {
nonisolated public func commands<Content>(
@CommandsBuilder content: () -> Content
) -> some Scene where Content: Commands {
// CommandModifier
_openSwiftUIUnimplementedWarning()
return self
modifier(CommandsModifier(content: content()))
}
}

Expand Down Expand Up @@ -266,7 +265,7 @@ extension TypeConformance where P == CommandsDescriptor {
}
}

// MARK: - CommandsModifier [WIP]
// MARK: - CommandsModifier

struct CommandsModifier<Content>: PrimitiveSceneModifier where Content: Commands {
var content: Content
Expand All @@ -276,7 +275,27 @@ struct CommandsModifier<Content>: PrimitiveSceneModifier where Content: Commands
inputs: _SceneInputs,
body: @escaping (_Graph, _SceneInputs) -> _SceneOutputs
) -> _SceneOutputs {
_openSwiftUIUnimplementedFailure()
guard inputs.preferences.requiresSceneList else {
return body(_Graph(), inputs)
}
var commandsInputs = _CommandsInputs(
base: inputs.base,
preferences: .init(hostKeys: inputs.preferences.hostKeys)
)
commandsInputs.preferences.add(CommandsList.Key.self)
var commandsOutputs = Content._makeCommands(
content: .init(modifier.value.content),
inputs: commandsInputs
)
var outputs = body(_Graph(), inputs)
if let commandsList = outputs.preferences.commandsList {
outputs.preferences.makePreferenceTransformer(
inputs: commandsInputs.preferences,
key: CommandsList.Key.self,
transform: Attribute(UpdateList(list: commandsList))
)
}
return outputs
}

private struct UpdateList: Rule {
Expand Down
7 changes: 3 additions & 4 deletions Sources/OpenSwiftUI/App/Commands/CommandsFlags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,13 @@ struct WithCommandFlag<Content>: PrimitiveCommands where Content: Commands {
content: content[offset: { .of(&$0.content) }],
inputs: inputs
)
if inputs.preferences.contains(CommandsList.Key.self) {
let setFlag = Attribute(
if inputs.preferences.requiresCommandsList {
outputs.preferences.commandsList = Attribute(
SetFlag(
container: content.value,
list: .init(outputs.preferences[CommandsList.Key.self]),
list: .init(outputs.preferences.commandsList),
)
)
outputs.preferences[CommandsList.Key.self] = setFlag
}
return outputs
}
Expand Down
24 changes: 24 additions & 0 deletions Sources/OpenSwiftUI/App/Commands/CommandsList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Audited for 6.5.4
// Status: Complete

import OpenAttributeGraphShims

// MARK: - CommandsList

struct CommandsList: Hashable {
Expand Down Expand Up @@ -68,3 +70,25 @@ extension CommandsList {
}
}
}

extension PreferencesInputs {
@inline(__always)
var requiresCommandsList: Bool {
get { contains(CommandsList.Key.self) }
set {
if newValue {
add(CommandsList.Key.self)
} else {
remove(CommandsList.Key.self)
}
}
}
}

extension PreferencesOutputs {
@inline(__always)
var commandsList: Attribute<CommandsList>? {
get { self[CommandsList.Key.self] }
set { self[CommandsList.Key.self] = newValue }
}
}
5 changes: 4 additions & 1 deletion Sources/OpenSwiftUI/App/Scene/SceneList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ extension SceneList {
case settings(AnyView)
// case menuBarExtra(MenuBarExtraConfiguration)
// case customScene(UISceneAdaptorConfiguration)
// case singleWindow(SingleWindowConfiguration)
case singleWindow(SingleWindowConfiguration)
// case documentIntroduction(DocumentIntroductionConfiguration)
// case alertDialog(DialogConfiguration)
}
Expand Down Expand Up @@ -136,3 +136,6 @@ extension PreferencesOutputs {
set { self[SceneList.Key.self] = newValue }
}
}

// TODO
struct SingleWindowConfiguration {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// AppearanceActionSceneModifier.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete

import OpenAttributeGraphShims
package import OpenSwiftUICore

@available(OpenSwiftUI_v4_0, *)
extension _AppearanceActionModifier: PrimitiveSceneModifier {
@MainActor
@preconcurrency
public static func _makeScene(
modifier: _GraphValue<_AppearanceActionModifier>,
inputs: _SceneInputs,
body: @escaping (_Graph, _SceneInputs) -> _SceneOutputs
) -> _SceneOutputs {
let effect = AppearanceEffect(
modifier: modifier.value,
phase: inputs.base.phase
)
let attribute = Attribute(effect)
attribute.flags = [.transactional, .removable]
return body(_Graph(), inputs)
}
}

@_spi(Private)
@available(OpenSwiftUI_v4_0, *)
extension Scene {
@_alwaysEmitIntoClient
nonisolated public func onAppear(perform action: (() -> Void)? = nil) -> some Scene {
modifier(_AppearanceActionModifier(appear: action, disappear: nil))
}

@_alwaysEmitIntoClient
nonisolated public func onDisappear(perform action: (() -> Void)? = nil) -> some Scene {
modifier(_AppearanceActionModifier(appear: nil, disappear: action))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// EnvironmentSceneModifier.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete

@available(OpenSwiftUI_v2_0, *)
extension _EnvironmentKeyWritingModifier: PrimitiveSceneModifier {}

extension Scene {

/// Sets the environment value of the specified key path to the given value.
///
/// Use this modifier to set one of the writable properties of the
/// ``EnvironmentValues`` structure, including custom values that you
/// create. For example, you can create a custom environment key
/// `styleOverrides` to set a value that represents style settings that for
/// the entire app:
///
/// WindowGroup {
/// ContentView()
/// }
/// .environment(\.styleOverrides, StyleOverrides())
///
/// You then read the value inside `ContentView` or one of its descendants
/// using the ``Environment`` property wrapper:
///
/// struct MyView: View {
/// @Environment(\.styleOverrides) var styleOverrides: StyleOverrides
///
/// var body: some View { ... }
/// }
///
/// This modifier affects the given scene,
/// as well as that scene's descendant views. It has no effect
/// outside the view hierarchy on which you call it.
///
/// - Parameters:
/// - keyPath: A key path that indicates the property of the
/// ``EnvironmentValues`` structure to update.
/// - value: The new value to set for the item specified by `keyPath`.
///
/// - Returns: A view that has the given value set in its environment.
@available(OpenSwiftUI_v2_0, *)
@_alwaysEmitIntoClient
nonisolated public func environment<V>(_ keyPath: WritableKeyPath<EnvironmentValues, V>, _ value: V) -> some Scene {
modifier(_EnvironmentKeyWritingModifier(keyPath: keyPath, value: value))
}
}

@available(OpenSwiftUI_v5_0, *)
extension _EnvironmentKeyTransformModifier: PrimitiveSceneModifier {}

@available(OpenSwiftUI_v5_0, *)
extension Scene {

/// Transforms the environment value of the specified key path with the
/// given function.
nonisolated public func transformEnvironment<V>(
_ keyPath: WritableKeyPath<EnvironmentValues, V>,
transform: @escaping (inout V) -> Void
) -> some Scene {
modifier(_EnvironmentKeyTransformModifier(keyPath: keyPath, transform: transform))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// EnvironmentWritingModifier.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete
// ID: 327A94017466EC589024364A56314D10 (SwiftUI)

import OpenAttributeGraphShims
import OpenSwiftUICore

// MARK: - Scene + environment

extension Scene {
@_spi(Private)
@available(OpenSwiftUI_v5_0, *)
nonisolated public func environment<K>(
key: K.Type = K.self,
value: K.Value
) -> some Scene where K: EnvironmentKey {
modifier(EnvironmentWritingSceneModifier<K>(value: value))
}
}

// MARK: - EnvironmentWritingModifier

private protocol EnvironmentWritingModifier: _GraphInputsModifier {
associatedtype Key: EnvironmentKey

var value: Key.Value { get }
}

// MARK: - EnvironmentWritingSceneModifier

struct EnvironmentWritingSceneModifier<Key>: PrimitiveSceneModifier, EnvironmentWritingModifier where Key: EnvironmentKey {
var value: Key.Value

static func _makeInputs(
modifier: _GraphValue<Self>,
inputs: inout _GraphInputs
) {
inputs.environment = Attribute(
ChildEnvironment(
modifier: modifier.value,
environment: inputs.environment,
)
)
}
}

// MARK: - ChildEnvironment

private struct ChildEnvironment<Modifier>: StatefulRule, AsyncAttribute, CustomStringConvertible where Modifier: EnvironmentWritingModifier {
@Attribute var modifier: Modifier
@Attribute var environment: EnvironmentValues
var oldModifier: Modifier?

init(
modifier: Attribute<Modifier>,
environment: Attribute<EnvironmentValues>,
oldModifier: Modifier? = nil
) {
self._modifier = modifier
self._environment = environment
self.oldModifier = oldModifier
}

var description: String {
"EnvironmentWriting: \(Modifier.self)"
}

typealias Value = EnvironmentValues

mutating func updateValue() {
let (modifier, modifierChanged) = $modifier.changedValue()
let (environment, environmentChanged) = $environment.changedValue()
var modifierNeedsUpdate: Bool {
guard modifierChanged else {
return false
}
if let oldModifier {
return compareValues(oldModifier.value, modifier.value)
} else {
return true
}
}
if environmentChanged || !hasValue || modifierNeedsUpdate {
var env = environment
env[Modifier.Key.self] = modifier.value
value = env
oldModifier = modifier
}
}
}
Loading
Loading