Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REPLAY-1510 Button image background support #1240

Merged
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we could benefit from decomposing this snapshot into multiple ones. WDYT @maciejburda ?

Right now it is a single snapshot that lists dozen of images in different configurations. It's not obvious to me:

  • which configurations do we cover vs which not?
  • what exactly to fix if something breaks?
  • how to add new configurations to this snapshot to not override existing ones?

Same as we prefer multiple unit tests over single complex one, I believe that dividing snapshots into smaller chunks could be healthy in the long term.

Copy link
Member Author

@maciejburda maciejburda Apr 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - perfectly valid point. I started to wonder about this as well.

I'll simplify the snapshot and some labels explaining the use cases, but in the next PR that also touches this storyboard.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand All @@ -25,15 +26,15 @@
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="apple.logo" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="KF9-wK-Okh">
<rect key="frame" x="166" y="171.33333333333334" width="61" height="59.333333333333343"/>
<rect key="frame" x="184.66666666666666" y="171.33333333333334" width="24" height="22.333333333333343"/>
<color key="tintColor" systemColor="systemPurpleColor"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="QrF-HG-Jtn"/>
<constraint firstAttribute="height" constant="61" id="rFX-W6-8HU"/>
<constraint firstAttribute="width" constant="24" id="QrF-HG-Jtn"/>
<constraint firstAttribute="height" constant="24" id="rFX-W6-8HU"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" alignment="center" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="zQI-BZ-L2g">
<rect key="frame" x="0.0" y="248" width="393" height="288"/>
<rect key="frame" x="0.0" y="211" width="393" height="288"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="n6y-pj-DAN">
<rect key="frame" x="52.666666666666657" y="0.0" width="288" height="60"/>
Expand Down Expand Up @@ -183,7 +184,7 @@
</subviews>
</stackView>
<tabBar contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="raw-wh-zEy">
<rect key="frame" x="0.0" y="552" width="393" height="49"/>
<rect key="frame" x="0.0" y="515" width="393" height="49"/>
<constraints>
<constraint firstAttribute="height" constant="49" id="t9n-YU-wtJ"/>
</constraints>
Expand All @@ -198,7 +199,7 @@
</items>
</tabBar>
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ftc-4B-7Pp">
<rect key="frame" x="0.0" y="617" width="393" height="44"/>
<rect key="frame" x="0.0" y="580" width="393" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="4hr-VJ-mh1"/>
</constraints>
Expand All @@ -210,35 +211,57 @@
</items>
</navigationBar>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="vKz-Ut-7bS">
<rect key="frame" x="156.66666666666666" y="677" width="80" height="80"/>
<rect key="frame" x="156.66666666666666" y="640" width="80" height="80"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="YUK-jg-T8h"/>
<constraint firstAttribute="height" constant="80" id="zPr-qF-VOv"/>
</constraints>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KxN-zV-mGU">
<rect key="frame" x="252.66666666666666" y="85" width="124.33333333333334" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="HaR-cP-xUI"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Button" image="face.dashed.fill" catalog="system">
<color key="titleColor" name="AccentColor"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="clipsToBounds" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="8"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="vKz-Ut-7bS" firstAttribute="top" secondItem="ftc-4B-7Pp" secondAttribute="bottom" constant="16" id="2KW-Vg-MSH"/>
<constraint firstItem="raw-wh-zEy" firstAttribute="top" secondItem="zQI-BZ-L2g" secondAttribute="bottom" constant="16" id="3Tf-N7-p6F"/>
<constraint firstItem="vDu-zF-Fre" firstAttribute="trailing" secondItem="KxN-zV-mGU" secondAttribute="trailing" constant="16" id="Cj8-dU-3FG"/>
<constraint firstItem="raw-wh-zEy" firstAttribute="leading" secondItem="vDu-zF-Fre" secondAttribute="leading" id="ET0-BN-qth"/>
<constraint firstItem="zQI-BZ-L2g" firstAttribute="leading" secondItem="vDu-zF-Fre" secondAttribute="leading" id="OAe-l4-L39"/>
<constraint firstItem="xxq-Cw-MRl" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="OTN-dD-tUV"/>
<constraint firstItem="ftc-4B-7Pp" firstAttribute="leading" secondItem="vDu-zF-Fre" secondAttribute="leading" id="OuL-9P-SDJ"/>
<constraint firstItem="ftc-4B-7Pp" firstAttribute="trailing" secondItem="vDu-zF-Fre" secondAttribute="trailing" id="P5h-A7-U1M"/>
<constraint firstItem="zQI-BZ-L2g" firstAttribute="top" secondItem="KF9-wK-Okh" secondAttribute="bottom" constant="16" id="PcY-W5-rVM"/>
<constraint firstItem="ftc-4B-7Pp" firstAttribute="top" secondItem="raw-wh-zEy" secondAttribute="bottom" constant="16" id="TIg-KH-e5o"/>
<constraint firstItem="KxN-zV-mGU" firstAttribute="leading" secondItem="xxq-Cw-MRl" secondAttribute="trailing" constant="16" id="VVE-7k-3Tk"/>
<constraint firstItem="vDu-zF-Fre" firstAttribute="trailing" secondItem="zQI-BZ-L2g" secondAttribute="trailing" id="Wjg-fd-LWW"/>
<constraint firstItem="KF9-wK-Okh" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="bah-mp-OGG"/>
<constraint firstItem="KF9-wK-Okh" firstAttribute="top" secondItem="xxq-Cw-MRl" secondAttribute="bottom" constant="16" id="d96-un-7EN"/>
<constraint firstItem="raw-wh-zEy" firstAttribute="trailing" secondItem="vDu-zF-Fre" secondAttribute="trailing" id="iAJ-aX-zcr"/>
<constraint firstItem="vKz-Ut-7bS" firstAttribute="centerX" secondItem="vDu-zF-Fre" secondAttribute="centerX" id="iGo-IL-Tk7"/>
<constraint firstItem="xxq-Cw-MRl" firstAttribute="top" secondItem="vDu-zF-Fre" secondAttribute="top" constant="16" id="jIN-YZ-8QX"/>
<constraint firstItem="KxN-zV-mGU" firstAttribute="centerY" secondItem="xxq-Cw-MRl" secondAttribute="centerY" id="wlR-Fb-T22"/>
</constraints>
</view>
<connections>
<outlet property="customButton" destination="KxN-zV-mGU" id="zX2-X5-J8J"/>
<outlet property="customImageView" destination="vKz-Ut-7bS" id="aJg-Sy-OrB"/>
<outlet property="navigationBar" destination="ftc-4B-7Pp" id="Cz6-ki-X2T"/>
<outlet property="tabBar" destination="raw-wh-zEy" id="TaQ-44-tXa"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
Expand All @@ -253,6 +276,7 @@
<image name="book" catalog="system" width="128" height="99"/>
<image name="dd_logo" width="100" height="100"/>
<image name="exclamationmark.icloud" catalog="system" width="128" height="90"/>
<image name="face.dashed.fill" catalog="system" width="128" height="123"/>
<image name="flag.2.crossed" catalog="system" width="128" height="72"/>
<image name="gearshape.fill" catalog="system" width="128" height="123"/>
<image name="list.bullet.below.rectangle" catalog="system" width="128" height="110"/>
Expand All @@ -268,6 +292,9 @@
<image name="sun.dust" catalog="system" width="128" height="120"/>
<image name="volume.2.fill" catalog="system" width="128" height="88"/>
<image name="wallet.pass" catalog="system" width="115" height="128"/>
<namedColor name="AccentColor">
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,36 @@
import UIKit

internal class ImagesViewController: UIViewController {
@IBOutlet weak var customButton: UIButton!
@IBOutlet weak var customImageView: UIImageView!
@IBOutlet weak var tabBar: UITabBar!
@IBOutlet weak var navigationBar: UINavigationBar!

override func viewDidLoad() {
super.viewDidLoad()

let color = UIColor(white: 0, alpha: 0.05)
customButton.setBackgroundImage(UIImage(color: color), for: .normal)

tabBar.backgroundImage = UIImage(color: color)
tabBar.selectedItem = tabBar.items?.first
navigationBar.setBackgroundImage(UIImage(color: color), for: .default)

customImageView.image = UIImage(named: "dd_logo")?.withRenderingMode(.alwaysTemplate)
}
}

fileprivate extension UIImage {
convenience init?(color: UIColor, size: CGSize = CGSize(width: 1.0, height: 1.0)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 1.0)
defer { UIGraphicsEndImageContext() }

guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.setFillColor(color.cgColor)
context.fill(rect)

guard let cgImage = context.makeImage() else { return nil }
self.init(cgImage: cgImage)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,20 @@ internal struct UIImageViewRecorder: NodeRecorder {
private let shouldRecordImagePredicate: (UIImageView) -> Bool
/// An option for overriding default semantics from parent recorder.
var semanticsOverride: (UIImageView, ViewAttributes) -> NodeSemantics? = { imageView, _ in
let className = "\(type(of: imageView))"
// This gets effective on iOS 15.0+ which is the earliest version that displays some elements in popover views.
// Here we explicitly ignore the "shadow" effect applied to popover.
let isSystemShadow = className == "_UICutoutShadowView"
return isSystemShadow ? IgnoredElement(subtreeStrategy: .ignore) : nil
return imageView.isSystemShadow ? IgnoredElement(subtreeStrategy: .ignore) : nil
}

internal init(
tintColorProvider: @escaping (UIImageView) -> UIColor? = { imageView in
if #available(iOS 13.0, *), let image = imageView.image {
return image.isSymbolImage || image.isAlwaysTemplate ? imageView.tintColor : nil
return image.isTinted ? imageView.tintColor : nil
} else {
return nil
}
},
shouldRecordImagePredicate: @escaping (UIImageView) -> Bool = { imageView in
if #available(iOS 13.0, *), let image = imageView.image {
return image.isSymbolImage || image.isBundled || image.isAlwaysTemplate
return image.isContextual || imageView.isSystemControlBackground
} else {
return false
}
Expand Down Expand Up @@ -144,7 +140,6 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder {
tintColor: tintColor
)
}

if let contentFrame = contentFrame {
wireframes.append(
builder.createImageWireframe(
Expand All @@ -160,11 +155,49 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder {
}

fileprivate extension UIImage {
var isBundled: Bool {
@available(iOS 13.0, *)
var isContextual: Bool {
return isSymbolImage || isBundled || isAlwaysTemplate
}

@available(iOS 13.0, *)
var isTinted: Bool {
return isSymbolImage || isAlwaysTemplate
}

private var isBundled: Bool {
return description.contains("named(")
}

var isAlwaysTemplate: Bool {
private var isAlwaysTemplate: Bool {
return renderingMode == .alwaysTemplate
}
}

fileprivate extension UIImageView {
var isSystemControlBackground: Bool {
return isButtonBackground || isBarBackground
}

var isSystemShadow: Bool {
let className = "\(type(of: self))"
// This gets effective on iOS 15.0+ which is the earliest version that displays some elements in popover views.
// Here we explicitly ignore the "shadow" effect applied to popover.
return className == "_UICutoutShadowView"
}

var isButtonBackground: Bool {
if let button = superview as? UIButton, button.buttonType == .custom {
return button.backgroundImage(for: button.state) == image
}
return false
}

var isBarBackground: Bool {
guard let superview = superview else {
return false
}
let superViewType = "\(type(of: superview))"
return superViewType == "_UIBarBackground"
}
}