@@ -13,14 +13,14 @@ public struct IntrospectionScope: OptionSet {
13
13
14
14
extension View {
15
15
@ViewBuilder
16
- public func introspect< SwiftUIViewType: IntrospectableViewType , PlatformSpecificView : PlatformView > (
16
+ public func introspect< SwiftUIViewType: IntrospectableViewType , PlatformSpecificEntity : PlatformEntity > (
17
17
_ viewType: SwiftUIViewType ,
18
- on platforms: ( PlatformViewVersions < SwiftUIViewType , PlatformSpecificView > ) ... ,
18
+ on platforms: ( PlatformViewVersions < SwiftUIViewType , PlatformSpecificEntity > ) ... ,
19
19
scope: IntrospectionScope ? = nil ,
20
- customize: @escaping ( PlatformSpecificView ) -> Void
20
+ customize: @escaping ( PlatformSpecificEntity ) -> Void
21
21
) -> some View {
22
22
if platforms. contains ( where: \. isCurrent) {
23
- let id = UUID ( )
23
+ let id = IntrospectionAnchorID ( )
24
24
self . background (
25
25
IntrospectionAnchorView (
26
26
id: id
@@ -29,17 +29,17 @@ extension View {
29
29
)
30
30
. overlay (
31
31
IntrospectionView (
32
- selector: { ( view : PlatformView ) in
32
+ selector: { entity in
33
33
let scope = scope ?? viewType. scope
34
34
if
35
35
scope. contains ( . receiver) ,
36
- let target = view . receiver ( ofType: PlatformSpecificView . self, anchorID: id)
36
+ let target = entity . receiver ( ofType: PlatformSpecificEntity . self, anchorID: id)
37
37
{
38
38
return target
39
39
}
40
40
if
41
41
scope. contains ( . ancestor) ,
42
- let target = view . ancestor ( ofType: PlatformSpecificView . self)
42
+ let target = entity . ancestor ( ofType: PlatformSpecificEntity . self)
43
43
{
44
44
return target
45
45
}
@@ -53,149 +53,138 @@ extension View {
53
53
self
54
54
}
55
55
}
56
-
57
- @ViewBuilder
58
- public func introspect< SwiftUIViewType: IntrospectableViewType , PlatformSpecificViewController: PlatformViewController > (
59
- _ viewType: SwiftUIViewType ,
60
- on platforms: ( PlatformViewVersions < SwiftUIViewType , PlatformSpecificViewController > ) ... ,
61
- scope: IntrospectionScope ? = nil ,
62
- customize: @escaping ( PlatformSpecificViewController ) -> Void
63
- ) -> some View {
64
- if platforms. contains ( where: \. isCurrent) {
65
- self . overlay (
66
- IntrospectionView (
67
- selector: { ( viewController: PlatformViewController ) in
68
- let scope = scope ?? viewType. scope
69
- if
70
- scope. contains ( . receiver) ,
71
- let target = viewController. receiver ( ofType: PlatformSpecificViewController . self)
72
- {
73
- return target
74
- }
75
- if
76
- scope. contains ( . ancestor) ,
77
- let target = viewController. ancestor ( ofType: PlatformSpecificViewController . self)
78
- {
79
- return target
80
- }
81
- return nil
82
- } ,
83
- customize: customize
84
- )
85
- . frame ( width: 0 , height: 0 )
86
- )
87
- } else {
88
- self
89
- }
90
- }
91
56
}
92
57
93
- extension PlatformView {
94
- fileprivate func receiver< PlatformSpecificView: PlatformView > (
95
- ofType type: PlatformSpecificView . Type ,
96
- anchorID: IntrospectionAnchorView . ID
97
- ) -> PlatformSpecificView ? {
98
- let frontView = self
99
- guard
100
- let backView = Array ( frontView. superviews) . last? . viewWithTag ( anchorID. hashValue) ,
101
- let superview = backView. nearestCommonSuperviewWith ( frontView)
102
- else {
103
- return nil
104
- }
58
+ public protocol PlatformEntity : AnyObject {
59
+ associatedtype Base : PlatformEntity
105
60
106
- return superview
107
- . subviewsBetween ( backView, and: frontView)
108
- . compactMap { $0 as? PlatformSpecificView }
109
- . first
110
- }
61
+ @_spi ( Internals)
62
+ var ancestor : Base ? { get }
111
63
112
- fileprivate func ancestor< PlatformSpecificView: PlatformView > (
113
- ofType type: PlatformSpecificView . Type
114
- ) -> PlatformSpecificView ? {
115
- self . superviews. lazy. compactMap { $0 as? PlatformSpecificView } . first
116
- }
64
+ @_spi ( Internals)
65
+ var descendants : [ Base ] { get }
66
+
67
+ @_spi ( Internals)
68
+ func isDescendant( of other: Base ) -> Bool
69
+
70
+ @_spi ( Internals)
71
+ func entityWithTag( _ tag: Int ) -> Base ?
117
72
}
118
73
119
- extension PlatformView {
120
- private var superviews : some Sequence < PlatformView > {
121
- sequence ( first: self , next: \. superview) . dropFirst ( )
74
+ extension PlatformEntity {
75
+ @_spi ( Internals)
76
+ public var ancestors : some Sequence < Base > {
77
+ sequence ( first: self ~ , next: { $0. ancestor~ } ) . dropFirst ( )
122
78
}
123
79
124
- private func nearestCommonSuperviewWith( _ other: PlatformView ) -> PlatformView ? {
125
- var nearestAncestor : PlatformView ? = self
80
+ @_spi ( Internals)
81
+ public var allDescendants : [ Base ] {
82
+ self . descendants. reduce ( [ self ~ ] ) { $0 + $1. allDescendants~ }
83
+ }
84
+
85
+ @_spi ( Internals)
86
+ public func nearestCommonAncestor( with other: Base ) -> Base ? {
87
+ var nearestAncestor : Base ? = self ~
126
88
127
- while let currentView = nearestAncestor, !other. isDescendant ( of: currentView ) {
128
- nearestAncestor = currentView . superview
89
+ while let currentEntity = nearestAncestor, !other . isDescendant( of: currentEntity ~ ) {
90
+ nearestAncestor = currentEntity . ancestor ~
129
91
}
130
92
131
93
return nearestAncestor
132
94
}
133
95
134
- private func subviewsBetween( _ bottomView: PlatformView , and topView: PlatformView ) -> [ PlatformView ] {
96
+ @_spi ( Internals)
97
+ public func descendantsBetween( _ bottomEntity: Base , and topEntity: Base ) -> [ Base ] {
135
98
var entered = false
136
- var result : [ PlatformView ] = [ ]
99
+ var result : [ Base ] = [ ]
137
100
138
- for subview in self . allSubviews {
139
- if subview === bottomView {
101
+ for descendant in self . allDescendants {
102
+ if descendant === bottomEntity {
140
103
entered = true
141
104
continue
142
105
}
143
- if subview === topView {
106
+ if descendant === topEntity {
144
107
return result
145
108
}
146
109
if entered {
147
- result. append ( subview )
110
+ result. append ( descendant )
148
111
}
149
112
}
150
113
151
114
return result
152
115
}
153
116
154
- private var allSubviews : [ PlatformView ] {
155
- self . subviews. reduce ( [ self ] ) { $0 + $1. allSubviews }
156
- }
157
- }
117
+ fileprivate func receiver< PlatformSpecificEntity: PlatformEntity > (
118
+ ofType type: PlatformSpecificEntity . Type ,
119
+ anchorID: IntrospectionAnchorID
120
+ ) -> PlatformSpecificEntity ? {
121
+ let frontEntity = self
122
+ guard
123
+ let backEntity = Array ( frontEntity. ancestors) . last? . entityWithTag ( anchorID. hashValue) ,
124
+ let commonAncestor = backEntity. nearestCommonAncestor ( with: frontEntity~ )
125
+ else {
126
+ return nil
127
+ }
158
128
159
- extension PlatformViewController {
160
- fileprivate func receiver< PlatformSpecificViewController: PlatformViewController > (
161
- ofType type: PlatformSpecificViewController . Type
162
- ) -> PlatformSpecificViewController ? {
163
- self . hostingView?
164
- . allChildren ( ofType: PlatformSpecificViewController . self)
165
- . filter { !( $0 is IntrospectionPlatformViewController ) }
129
+ return commonAncestor
130
+ . descendantsBetween ( backEntity~ , and: frontEntity~ )
131
+ . compactMap { $0 as? PlatformSpecificEntity }
166
132
. first
167
133
}
168
134
169
- fileprivate func ancestor< PlatformSpecificViewController : PlatformViewController > (
170
- ofType type: PlatformSpecificViewController . Type
171
- ) -> PlatformSpecificViewController ? {
172
- self . parents
135
+ fileprivate func ancestor< PlatformSpecificEntity : PlatformEntity > (
136
+ ofType type: PlatformSpecificEntity . Type
137
+ ) -> PlatformSpecificEntity ? {
138
+ self . ancestors
173
139
. lazy
174
- . filter { !( $0 is IntrospectionPlatformViewController ) }
175
- . compactMap { $0 as? PlatformSpecificViewController }
140
+ . compactMap { $0 as? PlatformSpecificEntity }
176
141
. first
177
142
}
178
143
}
179
144
180
- extension PlatformViewController {
181
- private var parents : some Sequence < PlatformViewController > {
182
- sequence ( first: self , next: \. parent) . dropFirst ( )
145
+ extension PlatformView : PlatformEntity {
146
+ @_spi ( Internals)
147
+ public var ancestor : PlatformView ? {
148
+ superview
149
+ }
150
+
151
+ @_spi ( Internals)
152
+ public var descendants : [ PlatformView ] {
153
+ subviews
154
+ }
155
+
156
+ @_spi ( Internals)
157
+ public func entityWithTag( _ tag: Int ) -> PlatformView ? {
158
+ viewWithTag ( tag)
159
+ }
160
+ }
161
+
162
+ extension PlatformViewController : PlatformEntity {
163
+ @_spi ( Internals)
164
+ public var ancestor : PlatformViewController ? {
165
+ parent
183
166
}
184
167
185
- private var hostingView : PlatformViewController ? {
186
- self . parents. first ( where: {
187
- let type = String ( reflecting: type ( of: $0) )
188
- return type. hasPrefix ( " SwiftUI. " ) && type. contains ( " Hosting " )
189
- } )
168
+ @_spi ( Internals)
169
+ public var descendants : [ PlatformViewController ] {
170
+ children
190
171
}
191
172
192
- private func allChildren< PlatformSpecificViewController: PlatformViewController > (
193
- ofType type: PlatformSpecificViewController . Type
194
- ) -> [ PlatformSpecificViewController ] {
195
- var result = self . children. compactMap { $0 as? PlatformSpecificViewController }
196
- for subview in self . children {
197
- result. append ( contentsOf: subview. allChildren ( ofType: type) )
173
+ @_spi ( Internals)
174
+ public func isDescendant( of other: PlatformViewController ) -> Bool {
175
+ self . ancestors. contains ( other)
176
+ }
177
+
178
+ @_spi ( Internals)
179
+ public func entityWithTag( _ tag: Int ) -> PlatformViewController ? {
180
+ if self . view. tag == tag {
181
+ return self
198
182
}
199
- return result
183
+ for child in children {
184
+ if let childWithTag = child. entityWithTag ( tag) {
185
+ return childWithTag
186
+ }
187
+ }
188
+ return nil
200
189
}
201
190
}
0 commit comments