Skip to content

Commit 4998fa2

Browse files
authored
Update ViewTrait (#219)
* Update ViewTrait path * Update ViewTrait
1 parent af2eae7 commit 4998fa2

File tree

3 files changed

+183
-21
lines changed

3 files changed

+183
-21
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/Variadic/ViewTrait.swift renamed to Sources/OpenSwiftUICore/View/ViewTrait.swift

Lines changed: 110 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
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

@@ -21,11 +21,11 @@ public protocol _ViewTraitKey {
2121
static var defaultValue: Value { get }
2222
}
2323

24-
// MARK: - _TraitWritingModifier [TODO]
24+
// MARK: - _TraitWritingModifier
2525

2626
/// A view content adapter that associates a trait with its base content.
2727
@frozen
28-
public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait : _ViewTraitKey {
28+
public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait: _ViewTraitKey {
2929
public let value: Trait.Value
3030

3131
@inlinable
@@ -38,23 +38,47 @@ public struct _TraitWritingModifier<Trait>: PrimitiveViewModifier where Trait :
3838
inputs: _ViewInputs,
3939
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
4040
) -> _ViewOutputs {
41-
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+
}
4250
}
51+
4352
nonisolated public static func _makeViewList(
4453
modifier: _GraphValue<Self>,
4554
inputs: _ViewListInputs,
4655
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
4756
) -> _ViewListOutputs {
48-
preconditionFailure("TODO")
49-
}
50-
51-
nonisolated public static func _viewListCount(inputs: _ViewListCountInputs, body: (_ViewListCountInputs) -> Int?) -> Int? {
52-
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+
}
5371
}
5472

55-
private struct AddTrait {
73+
private struct AddTrait: Rule {
5674
@Attribute var modifier: _TraitWritingModifier
5775
@OptionalAttribute var traits: ViewTraitCollection?
76+
77+
var value: ViewTraitCollection {
78+
var traits = traits ?? ViewTraitCollection()
79+
traits[Trait.self] = modifier.value
80+
return traits
81+
}
5882
}
5983
}
6084

@@ -65,16 +89,17 @@ extension View {
6589
/// Associate a trait `value` for the given `key` for this view content.
6690
@inlinable
6791
nonisolated public func _trait<K>(_ key: K.Type, _ value: K.Value) -> some View where K: _ViewTraitKey {
68-
return modifier(_TraitWritingModifier<K>(value: value))
92+
modifier(_TraitWritingModifier<K>(value: value))
6993
}
7094
}
7195

72-
// MARK: - _ConditionalTraitWritingModifier [TODO]
96+
// MARK: - _ConditionalTraitWritingModifier
7397

7498
/// Conditionally writes a trait.
7599
@frozen
76100
public struct _ConditionalTraitWritingModifier<Trait>: PrimitiveViewModifier where Trait : _ViewTraitKey {
77101
public var value: Trait.Value
102+
78103
public var isEnabled: Bool
79104

80105
@_alwaysEmitIntoClient
@@ -88,26 +113,56 @@ public struct _ConditionalTraitWritingModifier<Trait>: PrimitiveViewModifier whe
88113
inputs: _ViewInputs,
89114
body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs
90115
) -> _ViewOutputs {
91-
preconditionFailure("TODO")
116+
_TraitWritingModifier<Trait>._makeView(
117+
modifier: _GraphValue(Attribute(identifier: AnyAttribute.nil)),
118+
inputs: inputs,
119+
body: body
120+
)
92121
}
122+
93123
nonisolated public static func _makeViewList(
94124
modifier: _GraphValue<Self>,
95125
inputs: _ViewListInputs,
96126
body: @escaping (_Graph, _ViewListInputs) -> _ViewListOutputs
97127
) -> _ViewListOutputs {
98-
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+
}
99142
}
100143

101-
nonisolated public static func _viewListCount(inputs: _ViewListCountInputs, body: (_ViewListCountInputs) -> Int?) -> Int? {
102-
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+
}
103155
}
104156
}
105157

106158
@available(*, unavailable)
107159
extension _ConditionalTraitWritingModifier: Sendable {}
108160

109161
extension View {
162+
/// Conditionally writes a trait.
110163
@_alwaysEmitIntoClient
164+
@MainActor
165+
@preconcurrency
111166
public func _trait<K>(_ key: K.Type = K.self, _ value: K.Value, isEnabled: Bool) -> some View where K: _ViewTraitKey {
112167
modifier(_ConditionalTraitWritingModifier<K>(
113168
value: value,
@@ -116,15 +171,49 @@ extension View {
116171
}
117172
}
118173

119-
// MARK: - TraitTransformerModifier [TODO]
174+
// MARK: - TraitTransformerModifier
120175

121-
struct TraitTransformerModifier {
122-
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+
}
123212
}
124213

125214
extension View {
126215
package func transformTrait<K>(_ key: K.Type = K.self, transform: @escaping (inout K.Value) -> Void) -> some View where K: _ViewTraitKey {
127-
preconditionFailure("TODO")
216+
modifier(TraitTransformerModifier<K>(transform: transform))
128217
}
129218
}
130219

0 commit comments

Comments
 (0)