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
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//
// PlatformItemsReader.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete
// ID: 2D2DE8D65225CC97305A8AAD72170302 (SwiftUI)

import OpenAttributeGraphShims
@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore

// MARK: - PlatformItemsReader

struct PlatformItemsReader<Strategy, Content, Source>: PrimitiveView, UnaryView
where Strategy: PlatformItemsStrategy, Content: View, Source: View {
var content: (Strategy.Content) -> Content
var source: ZStack<Source>

init(
for strategy: Strategy,
@ViewBuilder content: @escaping (Strategy.Content) -> Content,
@ViewBuilder source: () -> Source
) {
self.content = content
self.source = ZStack(content: source)
}

static func _makeView(view: _GraphValue<Self>, inputs: _ViewInputs) -> _ViewOutputs {
let source = view[offset: { .of(&$0.source) }]
let hostKeys = inputs.intern(PreferenceKeys(), id: .defaultValue)
var sourceInputs = inputs.withoutGeometryDependencies
sourceInputs.preferences = PreferencesInputs(hostKeys: hostKeys)
Strategy.makeInputs(&sourceInputs)
let outputs = ZStack<Source>.makeDebuggableView(
view: source,
inputs: sourceInputs
)
let child = Child(
content: Strategy.makeContent(from: outputs),
viewContent: view.value[offset: { .of(&$0.content) }],
oldContent: Strategy.defaultValue
)
return Content.makeDebuggableView(view: _GraphValue(child), inputs: inputs)
}

private struct Child: StatefulRule {
@OptionalAttribute var content: Strategy.Content?
@Attribute var viewContent: (Strategy.Content) -> Content
var oldContent: Strategy.Content

typealias Value = Content

init(
content: OptionalAttribute<Strategy.Content>,
viewContent: Attribute<(Strategy.Content) -> Content>,
oldContent: Strategy.Content
) {
self._content = content
self._viewContent = viewContent
self.oldContent = oldContent
}

mutating func updateValue() {
let (viewContent, viewChanged) = $viewContent.changedValue()
let (content, contentChanged) = $content?.changedValue() ?? (Strategy.defaultValue, false)
defer { oldContent = content }
let changed = Strategy.hasChanges(from: oldContent, to: content)
guard !hasValue || (contentChanged && changed) || viewChanged else {
return
}
value = withObservation {
viewContent(content)
}
}
}
}

// MARK: - PlatformItemTraitWriter

struct PlatformItemTraitWriter<Strategy, Source, Trait>: PrimitiveViewModifier
where Strategy: UnaryPlatformItemsStrategy, Source: View,
Trait: _ViewTraitKey, Trait.Value == PlatformItem {
var source: Source

nonisolated static func _makeView(
modifier: _GraphValue<Self>,
inputs: _ViewInputs,
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
) -> _ViewOutputs {
body(_Graph(), inputs)
}

nonisolated static func _makeViewList(
modifier: _GraphValue<Self>,
inputs: _ViewListInputs,
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
) -> _ViewListOutputs {
var childInputs = inputs
var sourceInputs = inputs.withoutGeometryDependencies
Strategy.makeInputs(&sourceInputs)
let source = modifier[offset: { .of(&$0.source) }]
let outputs = Source._makeView(
view: source,
inputs: sourceInputs
)
let addTrait = AddTrait(
content: .init(outputs.platformItem),
traits: .init(inputs.traits),
oldContent: Strategy.defaultValue
)
childInputs.traits = Attribute(addTrait)
childInputs.addTraitKey(Trait.self)
return body(_Graph(), childInputs)
}

private struct AddTrait: StatefulRule, AsyncAttribute {
@OptionalAttribute var content: PlatformItem?
@OptionalAttribute var traits: ViewTraitCollection?
var oldContent: PlatformItem

typealias Value = ViewTraitCollection

mutating func updateValue() {
let (content, contentChanged) = $content?.changedValue() ?? (Strategy.defaultValue, false)
let (incomingTraits, traitsChanged) = $traits?.changedValue() ?? (ViewTraitCollection(), false)
defer { oldContent = content }
let changed = Strategy.hasChanges(from: oldContent, to: content)
guard !hasValue || (contentChanged && changed) || traitsChanged else {
return
}
var traits = incomingTraits
traits[Trait.self] = content
value = traits
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: WIP
// Status: Complete

import OpenAttributeGraphShims
import OpenSwiftUICore
Expand All @@ -21,3 +21,96 @@ protocol PlatformItemsStrategy {
static func makeInputs(_ inputs: inout _ViewInputs)
static func makeContent(from outputs: _ViewOutputs) -> OptionalAttribute<Content>
}

// MARK: - MultiPlatformItemsStrategy

protocol MultiPlatformItemsStrategy: PlatformItemsStrategy where Content == PlatformItems {}

extension MultiPlatformItemsStrategy {
static var defaultValue: PlatformItems { .init(features: itemsFeatures) }

static var itemsFeatures: PlatformItems.Features { .multiple }

static func hasChanges(from oldContent: PlatformItems, to newContent: PlatformItems) -> Bool {
oldContent.seed.matches(newContent.seed) && oldContent.id == newContent.id
}

static func makeInputs(_ inputs: inout _ViewInputs) {
inputs.preferences.requiresPlatformItems = true
inputs.requestedTextRepresentation = PlatformItemsTextRepresentable.self
inputs.requestedImageRepresentation = PlatformItemsImageRepresentable.self
inputs.platformItemsFeatures.formUnion(itemsFeatures)
inputs.platformItemFeatures.formUnion(itemFeatures)
inputs.requestsPlatformItems = true
}

static func makeContent(from outputs: _ViewOutputs) -> OptionalAttribute<PlatformItems> {
.init(outputs.preferences.platformItems)
}
}

// MARK: - UnaryPlatformItemsStrategy

protocol UnaryPlatformItemsStrategy: PlatformItemsStrategy where Content == PlatformItem {}

extension UnaryPlatformItemsStrategy {
static var defaultValue: PlatformItem { .init(id: .init(ids: [.invalid])) }

static var itemsFeatures: PlatformItems.Features { [] }

static func hasChanges(from oldContent: PlatformItem, to newContent: PlatformItem) -> Bool {
!oldContent.seed.matches(newContent.seed) || oldContent.id != newContent.id
}

static func makeInputs(_ inputs: inout _ViewInputs) {
inputs.preferences.requiresPlatformItems = true
inputs.requestedTextRepresentation = PlatformItemsTextRepresentable.self
inputs.requestedImageRepresentation = PlatformItemsImageRepresentable.self
inputs.platformItemsFeatures.formUnion(itemsFeatures)
inputs.platformItemFeatures.formUnion(itemFeatures)
inputs.requestsPlatformItems = true
if itemFeatures.contains(.accessibility) {
inputs.preferences.add(AccessibilityAttachment.Key.self)
}
}

static func makeContent(from outputs: _ViewOutputs) -> OptionalAttribute<PlatformItem> {
.init(outputs.platformItem)
}
}

// MARK: - MultiButtonPlatformItemsStrategy

struct MultiButtonPlatformItemsStrategy: MultiPlatformItemsStrategy {
static var itemFeatures: PlatformItem.Features {
[.text, .image, .selection, .secondaryText]
}
}

// MARK: - LabelPlatformItemsStrategy

struct LabelPlatformItemsStrategy: UnaryPlatformItemsStrategy {
static var itemFeatures: PlatformItem.Features {
[.text, .image, .secondaryText, .iconText, .accessibility]
}
}

// MARK: - TextPlatformItemsStrategy

struct TextPlatformItemsStrategy: UnaryPlatformItemsStrategy {
static var itemFeatures: PlatformItem.Features { .text }
}

// MARK: - ButtonPlatformItemsStrategy

struct ButtonPlatformItemsStrategy: UnaryPlatformItemsStrategy {
static var itemFeatures: PlatformItem.Features {
[.text, .image, .selection, .secondaryText]
}
}

// MARK: - StyledTextPlatformItemsStrategy

struct StyledTextPlatformItemsStrategy: UnaryPlatformItemsStrategy {
static var itemFeatures: PlatformItem.Features { [.text, .styledText] }
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ public struct DefaultButtonStyle: PrimitiveButtonStyle {
// TODO: macOS ToolbarButtonStyle in ToolbarStyleContext.
// TODO: macOS SheetToolbarButtonStyle in SheetToolbarStyleContext.
// TODO: macOS ListAccessoryBarButtonStyle in ListAccessoryBarStyleContext.
// TODO: SidebarSectionActionButtonStyle in SidebarSectionActionStyleContext.
.modifier(
PrimitiveButtonStyleContainerModifier(style: SidebarSectionActionButtonStyle())
.requiring(SidebarSectionActionStyleContext.self)
)
.modifier(
PrimitiveButtonStyleContainerModifier(style: PlatformItemListButtonStyle())
.requiring(AccessibilityQuickActionStyleContext.self)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// SidebarSectionActionButtonStyle_Mac.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete

#if os(macOS)
import OpenSwiftUICore

struct SidebarSectionActionButtonStyle_Mac: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(minWidth: 12, minHeight: 12)
.contentShape(Rectangle())
.labelStyle(.iconOnly)
.defaultForegroundStyle(
configuration.isPressed
? HierarchicalShapeStyle.secondary
: HierarchicalShapeStyle.tertiary
)
.help {
configuration.label
}
}
}
#endif
Loading
Loading