Skip to content

Commit e5c5153

Browse files
authored
Merge pull request #19182 from wordpress-mobile/task/jetpack-overlay-dismiss-button
Jetpack Overlay - Add dismiss button
2 parents 7c53784 + 61df373 commit e5c5153

6 files changed

Lines changed: 146 additions & 44 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import UIKit
2+
3+
/// Use this UIButton subclass to set a custom background for the button image, different from tintColor and backgroundColor.
4+
/// If there's not image, it has no effect. Supports only circular images.
5+
class CircularImageButton: UIButton {
6+
7+
private lazy var imageBackgroundView: UIView = {
8+
let view = UIView()
9+
view.translatesAutoresizingMaskIntoConstraints = false
10+
return view
11+
}()
12+
13+
14+
/// Sets a custom circular background color below the imageView, different from the button background or tint color
15+
/// - Parameters:
16+
/// - color: the custom background color
17+
/// - ratio: the extent of the background view that lays below the button image view (default: 0.75 of the image view)
18+
func setImageBackgroundColor(_ color: UIColor, ratio: CGFloat = 0.75) {
19+
guard let imageView = imageView else {
20+
return
21+
}
22+
imageBackgroundView.backgroundColor = color
23+
insertSubview(imageBackgroundView, belowSubview: imageView)
24+
imageBackgroundView.clipsToBounds = true
25+
imageBackgroundView.isUserInteractionEnabled = false
26+
NSLayoutConstraint.activate([
27+
imageBackgroundView.centerXAnchor.constraint(equalTo: imageView.centerXAnchor),
28+
imageBackgroundView.centerYAnchor.constraint(equalTo: imageView.centerYAnchor),
29+
imageBackgroundView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: ratio),
30+
imageBackgroundView.widthAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: ratio),
31+
])
32+
}
33+
34+
override func layoutSubviews() {
35+
super.layoutSubviews()
36+
guard imageView != nil else {
37+
return
38+
}
39+
imageBackgroundView.layer.cornerRadius = imageBackgroundView.frame.height / 2
40+
}
41+
}

WordPress/Classes/ViewRelated/Jetpack/Branding/Button/JetpackButton.swift

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import UIKit
22
import SwiftUI
33

44
/// A "Jetpack powered" button with two different styles (`badge` or `banner`)
5-
class JetpackButton: UIButton {
5+
class JetpackButton: CircularImageButton {
66

77
enum ButtonStyle {
88
case badge
@@ -11,13 +11,6 @@ class JetpackButton: UIButton {
1111

1212
private let style: ButtonStyle
1313

14-
private lazy var imageBackgroundView: UIView = {
15-
let view = UIView()
16-
view.backgroundColor = imageBackgroundColor
17-
view.translatesAutoresizingMaskIntoConstraints = false
18-
return view
19-
}()
20-
2114
init(style: ButtonStyle) {
2215
self.style = style
2316
super.init(frame: .zero)
@@ -84,18 +77,7 @@ class JetpackButton: UIButton {
8477
contentEdgeInsets = Appearance.contentInsets
8578
imageView?.contentMode = .scaleAspectFit
8679
flipInsetsForRightToLeftLayoutDirection()
87-
88-
// sets the background of the jp logo to white
89-
if let imageView = imageView {
90-
insertSubview(imageBackgroundView, belowSubview: imageView)
91-
imageBackgroundView.clipsToBounds = true
92-
NSLayoutConstraint.activate([
93-
imageBackgroundView.centerXAnchor.constraint(equalTo: imageView.centerXAnchor),
94-
imageBackgroundView.centerYAnchor.constraint(equalTo: imageView.centerYAnchor),
95-
imageBackgroundView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: Appearance.imageBackgroundViewMultiplier),
96-
imageBackgroundView.widthAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: Appearance.imageBackgroundViewMultiplier),
97-
])
98-
}
80+
setImageBackgroundColor(imageBackgroundColor)
9981
}
10082

10183
private enum Appearance {
@@ -115,7 +97,6 @@ class JetpackButton: UIButton {
11597

11698
override func layoutSubviews() {
11799
super.layoutSubviews()
118-
imageBackgroundView.layer.cornerRadius = imageBackgroundView.frame.height / 2
119100
if style == .badge {
120101
layer.cornerRadius = frame.height / 2
121102
layer.cornerCurve = .continuous

WordPress/Classes/ViewRelated/Jetpack/Branding/Overlay/JetpackOverlayView.swift

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ class JetpackOverlayView: UIView {
55

66
private var buttonAction: (() -> Void)?
77

8+
private var dismissButtonTintColor: UIColor {
9+
UIColor(light: .muriel(color: .gray, .shade5),
10+
dark: .muriel(color: .jetpackGreen, .shade90))
11+
}
12+
13+
private var dismissButtonImage: UIImage {
14+
let fontForSystemImage = UIFont.systemFont(ofSize: Metrics.dismissButtonSize)
15+
let configuration = UIImage.SymbolConfiguration(font: fontForSystemImage)
16+
17+
// fallback to the gridicon if for any reason the system image fails to render
18+
return UIImage(systemName: Graphics.dismissButtonSystemName, withConfiguration: configuration) ??
19+
UIImage.gridicon(.crossCircle, size: CGSize(width: Metrics.dismissButtonSize, height: Metrics.dismissButtonSize))
20+
}
21+
22+
private lazy var dismissButton: CircularImageButton = {
23+
let button = CircularImageButton()
24+
button.translatesAutoresizingMaskIntoConstraints = false
25+
button.setImage(dismissButtonImage, for: .normal)
26+
button.tintColor = dismissButtonTintColor
27+
button.addTarget(self, action: #selector(dismissTapped), for: .touchUpInside)
28+
return button
29+
}()
30+
831
private lazy var stackView: UIStackView = {
932
let stackView = UIStackView(arrangedSubviews: [animationContainerView, titleLabel, descriptionLabel, getJetpackButton])
1033
stackView.translatesAutoresizingMaskIntoConstraints = false
@@ -20,7 +43,7 @@ class JetpackOverlayView: UIView {
2043
}()
2144

2245
private lazy var animationView: AnimationView = {
23-
let animationView = AnimationView(name: Animations.wpJetpackLogoAnimation)
46+
let animationView = AnimationView(name: Graphics.wpJetpackLogoAnimation)
2447
animationView.translatesAutoresizingMaskIntoConstraints = false
2548
return animationView
2649
}()
@@ -29,8 +52,9 @@ class JetpackOverlayView: UIView {
2952
let label = UILabel()
3053
label.adjustsFontForContentSizeCategory = true
3154
label.adjustsFontSizeToFitWidth = true
32-
label.font = WPStyleGuide.fontForTextStyle(.title1, fontWeight: .bold)
33-
label.numberOfLines = 2
55+
label.minimumScaleFactor = Metrics.minimumScaleFactor
56+
label.font = Metrics.titleFont
57+
label.numberOfLines = Metrics.titleLabelNumberOfLines
3458
label.textAlignment = .natural
3559
label.text = TextContent.title
3660
return label
@@ -40,8 +64,9 @@ class JetpackOverlayView: UIView {
4064
let label = UILabel()
4165
label.adjustsFontForContentSizeCategory = true
4266
label.adjustsFontSizeToFitWidth = true
43-
label.font = .preferredFont(forTextStyle: .body)
44-
label.numberOfLines = 0
67+
label.minimumScaleFactor = Metrics.minimumScaleFactor
68+
label.font = Metrics.descriptionFont
69+
label.numberOfLines = Metrics.descriptionLabelNumberOfLines
4570
label.textAlignment = .natural
4671
label.text = TextContent.description
4772
return label
@@ -53,7 +78,7 @@ class JetpackOverlayView: UIView {
5378
button.setTitle(TextContent.buttonTitle, for: .normal)
5479
button.titleLabel?.adjustsFontSizeToFitWidth = true
5580
button.titleLabel?.adjustsFontForContentSizeCategory = true
56-
button.layer.cornerRadius = Metrics.buttonCornerRadius
81+
button.layer.cornerRadius = Metrics.tryJetpackButtonCornerRadius
5782
button.layer.cornerCurve = .continuous
5883
return button
5984
}()
@@ -62,16 +87,25 @@ class JetpackOverlayView: UIView {
6287
buttonAction?()
6388
}
6489

90+
@objc private func dismissTapped() {
91+
guard let presentingViewController = next as? UIViewController else {
92+
return
93+
}
94+
presentingViewController.dismiss(animated: true)
95+
}
96+
6597
private func setup() {
6698
backgroundColor = UIColor(light: .muriel(color: .jetpackGreen, .shade0),
6799
dark: .muriel(color: .jetpackGreen, .shade100))
100+
addSubview(dismissButton)
68101
addSubview(stackView)
69102
stackView.setCustomSpacing(Metrics.imageToTitleSpacing, after: animationContainerView)
70103
stackView.setCustomSpacing(Metrics.titleToDescriptionSpacing, after: titleLabel)
71104
stackView.setCustomSpacing(Metrics.descriptionToButtonSpacing, after: descriptionLabel)
72105
animationContainerView.addSubview(animationView)
73106
getJetpackButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
74107
configureConstraints()
108+
dismissButton.setImageBackgroundColor(UIColor(light: .black, dark: .white))
75109
animationView.play()
76110
}
77111

@@ -87,33 +121,73 @@ class JetpackOverlayView: UIView {
87121

88122
private func configureConstraints() {
89123
animationContainerView.pinSubviewToAllEdges(animationView)
124+
125+
126+
let stackViewTrailingConstraint = stackView.trailingAnchor.constraint(equalTo: trailingAnchor,
127+
constant: -Metrics.edgeMargins.right)
128+
stackViewTrailingConstraint.priority = Metrics.veryHighPriority
129+
let stackViewBottomConstraint = stackView.bottomAnchor.constraint(lessThanOrEqualTo: safeBottomAnchor,
130+
constant: -Metrics.edgeMargins.bottom)
131+
stackViewBottomConstraint.priority = Metrics.veryHighPriority
132+
90133
NSLayoutConstraint.activate([
134+
dismissButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Metrics.dismissButtonPadding),
135+
dismissButton.topAnchor.constraint(equalTo: topAnchor, constant: Metrics.dismissButtonPadding),
136+
dismissButton.heightAnchor.constraint(equalToConstant: Metrics.dismissButtonSize),
137+
dismissButton.widthAnchor.constraint(equalToConstant: Metrics.dismissButtonSize),
91138
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Metrics.edgeMargins.left),
92-
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Metrics.edgeMargins.right),
93-
stackView.topAnchor.constraint(equalTo: topAnchor, constant: Metrics.edgeMargins.top),
94-
stackView.bottomAnchor.constraint(lessThanOrEqualTo: safeBottomAnchor, constant: -Metrics.edgeMargins.bottom),
139+
stackViewTrailingConstraint,
140+
stackView.topAnchor.constraint(equalTo: dismissButton.bottomAnchor),
141+
stackViewBottomConstraint,
95142

96-
getJetpackButton.heightAnchor.constraint(equalToConstant: Metrics.getJetpackButtonHeight),
143+
getJetpackButton.heightAnchor.constraint(equalToConstant: Metrics.tryJetpackButtonHeight),
97144
getJetpackButton.widthAnchor.constraint(equalTo: stackView.widthAnchor),
98145
])
99146
}
100147
}
101148

102-
103149
// MARK: Appearance
104150
private extension JetpackOverlayView {
105151

106-
enum Animations {
107-
static let wpJetpackLogoAnimation = "JetpackWordPressLogoAnimation_mask"
152+
enum Graphics {
153+
static let wpJetpackLogoAnimation = "JetpackWordPressLogoAnimation_left"
154+
static let dismissButtonSystemName = "xmark.circle.fill"
108155
}
109156

110157
enum Metrics {
158+
// stack view
111159
static let imageToTitleSpacing: CGFloat = 24
112160
static let titleToDescriptionSpacing: CGFloat = 20
113161
static let descriptionToButtonSpacing: CGFloat = 40
114-
static let edgeMargins = UIEdgeInsets(top: 46, left: 30, bottom: 30, right: 20)
115-
static let getJetpackButtonHeight: CGFloat = 44
116-
static let buttonCornerRadius: CGFloat = 6
162+
static let edgeMargins = UIEdgeInsets(top: 46, left: 30, bottom: 20, right: 30)
163+
// dismiss button
164+
static let dismissButtonPadding: CGFloat = 20
165+
static let dismissButtonSize: CGFloat = 30
166+
// labels
167+
static let maximumFontSize: CGFloat = 32
168+
static let minimumScaleFactor: CGFloat = 0.6
169+
170+
static let titleLabelNumberOfLines = 2
171+
172+
static let descriptionLabelNumberOfLines = 0
173+
174+
static var titleFont: UIFont {
175+
let weightTrait = [UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold]
176+
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title1).addingAttributes([.traits: weightTrait])
177+
let font = UIFont(descriptor: fontDescriptor, size: min(fontDescriptor.pointSize, maximumFontSize))
178+
return UIFontMetrics.default.scaledFont(for: font, maximumPointSize: maximumFontSize)
179+
}
180+
181+
static var descriptionFont: UIFont {
182+
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
183+
let font = UIFont(descriptor: fontDescriptor, size: min(fontDescriptor.pointSize, maximumFontSize))
184+
return UIFontMetrics.default.scaledFont(for: font, maximumPointSize: maximumFontSize)
185+
}
186+
// "Try Jetpack" button
187+
static let tryJetpackButtonHeight: CGFloat = 44
188+
static let tryJetpackButtonCornerRadius: CGFloat = 6
189+
// constraints
190+
static let veryHighPriority = UILayoutPriority(rawValue: 999)
117191
}
118192

119193
enum TextContent {

0 commit comments

Comments
 (0)