Skip to content

Commit 2530cbf

Browse files
committed
Update ViewTrait
1 parent c4e05ab commit 2530cbf

File tree

2 files changed

+183
-23
lines changed

2 files changed

+183
-23
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// LayoutPriorityLayout.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for iOS 18.0
6+
// Status: WIP
7+
8+
extension View {
9+
/// Sets the priority by which a parent layout should apportion space to
10+
/// this child.
11+
///
12+
/// Views typically have a default priority of `0` which causes space to be
13+
/// apportioned evenly to all sibling views. Raising a view's layout
14+
/// priority encourages the higher priority view to shrink later when the
15+
/// group is shrunk and stretch sooner when the group is stretched.
16+
///
17+
/// HStack {
18+
/// Text("This is a moderately long string.")
19+
/// .font(.largeTitle)
20+
/// .border(Color.gray)
21+
///
22+
/// Spacer()
23+
///
24+
/// Text("This is a higher priority string.")
25+
/// .font(.largeTitle)
26+
/// .layoutPriority(1)
27+
/// .border(Color.gray)
28+
/// }
29+
///
30+
/// In the example above, the first ``Text`` element has the default
31+
/// priority `0` which causes its view to shrink dramatically due to the
32+
/// higher priority of the second ``Text`` element, even though all of their
33+
/// other attributes (font, font size and character count) are the same.
34+
///
35+
/// ![A screenshot showing twoText views different layout
36+
/// priorities.](OpenSwiftUI-View-layoutPriority.png)
37+
///
38+
/// A parent layout offers the child views with the highest layout priority
39+
/// all the space offered to the parent minus the minimum space required for
40+
/// all its lower-priority children.
41+
///
42+
/// - Parameter value: The priority by which a parent layout apportions
43+
/// space to the child.
44+
@inlinable
45+
nonisolated public func layoutPriority(_ value: Double) -> some View {
46+
_trait(LayoutPriorityTraitKey.self, value)
47+
}
48+
}
49+
50+
@usableFromInline
51+
package struct LayoutPriorityTraitKey: _ViewTraitKey {
52+
@inlinable
53+
package static var defaultValue: Double { .zero }
54+
}
55+
56+
@available(*, unavailable)
57+
extension LayoutPriorityTraitKey: Sendable {}
58+
59+
// FIXME
60+
protocol UnaryLayout: ViewModifier {
61+
static func makeViewImpl(
62+
modifier: _GraphValue<Self>,
63+
inputs: _ViewInputs,
64+
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
65+
) -> _ViewOutputs
66+
}
67+
68+
// FIXME
69+
package struct LayoutPriorityLayout: UnaryLayout {
70+
static func makeViewImpl(modifier: _GraphValue<LayoutPriorityLayout>, inputs: _ViewInputs, body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs) -> _ViewOutputs {
71+
.init()
72+
}
73+
}

Sources/OpenSwiftUICore/View/ViewTrait.swift

Lines changed: 110 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
//
22
// ViewTrait.swift
3-
// OpenSwiftUI
3+
// OpenSwiftUICore
44
//
55
// Audited for iOS 18.0
6-
// Status: Blocked by ViewList
6+
// Status: Complete
77
// ID: 9929B476764059557433A108298EE66F (SwiftUI)
88
// ID: 48526BA25CDCBF890FA91D018A5421B4 (SwiftUICore)
99

10-
// TODO: Update path and fix the ViewList issue and the TODO
11-
1210
import OpenGraphShims
1311

1412
// MARK: - ViewTraitKey
@@ -23,11 +21,11 @@ public protocol _ViewTraitKey {
2321
static var defaultValue: Value { get }
2422
}
2523

26-
// MARK: - _TraitWritingModifier [TODO]
24+
// MARK: - _TraitWritingModifier
2725

2826
/// A view content adapter that associates a trait with its base content.
2927
@frozen
30-
public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait : _ViewTraitKey {
28+
public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait: _ViewTraitKey {
3129
public let value: Trait.Value
3230

3331
@inlinable
@@ -40,23 +38,47 @@ public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait :
4038
inputs: _ViewInputs,
4139
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
4240
) -> _ViewOutputs {
43-
preconditionFailure("TODO")
41+
if Trait.self == LayoutPriorityTraitKey.self {
42+
LayoutPriorityLayout.makeViewImpl(
43+
modifier: modifier.unsafeCast(),
44+
inputs: inputs,
45+
body: body
46+
)
47+
} else {
48+
body(_Graph(), inputs)
49+
}
4450
}
51+
4552
nonisolated public static func _makeViewList(
4653
modifier: _GraphValue<Self>,
4754
inputs: _ViewListInputs,
4855
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
4956
) -> _ViewListOutputs {
50-
preconditionFailure("TODO")
51-
}
52-
53-
nonisolated public static func _viewListCount(inputs: _ViewListCountInputs, body: (_ViewListCountInputs) -> Int?) -> Int? {
54-
preconditionFailure("TODO")
57+
var inputs = inputs
58+
if Trait.self == LayoutPriorityTraitKey.self,
59+
!inputs.options.contains(.layoutPriorityIsTrait) {
60+
let attribute = modifier.value.unsafeBitCast(to: _TraitWritingModifier<LayoutPriorityTraitKey>.self)
61+
var outputs = body(_Graph(), inputs)
62+
outputs.multiModifier(_GraphValue(attribute), inputs: inputs)
63+
return outputs
64+
} else {
65+
let addTrait = AddTrait(modifier: modifier.value, traits: OptionalAttribute(inputs.traits))
66+
let attribute = Attribute(addTrait)
67+
inputs.addTraitKey(Trait.self)
68+
inputs.traits = attribute
69+
return body(_Graph(), inputs)
70+
}
5571
}
5672

57-
private struct AddTrait {
73+
private struct AddTrait: Rule {
5874
@Attribute var modifier: _TraitWritingModifier
5975
@OptionalAttribute var traits: ViewTraitCollection?
76+
77+
var value: ViewTraitCollection {
78+
var traits = traits ?? ViewTraitCollection()
79+
traits[Trait.self] = modifier.value
80+
return traits
81+
}
6082
}
6183
}
6284

@@ -67,16 +89,17 @@ extension View {
6789
/// Associate a trait `value` for the given `key` for this view content.
6890
@inlinable
6991
nonisolated public func _trait<K>(_ key: K.Type, _ value: K.Value) -> some View where K: _ViewTraitKey {
70-
return modifier(_TraitWritingModifier<K>(value: value))
92+
modifier(_TraitWritingModifier<K>(value: value))
7193
}
7294
}
7395

74-
// MARK: - _ConditionalTraitWritingModifier [TODO]
96+
// MARK: - _ConditionalTraitWritingModifier
7597

7698
/// Conditionally writes a trait.
7799
@frozen
78100
public struct _ConditionalTraitWritingModifier<Trait>: PrimitiveViewModifier where Trait : _ViewTraitKey {
79101
public var value: Trait.Value
102+
80103
public var isEnabled: Bool
81104

82105
@_alwaysEmitIntoClient
@@ -90,26 +113,56 @@ public struct _ConditionalTraitWritingModifier<Trait>: PrimitiveViewModifier whe
90113
inputs: _ViewInputs,
91114
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
92115
) -> _ViewOutputs {
93-
preconditionFailure("TODO")
116+
_TraitWritingModifier<Trait>._makeView(
117+
modifier: _GraphValue(.init(identifier: .nil)),
118+
inputs: inputs,
119+
body: body
120+
)
94121
}
122+
95123
nonisolated public static func _makeViewList(
96124
modifier: _GraphValue<Self>,
97125
inputs: _ViewListInputs,
98126
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
99127
) -> _ViewListOutputs {
100-
preconditionFailure("TODO")
128+
var inputs = inputs
129+
if Trait.self == LayoutPriorityTraitKey.self,
130+
!inputs.options.contains(.layoutPriorityIsTrait) {
131+
let attribute = modifier.value.unsafeBitCast(to: _TraitWritingModifier<LayoutPriorityTraitKey>.self)
132+
var outputs = body(_Graph(), inputs)
133+
outputs.multiModifier(_GraphValue(attribute), inputs: inputs)
134+
return outputs
135+
} else {
136+
let addTrait = ConditionalAddTrait(modifier: modifier.value, traits: OptionalAttribute(inputs.traits))
137+
let attribute = Attribute(addTrait)
138+
inputs.addTraitKey(Trait.self)
139+
inputs.traits = attribute
140+
return body(_Graph(), inputs)
141+
}
101142
}
102143

103-
nonisolated public static func _viewListCount(inputs: _ViewListCountInputs, body: (_ViewListCountInputs) -> Int?) -> Int? {
104-
preconditionFailure("TODO")
144+
private struct ConditionalAddTrait: Rule {
145+
@Attribute var modifier: _ConditionalTraitWritingModifier
146+
@OptionalAttribute var traits: ViewTraitCollection?
147+
148+
var value: ViewTraitCollection {
149+
var traits = traits ?? ViewTraitCollection()
150+
if modifier.isEnabled {
151+
traits[Trait.self] = modifier.value
152+
}
153+
return traits
154+
}
105155
}
106156
}
107157

108158
@available(*, unavailable)
109159
extension _ConditionalTraitWritingModifier: Sendable {}
110160

111161
extension View {
162+
/// Conditionally writes a trait.
112163
@_alwaysEmitIntoClient
164+
@MainActor
165+
@preconcurrency
113166
public func _trait<K>(_ key: K.Type = K.self, _ value: K.Value, isEnabled: Bool) -> some View where K: _ViewTraitKey {
114167
modifier(_ConditionalTraitWritingModifier<K>(
115168
value: value,
@@ -118,15 +171,49 @@ extension View {
118171
}
119172
}
120173

121-
// MARK: - TraitTransformerModifier [TODO]
174+
// MARK: - TraitTransformerModifier
122175

123-
struct TraitTransformerModifier {
124-
176+
struct TraitTransformerModifier<Trait>: PrimitiveViewModifier where Trait: _ViewTraitKey {
177+
var transform: (inout Trait.Value) -> Void
178+
179+
nonisolated public static func _makeView(
180+
modifier: _GraphValue<Self>,
181+
inputs: _ViewInputs,
182+
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
183+
) -> _ViewOutputs {
184+
body(_Graph(), inputs)
185+
}
186+
187+
nonisolated public static func _makeViewList(
188+
modifier: _GraphValue<Self>,
189+
inputs: _ViewListInputs,
190+
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
191+
) -> _ViewListOutputs {
192+
var inputs = inputs
193+
let trait = TransformTrait(modifier: modifier.value, traits: OptionalAttribute(inputs.traits))
194+
let attribute = Attribute(trait)
195+
inputs.traits = attribute
196+
return body(_Graph(), inputs)
197+
}
198+
199+
private struct TransformTrait: Rule {
200+
@Attribute var modifier: TraitTransformerModifier
201+
@OptionalAttribute var traits: ViewTraitCollection?
202+
203+
var value: ViewTraitCollection {
204+
var traits = traits ?? ViewTraitCollection()
205+
let transform = modifier.transform
206+
var value = traits.value(for: Trait.self)
207+
transform(&value)
208+
traits[Trait.self] = value
209+
return traits
210+
}
211+
}
125212
}
126213

127214
extension View {
128215
package func transformTrait<K>(_ key: K.Type = K.self, transform: @escaping (inout K.Value) -> Void) -> some View where K: _ViewTraitKey {
129-
preconditionFailure("TODO")
216+
modifier(TraitTransformerModifier<K>(transform: transform))
130217
}
131218
}
132219

0 commit comments

Comments
 (0)