diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Classes/AccessibilitySnapshotView.swift b/Sources/AccessibilitySnapshot/Core/Swift/Classes/AccessibilitySnapshotView.swift index 07bbc1ff..5bbe13bf 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Classes/AccessibilitySnapshotView.swift +++ b/Sources/AccessibilitySnapshot/Core/Swift/Classes/AccessibilitySnapshotView.swift @@ -37,32 +37,7 @@ public enum ActivationPointDisplayMode { /// /// The overlays and legend will be added when `parseAccessibility()` is called. In order for the coordinates to be /// calculated properly, the view must already be in the view hierarchy. -public final class AccessibilitySnapshotView: UIView { - - // MARK: - Public Types - - public enum Error: Swift.Error { - - /// An error indicating that the `containedView` is too large too snapshot using the specified rendering - /// parameters. - /// - /// - Note: This error is thrown due to filters failing. To avoid this error, try rendering the snapshot in - /// polychrome, reducing the size of the `containedView`, or running on a different iOS version. In particular, - /// this error is known to occur when rendering a monochrome snapshot on iOS 13. - case containedViewExceedsMaximumSize(viewSize: CGSize, maximumSize: CGSize) - - /// An error indicating that the `containedView` has a transform that is not support while using the specified - /// rendering parameters. - /// - /// - Note: In particular, this error is known to occur when using a non-identity transform that requires - /// tiling. To avoid this error, try setting an identity transform on the `containedView` or using the - /// `.renderLayerInContext` view rendering mode - case containedViewHasUnsupportedTransform(transform: CATransform3D) - - /// An error indicating the `containedView` has an invalid size due to the `width` and/or `height` being zero. - case containedViewHasZeroSize(viewSize: CGSize) - - } +public final class AccessibilitySnapshotView: SnapshotAndLegendView { // MARK: - Life Cycle @@ -91,9 +66,6 @@ public final class AccessibilitySnapshotView: UIView { super.init(frame: containedView.bounds) - snapshotView.clipsToBounds = true - addSubview(snapshotView) - backgroundColor = .init(white: 0.9, alpha: 1.0) } @@ -102,14 +74,22 @@ public final class AccessibilitySnapshotView: UIView { fatalError("init(coder:) has not been implemented") } + // MARK: - SnapshotAndLegendView + + override var legendViews: [UIView] { + return displayMarkers.map { $0.legendView } + } + + override var minimumLegendWidth: CGFloat { + return LegendView.Metrics.minimumWidth + } + // MARK: - Private Properties private let containedView: UIView private let viewRenderingMode: ViewRenderingMode - private let snapshotView: UIImageView = .init() - private let markerColors: [UIColor] private let activationPointDisplayMode: ActivationPointDisplayMode @@ -234,156 +214,6 @@ public final class AccessibilitySnapshotView: UIView { self.displayMarkers = displayMarkers } - // MARK: - UIView - - public override func layoutSubviews() { - let legendViews = displayMarkers.map { $0.legendView } - - switch legendLocation(viewSize: snapshotView.bounds.size) { - case let .bottom(width: availableLegendWidth): - snapshotView.frame.origin.y = bounds.minY - snapshotView.frame.origin.x = ((bounds.width - snapshotView.frame.width) / 2).floorToPixel(in: window) - - var nextLegendY = snapshotView.frame.maxY + Metrics.legendInsets.top - for legendView in legendViews { - legendView.bounds.size = legendView.sizeThatFits( - .init(width: availableLegendWidth, height: .greatestFiniteMagnitude) - ) - legendView.frame.origin = .init(x: Metrics.legendInsets.left, y: nextLegendY) - nextLegendY += legendView.frame.height + Metrics.legendVerticalSpacing - } - - case let .right(height: availableLegendHeight): - snapshotView.frame.origin = .zero - - var nextLegendOrigin: CGPoint = .init( - x: snapshotView.frame.maxX + Metrics.legendInsets.left, - y: Metrics.legendInsets.top - ) - - let maxYBoundary = bounds.minY + availableLegendHeight - - for legendView in legendViews { - legendView.bounds.size = legendView.sizeThatFits( - .init(width: LegendView.Metrics.minimumWidth, height: availableLegendHeight) - ) - - if nextLegendOrigin.y + legendView.bounds.height <= maxYBoundary { - legendView.frame.origin = nextLegendOrigin - nextLegendOrigin.y += legendView.bounds.height + Metrics.legendVerticalSpacing - - } else { - legendView.frame.origin = .init( - x: nextLegendOrigin.x + LegendView.Metrics.minimumWidth + Metrics.legendHorizontalSpacing, - y: Metrics.legendInsets.top - ) - nextLegendOrigin = .init( - x: legendView.frame.minX, - y: legendView.frame.maxY + Metrics.legendVerticalSpacing - ) - } - } - } - } - - public override func sizeThatFits(_ size: CGSize) -> CGSize { - guard !displayMarkers.isEmpty else { - return snapshotView.bounds.size - } - - switch legendLocation(viewSize: snapshotView.bounds.size) { - case let .bottom(width: availableWidth): - let legendViewSizes = displayMarkers.map { - $0.legendView.sizeThatFits(.init(width: availableWidth, height: .greatestFiniteMagnitude)) - } - - let widestLegendView = legendViewSizes - .map { $0.width } - .reduce(0, max) - - let legendHeight = legendViewSizes - .map { $0.height } - .reduce(-Metrics.legendVerticalSpacing, { $0 + $1 + Metrics.legendVerticalSpacing }) - - let width = max( - snapshotView.frame.width, - widestLegendView + Metrics.legendInsets.left + Metrics.legendInsets.right, - Metrics.minimumWidth - ) - - let heightComponents = [ - snapshotView.frame.height, - Metrics.legendInsets.top, - legendHeight, - Metrics.legendInsets.bottom, - ] - - return CGSize( - width: width.ceilToPixel(in: window), - height: heightComponents.reduce(0, +).ceilToPixel(in: window) - ) - - case let .right(height: availableHeight): - let legendViewSizes = displayMarkers.map { - $0.legendView.sizeThatFits(.init(width: LegendView.Metrics.minimumWidth, height: availableHeight)) - } - - var columnHeights = [-Metrics.legendVerticalSpacing] - var lastColumnIndex = 0 - - for legendViewSize in legendViewSizes { - let lastColumnHeight = columnHeights[lastColumnIndex] - let heightByAddingLegendView = lastColumnHeight + Metrics.legendVerticalSpacing + legendViewSize.height - - if heightByAddingLegendView <= availableHeight { - columnHeights[lastColumnIndex] = heightByAddingLegendView - - } else { - columnHeights.append(legendViewSize.height) - lastColumnIndex += 1 - } - } - - let widthComponents = [ - snapshotView.bounds.width, - Metrics.legendInsets.left, - CGFloat(columnHeights.count) * LegendView.Metrics.minimumWidth, - CGFloat(columnHeights.count - 1) * Metrics.legendHorizontalSpacing, - Metrics.legendInsets.right, - ] - - let maxLegendViewHeight = legendViewSizes.reduce(0, { max($0, $1.height) }) - let height = max( - snapshotView.bounds.height, - maxLegendViewHeight + Metrics.legendInsets.top + Metrics.legendInsets.bottom - ) - - return CGSize( - width: widthComponents.reduce(0, +), - height: height - ) - } - } - - // MARK: - Private Methods - - private func legendLocation(viewSize: CGSize) -> LegendLocation { - let aspectRatio = viewSize.width / viewSize.height - - if aspectRatio > 1 || viewSize.width < Metrics.minimumWidth { - // Wide views should display the legend underneath the snapshotted view. Small views are an exception, as - // all views smaller than the minimum width should display the legend underneath. - let contentWidth = max(viewSize.width, Metrics.minimumWidth) - let availableWidth = contentWidth - Metrics.legendInsets.left - Metrics.legendInsets.right - return .bottom(width: availableWidth) - - } else { - // Tall views that meet the minimum height requirement should display the legend to the right of the - // snapshotted view. - return .right(height: viewSize.height - Metrics.legendInsets.top - Metrics.legendInsets.bottom) - } - } - // MARK: - Public Static Properties public static let defaultMarkerColors: [UIColor] = [ .cyan, .magenta, .green, .blue, .yellow, .purple, .orange ] @@ -402,28 +232,6 @@ public final class AccessibilitySnapshotView: UIView { } - private enum LegendLocation { - - case bottom(width: CGFloat) - - case right(height: CGFloat) - - } - - private enum Metrics { - - static var minimumWidth: CGFloat { - return LegendView.Metrics.minimumWidth + legendInsets.left + legendInsets.right - } - - static let legendInsets: UIEdgeInsets = .init(top: 16, left: 16, bottom: 16, right: 16) - - static let legendHorizontalSpacing: CGFloat = 16 - - static let legendVerticalSpacing: CGFloat = 16 - - } - } // MARK: - @@ -806,22 +614,6 @@ private extension Bundle { // MARK: - -private extension CGFloat { - - func floorToPixel(in source: UIWindow?) -> CGFloat { - let scale = source?.screen.scale ?? 1 - return floor(self * scale) / scale - } - - func ceilToPixel(in source: UIWindow?) -> CGFloat { - let scale = source?.screen.scale ?? 1 - return ceil(self * scale) / scale - } - -} - -// MARK: - - private extension UIView { func superviewWithSubviewIndex() -> (UIView, Int)? { diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Classes/HitTargetSnapshotView.swift b/Sources/AccessibilitySnapshot/Core/Swift/Classes/HitTargetSnapshotView.swift index a2b2b0b8..caee84c2 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Classes/HitTargetSnapshotView.swift +++ b/Sources/AccessibilitySnapshot/Core/Swift/Classes/HitTargetSnapshotView.swift @@ -70,7 +70,7 @@ public enum HitTargetSnapshotUtility { ) guard view.bounds.width > 0 && view.bounds.height > 0 else { - throw AccessibilitySnapshotView.Error.containedViewHasZeroSize(viewSize: view.bounds.size) + throw ImageRenderingError.containedViewHasZeroSize(viewSize: view.bounds.size) } return renderer.image { context in diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Classes/SnapshotAndLegendView.swift b/Sources/AccessibilitySnapshot/Core/Swift/Classes/SnapshotAndLegendView.swift new file mode 100644 index 00000000..68100e0c --- /dev/null +++ b/Sources/AccessibilitySnapshot/Core/Swift/Classes/SnapshotAndLegendView.swift @@ -0,0 +1,239 @@ +// +// Copyright 2024 Block Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +public class SnapshotAndLegendView: UIView { + + // MARK: - Life Cycle + + internal override init(frame: CGRect) { + super.init(frame: frame) + + snapshotView.clipsToBounds = true + addSubview(snapshotView) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Internal Properties + + internal let snapshotView: UIImageView = .init() + + internal var legendViews: [UIView] { + // This is intended to be overridden and implemented by subclasses. + return [] + } + + internal var minimumLegendWidth: CGFloat { + // This is intended to be overridden and implemented by subclasses. + return 0 + } + + // MARK: - Private Properties + + private var minimumWidth: CGFloat { + return minimumLegendWidth + Metrics.legendInsets.left + Metrics.legendInsets.right + } + + // MARK: - UIView + + public override func layoutSubviews() { + switch legendLocation(viewSize: snapshotView.bounds.size) { + case let .bottom(width: availableLegendWidth): + snapshotView.frame.origin.y = bounds.minY + snapshotView.frame.origin.x = ((bounds.width - snapshotView.frame.width) / 2).floorToPixel(in: window) + + var nextLegendY = snapshotView.frame.maxY + Metrics.legendInsets.top + for legendView in legendViews { + legendView.bounds.size = legendView.sizeThatFits( + .init(width: availableLegendWidth, height: .greatestFiniteMagnitude) + ) + legendView.frame.origin = .init(x: Metrics.legendInsets.left, y: nextLegendY) + nextLegendY += legendView.frame.height + Metrics.legendVerticalSpacing + } + + case let .right(height: availableLegendHeight): + snapshotView.frame.origin = .zero + + var nextLegendOrigin: CGPoint = .init( + x: snapshotView.frame.maxX + Metrics.legendInsets.left, + y: Metrics.legendInsets.top + ) + + let maxYBoundary = bounds.minY + availableLegendHeight + + for legendView in legendViews { + legendView.bounds.size = legendView.sizeThatFits( + .init(width: minimumLegendWidth, height: availableLegendHeight) + ) + + if nextLegendOrigin.y + legendView.bounds.height <= maxYBoundary { + legendView.frame.origin = nextLegendOrigin + nextLegendOrigin.y += legendView.bounds.height + Metrics.legendVerticalSpacing + + } else { + legendView.frame.origin = .init( + x: nextLegendOrigin.x + minimumLegendWidth + Metrics.legendHorizontalSpacing, + y: Metrics.legendInsets.top + ) + nextLegendOrigin = .init( + x: legendView.frame.minX, + y: legendView.frame.maxY + Metrics.legendVerticalSpacing + ) + } + } + } + } + + public override func sizeThatFits(_ size: CGSize) -> CGSize { + guard !legendViews.isEmpty else { + return snapshotView.bounds.size + } + + switch legendLocation(viewSize: snapshotView.bounds.size) { + case let .bottom(width: availableWidth): + let legendViewSizes = legendViews.map { + $0.sizeThatFits(.init(width: availableWidth, height: .greatestFiniteMagnitude)) + } + + let widestLegendView = legendViewSizes + .map { $0.width } + .reduce(0, max) + + let legendHeight = legendViewSizes + .map { $0.height } + .reduce(-Metrics.legendVerticalSpacing, { $0 + $1 + Metrics.legendVerticalSpacing }) + + let width = max( + snapshotView.frame.width, + widestLegendView + Metrics.legendInsets.left + Metrics.legendInsets.right, + minimumWidth + ) + + let heightComponents = [ + snapshotView.frame.height, + Metrics.legendInsets.top, + legendHeight, + Metrics.legendInsets.bottom, + ] + + return CGSize( + width: width.ceilToPixel(in: window), + height: heightComponents.reduce(0, +).ceilToPixel(in: window) + ) + + case let .right(height: availableHeight): + let legendViewSizes = legendViews.map { + $0.sizeThatFits(.init(width: minimumLegendWidth, height: availableHeight)) + } + + var columnHeights = [-Metrics.legendVerticalSpacing] + var lastColumnIndex = 0 + + for legendViewSize in legendViewSizes { + let lastColumnHeight = columnHeights[lastColumnIndex] + let heightByAddingLegendView = lastColumnHeight + Metrics.legendVerticalSpacing + legendViewSize.height + + if heightByAddingLegendView <= availableHeight { + columnHeights[lastColumnIndex] = heightByAddingLegendView + + } else { + columnHeights.append(legendViewSize.height) + lastColumnIndex += 1 + } + } + + let widthComponents = [ + snapshotView.bounds.width, + Metrics.legendInsets.left, + CGFloat(columnHeights.count) * minimumLegendWidth, + CGFloat(columnHeights.count - 1) * Metrics.legendHorizontalSpacing, + Metrics.legendInsets.right, + ] + + let maxLegendViewHeight = legendViewSizes.reduce(0, { max($0, $1.height) }) + let height = max( + snapshotView.bounds.height, + maxLegendViewHeight + Metrics.legendInsets.top + Metrics.legendInsets.bottom + ) + + return CGSize( + width: widthComponents.reduce(0, +), + height: height + ) + } + } + + // MARK: - Private Methods + + private func legendLocation(viewSize: CGSize) -> LegendLocation { + let aspectRatio = viewSize.width / viewSize.height + + if aspectRatio > 1 || viewSize.width < minimumWidth { + // Wide views should display the legend underneath the snapshotted view. Small views are an exception, as + // all views smaller than the minimum width should display the legend underneath. + let contentWidth = max(viewSize.width, minimumWidth) + let availableWidth = contentWidth - Metrics.legendInsets.left - Metrics.legendInsets.right + return .bottom(width: availableWidth) + + } else { + // Tall views that meet the minimum height requirement should display the legend to the right of the + // snapshotted view. + return .right(height: viewSize.height - Metrics.legendInsets.top - Metrics.legendInsets.bottom) + } + } + + // MARK: - Private Types + + private enum LegendLocation { + + case bottom(width: CGFloat) + + case right(height: CGFloat) + + } + + private enum Metrics { + + static let legendInsets: UIEdgeInsets = .init(top: 16, left: 16, bottom: 16, right: 16) + + static let legendHorizontalSpacing: CGFloat = 16 + + static let legendVerticalSpacing: CGFloat = 16 + + } + +} + +// MARK: - + +private extension CGFloat { + + func floorToPixel(in source: UIWindow?) -> CGFloat { + let scale = source?.screen.scale ?? 1 + return floor(self * scale) / scale + } + + func ceilToPixel(in source: UIWindow?) -> CGFloat { + let scale = source?.screen.scale ?? 1 + return ceil(self * scale) / scale + } + +} diff --git a/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIView+ImageRendering.swift b/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIView+ImageRendering.swift index e5ee10a1..f205c88c 100644 --- a/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIView+ImageRendering.swift +++ b/Sources/AccessibilitySnapshot/Core/Swift/Classes/UIView+ImageRendering.swift @@ -17,6 +17,29 @@ import CoreImage import UIKit +public enum ImageRenderingError: Swift.Error { + + /// An error indicating that the `containedView` is too large too snapshot using the specified rendering + /// parameters. + /// + /// - Note: This error is thrown due to filters failing. To avoid this error, try rendering the snapshot in + /// polychrome, reducing the size of the `containedView`, or running on a different iOS version. In particular, + /// this error is known to occur when rendering a monochrome snapshot on iOS 13. + case containedViewExceedsMaximumSize(viewSize: CGSize, maximumSize: CGSize) + + /// An error indicating that the `containedView` has a transform that is not support while using the specified + /// rendering parameters. + /// + /// - Note: In particular, this error is known to occur when using a non-identity transform that requires + /// tiling. To avoid this error, try setting an identity transform on the `containedView` or using the + /// `.renderLayerInContext` view rendering mode + case containedViewHasUnsupportedTransform(transform: CATransform3D) + + /// An error indicating the `containedView` has an invalid size due to the `width` and/or `height` being zero. + case containedViewHasZeroSize(viewSize: CGSize) + +} + extension UIView { func renderToImage( @@ -60,7 +83,7 @@ extension UIView { // result in a blank image. let maximumSize = CGSize(width: 1365, height: 1365) if snapshot.size.width > maximumSize.width || snapshot.size.height > maximumSize.height { - throw AccessibilitySnapshotView.Error.containedViewExceedsMaximumSize( + throw ImageRenderingError.containedViewExceedsMaximumSize( viewSize: snapshot.size, maximumSize: maximumSize ) @@ -93,7 +116,7 @@ extension UIView { private func drawTiledHierarchySnapshots(in context: UIGraphicsImageRendererContext, error: inout Error?) { guard CATransform3DIsIdentity(layer.transform) else { - error = AccessibilitySnapshotView.Error.containedViewHasUnsupportedTransform(transform: layer.transform) + error = ImageRenderingError.containedViewHasUnsupportedTransform(transform: layer.transform) return } diff --git a/Sources/AccessibilitySnapshot/SnapshotTesting/SnapshotTesting+Accessibility.swift b/Sources/AccessibilitySnapshot/SnapshotTesting/SnapshotTesting+Accessibility.swift index c2d7b09e..642dbd93 100644 --- a/Sources/AccessibilitySnapshot/SnapshotTesting/SnapshotTesting+Accessibility.swift +++ b/Sources/AccessibilitySnapshot/SnapshotTesting/SnapshotTesting+Accessibility.swift @@ -73,7 +73,7 @@ extension Snapshotting where Value == UIView, Format == UIImage { do { try containerView.parseAccessibility(useMonochromeSnapshot: useMonochromeSnapshot) - } catch AccessibilitySnapshotView.Error.containedViewExceedsMaximumSize { + } catch ImageRenderingError.containedViewExceedsMaximumSize { fatalError( """ View is too large to render monochrome snapshot. Try setting useMonochromeSnapshot to false or \ @@ -81,7 +81,7 @@ extension Snapshotting where Value == UIView, Format == UIImage { iOS 14. """ ) - } catch AccessibilitySnapshotView.Error.containedViewHasUnsupportedTransform { + } catch ImageRenderingError.containedViewHasUnsupportedTransform { fatalError( """ View has an unsupported transform for the specified snapshot parameters. Try using an identity \ @@ -206,7 +206,7 @@ extension Snapshotting where Value == UIView, Format == UIImage { } return image - } catch AccessibilitySnapshotView.Error.containedViewExceedsMaximumSize { + } catch ImageRenderingError.containedViewExceedsMaximumSize { fatalError( """ View is too large to render monochrome snapshot. Try setting useMonochromeSnapshot to false or \ @@ -216,7 +216,7 @@ extension Snapshotting where Value == UIView, Format == UIImage { file: file, line: line ) - } catch AccessibilitySnapshotView.Error.containedViewHasUnsupportedTransform { + } catch ImageRenderingError.containedViewHasUnsupportedTransform { fatalError( """ View has an unsupported transform for the specified snapshot parameters. Try using an identity \ diff --git a/Sources/AccessibilitySnapshot/iOSSnapshotTestCase/Swift/ErrorMessageFactory.swift b/Sources/AccessibilitySnapshot/iOSSnapshotTestCase/Swift/ErrorMessageFactory.swift index 562c796c..3777a38a 100644 --- a/Sources/AccessibilitySnapshot/iOSSnapshotTestCase/Swift/ErrorMessageFactory.swift +++ b/Sources/AccessibilitySnapshot/iOSSnapshotTestCase/Swift/ErrorMessageFactory.swift @@ -28,12 +28,12 @@ internal enum ErrorMessageFactory { static func errorMessageForAccessibilityParsingError(_ error: Error) -> String { switch error { - case AccessibilitySnapshotView.Error.containedViewExceedsMaximumSize: + case ImageRenderingError.containedViewExceedsMaximumSize: return """ View is too large to render monochrome snapshot. Try setting useMonochromeSnapshot to false or use a \ different iOS version. In particular, this is known to fail on iOS 13, but was fixed in iOS 14. """ - case AccessibilitySnapshotView.Error.containedViewHasUnsupportedTransform: + case ImageRenderingError.containedViewHasUnsupportedTransform: return """ View has an unsupported transform for the specified snapshot parameters. Try using an identity \ transform or changing the view rendering mode to render the layer in the graphics context. diff --git a/Sources/AccessibilitySnapshotCore.xcodeproj/project.pbxproj b/Sources/AccessibilitySnapshotCore.xcodeproj/project.pbxproj index 836cdb96..aeaae7d5 100644 --- a/Sources/AccessibilitySnapshotCore.xcodeproj/project.pbxproj +++ b/Sources/AccessibilitySnapshotCore.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3D63420F2B589032003FB4D3 /* SnapshotAndLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D63420E2B589032003FB4D3 /* SnapshotAndLegendView.swift */; }; 3D9D41882B355E970033460C /* HitTargetSnapshotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9D41862B355E970033460C /* HitTargetSnapshotView.swift */; }; 3D9D41892B355E970033460C /* UIView+ImageRendering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9D41872B355E970033460C /* UIView+ImageRendering.swift */; }; 8342DC102A8E441B00810258 /* AccessibilitySnapshotView+PillsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8342DC0F2A8E441B00810258 /* AccessibilitySnapshotView+PillsView.swift */; }; @@ -36,6 +37,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 3D63420E2B589032003FB4D3 /* SnapshotAndLegendView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotAndLegendView.swift; sourceTree = ""; }; 3D9D41862B355E970033460C /* HitTargetSnapshotView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HitTargetSnapshotView.swift; sourceTree = ""; }; 3D9D41872B355E970033460C /* UIView+ImageRendering.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+ImageRendering.swift"; sourceTree = ""; }; 8342DC0F2A8E441B00810258 /* AccessibilitySnapshotView+PillsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AccessibilitySnapshotView+PillsView.swift"; sourceTree = ""; }; @@ -106,6 +108,7 @@ EF4D51D42A55A4A400FF0E46 /* Classes */ = { isa = PBXGroup; children = ( + 3D63420E2B589032003FB4D3 /* SnapshotAndLegendView.swift */, 3D9D41862B355E970033460C /* HitTargetSnapshotView.swift */, 3D9D41872B355E970033460C /* UIView+ImageRendering.swift */, 8342DC0F2A8E441B00810258 /* AccessibilitySnapshotView+PillsView.swift */, @@ -295,6 +298,7 @@ EF4D52042A55A69A00FF0E46 /* ASAccessibilityEnabler.m in Sources */, EF4D52022A55A68500FF0E46 /* AccessibilitySnapshotView.swift in Sources */, EF4D52072A55A69A00FF0E46 /* UIAccessibilityStatusUtility.m in Sources */, + 3D63420F2B589032003FB4D3 /* SnapshotAndLegendView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };