diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Helpers/FinancialConnectionsAppearance.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Helpers/FinancialConnectionsAppearance.swift index e97f0eef306..fd969f0cf76 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Helpers/FinancialConnectionsAppearance.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Helpers/FinancialConnectionsAppearance.swift @@ -24,6 +24,7 @@ struct FinancialConnectionsAppearance: Equatable { static let spinnerNeutral: UIColor = .neutral200 static let warningLight: UIColor = .attention50 static let warning: UIColor = .attention300 + static let shadow: UIColor = .dynamic(light: .black, dark: .neutral0) // These colors change based on the manifest's theme. let primary: UIColor @@ -80,6 +81,10 @@ extension FinancialConnectionsAppearance.Colors { // MARK: - Raw colors private extension UIColor { + static var black: UIColor { + return UIColor(red: 0 / 255.0, green: 0 / 255.0, blue: 0 / 255.0, alpha: 1) // #000000 + } + // MARK: Neutral static var neutral0: UIColor { return UIColor(red: 255 / 255.0, green: 255 / 255.0, blue: 255 / 255.0, alpha: 1) // #ffffff diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Consent/ConsentLogoView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Consent/ConsentLogoView.swift index 9e6279fb99c..c2cfd1f8ee1 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Consent/ConsentLogoView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Consent/ConsentLogoView.swift @@ -15,6 +15,7 @@ private let ellipsisViewWidth: CGFloat = 32.0 final class ConsentLogoView: UIView { private var multipleDotView: UIView? + private var shadowLayers: [CALayer] = [] init(merchantLogo: [String], showsAnimatedDots: Bool) { super.init(frame: .zero) @@ -25,9 +26,9 @@ final class ConsentLogoView: UIView { if merchantLogo.count == 2 || merchantLogo.count == 3 { for i in 0.. UIView { let cornerRadius: CGFloat = 16.0 let shadowContainerView = UIView() - shadowContainerView.layer.shadowColor = UIColor.black.cgColor + shadowContainerView.layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor shadowContainerView.layer.shadowOpacity = 0.18 shadowContainerView.layer.shadowOffset = CGSize(width: 0, height: 3) shadowContainerView.layer.shadowRadius = 5 diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionPickerViewController.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionPickerViewController.swift index fae2a428c47..3f1a2c81f4b 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionPickerViewController.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionPickerViewController.swift @@ -41,6 +41,8 @@ class InstitutionPickerViewController: UIViewController { private let dataSource: InstitutionDataSource weak var delegate: InstitutionPickerViewControllerDelegate? + private var shadowLayer: CALayer? + private lazy var headerView: UIView = { let verticalStackView = UIStackView( arrangedSubviews: [ @@ -88,6 +90,7 @@ class InstitutionPickerViewController: UIViewController { // appear IF the user scrolls up very quickly height: -Self.headerAndSearchBarSpacing ) + self.shadowLayer = verticalStackView.layer return verticalStackView }() private lazy var searchBar: InstitutionSearchBar = { @@ -241,6 +244,14 @@ class InstitutionPickerViewController: UIViewController { animated: true ) } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + shadowLayer?.shadowColor = FinancialConnectionsAppearance.Colors.background.cgColor + } } // MARK: - Data diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionSearchBar.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionSearchBar.swift index cde534544c7..ff98f8a3721 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionSearchBar.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/InstitutionPicker/InstitutionSearchBar.swift @@ -19,6 +19,7 @@ protocol InstitutionSearchBarDelegate: AnyObject { final class InstitutionSearchBar: UIView { private let appearance: FinancialConnectionsAppearance + private var shadowLayer: CALayer? weak var delegate: InstitutionSearchBarDelegate? var text: String { get { @@ -180,6 +181,14 @@ final class InstitutionSearchBar: UIView { height: 1 / UIScreen.main.nativeScale ) } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor + } } // MARK: - UITextFieldDelegate diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/LinkAccountPicker/LinkAccountPickerNewAccountRowView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/LinkAccountPicker/LinkAccountPickerNewAccountRowView.swift index 8f91bc24165..824ae15b7e2 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/LinkAccountPicker/LinkAccountPickerNewAccountRowView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/LinkAccountPicker/LinkAccountPickerNewAccountRowView.swift @@ -50,6 +50,14 @@ final class LinkAccountPickerNewAccountRowView: UIView { @objc private func didTapView() { self.didSelect() } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + layer.borderColor = FinancialConnectionsAppearance.Colors.borderNeutral.cgColor + } } private func CreateIconView(imageUrl: String, appearance: FinancialConnectionsAppearance) -> UIView { diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkLoginWarmup/NetworkingLinkLoginWarmupBodyView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkLoginWarmup/NetworkingLinkLoginWarmupBodyView.swift index 8da2d86fa9f..8d1539d75a4 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkLoginWarmup/NetworkingLinkLoginWarmupBodyView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NetworkingLinkLoginWarmup/NetworkingLinkLoginWarmupBodyView.swift @@ -11,16 +11,26 @@ import Foundation import UIKit final class NetworkingLinkLoginWarmupBodyView: HitTestView { + var borderLayer: CALayer? init(email: String) { super.init(frame: .zero) let emailView = CreateEmailView(email: email) + self.borderLayer = emailView.layer addAndPinSubview(emailView) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + borderLayer?.borderColor = FinancialConnectionsAppearance.Colors.borderNeutral.cgColor + } } private func CreateEmailView( diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PrepaneImageView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PrepaneImageView.swift index b1a2e531329..e53a79a93eb 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PrepaneImageView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PrepaneImageView.swift @@ -13,12 +13,14 @@ import WebKit final class PrepaneImageView: UIView { private let centeringView: UIView + private var imageLayer: CALayer? init(imageURLString: String) { // first we load an image (or GIF) into a WebView let imageView = GIFImageView(gifUrlString: imageURLString) // the WebView is surrounded by a background that imitates the GIF presented inside of a phone - let phoneBackgroundView = CreatePhoneBackgroundView(imageView: imageView) + let (phoneBackgroundView, imageLayer) = CreatePhoneBackgroundView(imageView: imageView) + self.imageLayer = imageLayer // we center the phone+gif in the middle let centeringView = CreateCenteringView(centeredView: phoneBackgroundView) self.centeringView = centeringView @@ -65,9 +67,18 @@ final class PrepaneImageView: UIView { maskLayer.path = path layer.mask = maskLayer } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + imageLayer?.borderColor = FinancialConnectionsAppearance.Colors.backgroundSecondary.cgColor + imageLayer?.shadowColor = FinancialConnectionsAppearance.Colors.borderNeutral.cgColor + } } -private func CreatePhoneBackgroundView(imageView: UIView) -> UIView { +private func CreatePhoneBackgroundView(imageView: UIView) -> (UIView, CALayer) { let containerView = UIView() let borderWidth: CGFloat = 8 imageView.layer.borderWidth = borderWidth @@ -84,7 +95,7 @@ private func CreatePhoneBackgroundView(imageView: UIView) -> UIView { trailing: 0 ) ) - return containerView + return (containerView, imageView.layer) } private func CreateCenteringView(centeredView: UIView) -> UIView { diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/AccountPickerRowView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/AccountPickerRowView.swift index 506d09389fa..a461df9cff9 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/AccountPickerRowView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/AccountPickerRowView.swift @@ -15,29 +15,7 @@ final class AccountPickerRowView: UIView { private let didSelect: () -> Void private var isSelected: Bool = false { didSet { - layer.cornerRadius = 12 - if isSelected { - layer.borderColor = appearance.colors.border.cgColor - layer.borderWidth = 2 - let shadowWidthOffset: CGFloat = 0 - layer.shadowPath = CGPath( - roundedRect: CGRect(x: shadowWidthOffset / 2, y: 0, width: bounds.width - shadowWidthOffset, height: bounds.height), - cornerWidth: layer.cornerRadius, - cornerHeight: layer.cornerRadius, - transform: nil - ) - layer.shadowColor = UIColor.black.cgColor - layer.shadowRadius = 1.5 / UIScreen.main.nativeScale - layer.shadowOpacity = 0.23 - layer.shadowOffset = CGSize( - width: 0, - height: 1 / UIScreen.main.nativeScale - ) - } else { - layer.borderColor = FinancialConnectionsAppearance.Colors.borderNeutral.cgColor - layer.borderWidth = 1 - layer.shadowOpacity = 0 - } + updateLayer() checkboxView.isSelected = isSelected } } @@ -142,6 +120,40 @@ final class AccountPickerRowView: UIView { @objc private func didTapView() { self.didSelect() } + + private func updateLayer() { + layer.cornerRadius = 12 + if isSelected { + layer.borderColor = appearance.colors.border.cgColor + layer.borderWidth = 2 + let shadowWidthOffset: CGFloat = 0 + layer.shadowPath = CGPath( + roundedRect: CGRect(x: shadowWidthOffset / 2, y: 0, width: bounds.width - shadowWidthOffset, height: bounds.height), + cornerWidth: layer.cornerRadius, + cornerHeight: layer.cornerRadius, + transform: nil + ) + layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor + layer.shadowRadius = 1.5 / UIScreen.main.nativeScale + layer.shadowOpacity = 0.23 + layer.shadowOffset = CGSize( + width: 0, + height: 1 / UIScreen.main.nativeScale + ) + } else { + layer.borderColor = FinancialConnectionsAppearance.Colors.borderNeutral.cgColor + layer.borderWidth = 1 + layer.shadowOpacity = 0 + } + } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + updateLayer() + } } private func CreateHorizontalStackView(arrangedSubviews: [UIView]) -> UIStackView { diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/Button+Extensions.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/Button+Extensions.swift index 01e6e103f3c..512067ec9a8 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/Button+Extensions.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/Button+Extensions.swift @@ -12,7 +12,7 @@ import UIKit extension StripeUICore.Button { static func primary(appearance: FinancialConnectionsAppearance) -> StripeUICore.Button { let button = Button(configuration: .financialConnectionsPrimary(appearance: appearance)) - button.layer.shadowColor = UIColor.black.cgColor + button.layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor button.layer.shadowRadius = 5 / UIScreen.main.nativeScale button.layer.shadowOpacity = 0.25 button.layer.shadowOffset = CGSize( diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/PaneLayoutView.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/PaneLayoutView.swift index c65af662951..cdca2f049de 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/PaneLayoutView.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/PaneLayoutView.swift @@ -229,4 +229,12 @@ private class AutomaticShadowScrollView: UIScrollView { shadowView.alpha = remainingFadeDistance / startFadingDistanceToBottom } } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + shadowView?.layer.shadowColor = FinancialConnectionsAppearance.Colors.textDefault.cgColor + } } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/RoundedTextField.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/RoundedTextField.swift index 68dcb4f123e..1322b87fe0c 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/RoundedTextField.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/RoundedTextField.swift @@ -57,7 +57,7 @@ final class RoundedTextField: UIView { trailing: 16 ) containerStackView.layer.cornerRadius = 12 - containerStackView.layer.shadowColor = UIColor.black.cgColor + containerStackView.layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor containerStackView.layer.shadowRadius = 2 / UIScreen.main.nativeScale containerStackView.layer.shadowOpacity = 0.1 containerStackView.layer.shadowOffset = CGSize( @@ -190,8 +190,6 @@ final class RoundedTextField: UIView { } private func updateBorder(highlighted: Bool) { - let highlighted = textField.isFirstResponder - if errorText != nil && !highlighted { containerHorizontalStackView.layer.borderColor = FinancialConnectionsAppearance.Colors.textCritical.cgColor containerHorizontalStackView.layer.borderWidth = 2.0 @@ -209,6 +207,15 @@ final class RoundedTextField: UIView { @IBAction private func textFieldDidChange() { delegate?.roundedTextField(self, textDidChange: text) } + + // CGColor's need to be manually updated when the system theme changes. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + guard traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) else { return } + + updateBorder(highlighted: textField.isFirstResponder) + containerHorizontalStackView.layer.shadowColor = FinancialConnectionsAppearance.Colors.shadow.cgColor + } } // MARK: - UITextFieldDelegate diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift index b4d8eec65f8..7ad36b62816 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift @@ -173,10 +173,10 @@ extension PaymentMethodFormViewController: ElementDelegate { analyticsHelper.logFormInteracted(paymentMethodTypeIdentifier: paymentMethodType.identifier) delegate?.didUpdate(self) animateHeightChange() - + if let instantDebitsFormElement = form as? InstantDebitsPaymentMethodElement { let incentive = instantDebitsFormElement.displayableIncentive - + if let formHeaderView = headerView as? FormHeaderView { // We already display a promo badge in the bank form, so we don't want // to display another one in the header.