diff --git a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift index 4fe1fcc4be6..662d9473043 100644 --- a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift +++ b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift @@ -648,6 +648,12 @@ private func PresentPaymentSheet( configuration.defaultBillingDetails.email = config.email configuration.defaultBillingDetails.phone = config.phone + switch config.style { + case .automatic: configuration.style = .automatic + case .alwaysLight: configuration.style = .alwaysLight + case .alwaysDark: configuration.style = .alwaysDark + } + let isUITest = (ProcessInfo.processInfo.environment["UITesting"] != nil) // disable app-to-app for UI tests configuration.returnURL = isUITest ? nil : "financial-connections-example://redirect" diff --git a/StripeCore/StripeCore/Source/Connections Bindings/ElementsSessionContext.swift b/StripeCore/StripeCore/Source/Connections Bindings/ElementsSessionContext.swift index 507a3a88316..775796e6a60 100644 --- a/StripeCore/StripeCore/Source/Connections Bindings/ElementsSessionContext.swift +++ b/StripeCore/StripeCore/Source/Connections Bindings/ElementsSessionContext.swift @@ -44,6 +44,14 @@ import Foundation } } + /// Intermediary object between `PaymentSheet.Configuration.UserInterfaceStyle` + /// and `FinancialConnectionsSheet.Configuration.UserInterfaceStyle`. + @_spi(STP) @frozen public enum StyleConfig { + case automatic + case alwaysLight + case alwaysDark + } + @_spi(STP) public let amount: Int? @_spi(STP) public let currency: String? @_spi(STP) public let prefillDetails: PrefillDetails? @@ -51,6 +59,7 @@ import Foundation @_spi(STP) public let linkMode: LinkMode? @_spi(STP) public let billingDetails: BillingDetails? @_spi(STP) public let eligibleForIncentive: Bool + @_spi(STP) public let styleConfig: StyleConfig? @_spi(STP) public var billingAddress: BillingAddress? { BillingAddress(from: billingDetails) @@ -70,7 +79,8 @@ import Foundation intentId: IntentID? = nil, linkMode: LinkMode? = nil, billingDetails: BillingDetails? = nil, - eligibleForIncentive: Bool = false + eligibleForIncentive: Bool = false, + styleConfig: StyleConfig? = nil ) { self.amount = amount self.currency = currency @@ -79,6 +89,7 @@ import Foundation self.linkMode = linkMode self.billingDetails = billingDetails self.eligibleForIncentive = eligibleForIncentive + self.styleConfig = styleConfig } } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSDK/FinancialConnectionsSDKImplementation.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSDK/FinancialConnectionsSDKImplementation.swift index c427a01b910..8aa0cbfcc32 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSDK/FinancialConnectionsSDKImplementation.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSDK/FinancialConnectionsSDKImplementation.swift @@ -32,6 +32,16 @@ public class FinancialConnectionsSDKImplementation: FinancialConnectionsSDKInter financialConnectionsSheet.apiClient = apiClient financialConnectionsSheet.elementsSessionContext = elementsSessionContext financialConnectionsSheet.onEvent = onEvent + + var configuration = FinancialConnectionsSheet.Configuration() + if let styleConfig = elementsSessionContext?.styleConfig { + switch styleConfig { + case .automatic: configuration.style = .automatic + case .alwaysLight: configuration.style = .alwaysLight + case .alwaysDark: configuration.style = .alwaysDark + } + } + financialConnectionsSheet.configuration = configuration // Captures self explicitly until the callback is invoked financialConnectionsSheet.present( from: presentingViewController, diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSheet.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSheet.swift index efe7e27b801..f3401891591 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSheet.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/FinancialConnectionsSheet.swift @@ -48,19 +48,21 @@ final public class FinancialConnectionsSheet { @_spi(STP) public struct Configuration { /// Style options for colors in Financial Connections. @_spi(STP) @frozen public enum UserInterfaceStyle { - /// (default) Financial Connections will automatically switch between light and dark mode compatible colors based on device settings. + /// Financial Connections will automatically switch between light and dark mode compatible colors based on device settings. case automatic - /// Financial Connections will always use colors appropriate for light mode UI. + + /// (default) Financial Connections will always use colors appropriate for light mode UI. case alwaysLight + /// Financial Connections will always use colors appropriate for dark mode UI. case alwaysDark /// Applies the specified user interface style to the given view controller. func configure(_ viewController: UIViewController?) { - guard let viewController else { return } guard ExperimentStore.shared.supportsDynamicStyle else { return } + guard let viewController else { return } switch self { case .automatic: diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift index fb45cffe642..2c7f60814ec 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift @@ -1698,6 +1698,7 @@ private func CreatePaneViewController( ) } + // Applies the style configuration to each view controller. dataManager.configuration.style.configure(viewController) return viewController } diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/ExperimentStore.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/ExperimentStore.swift index ea9b6380202..187f90a0677 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/ExperimentStore.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/Shared/ExperimentStore.swift @@ -7,7 +7,8 @@ import Foundation -/// Internal store to access exoerimental features, +/// Internal singleton store to access experimental features. +/// Enabling any of these might result in unexpected behavior. @_spi(STP) public class ExperimentStore { @_spi(STP) public static let shared = ExperimentStore() diff --git a/StripeFinancialConnections/StripeFinancialConnectionsTests/FinancialConnectionsSheetTests.swift b/StripeFinancialConnections/StripeFinancialConnectionsTests/FinancialConnectionsSheetTests.swift index 1fbf15c5821..ccf53e2bf4d 100644 --- a/StripeFinancialConnections/StripeFinancialConnectionsTests/FinancialConnectionsSheetTests.swift +++ b/StripeFinancialConnections/StripeFinancialConnectionsTests/FinancialConnectionsSheetTests.swift @@ -52,8 +52,9 @@ class FinancialConnectionsSheetTests: XCTestCase { apiClient: mockApiClient, analyticsClientV1: mockAnalyticsClient, clientSecret: "test", - elementsSessionContext: nil, returnURL: nil, + configuration: .init(), + elementsSessionContext: nil, publishableKey: "test", stripeAccount: nil ) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Link/LinkPaymentController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Link/LinkPaymentController.swift index 4970dc2ecd1..106b5a969c7 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Link/LinkPaymentController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Link/LinkPaymentController.swift @@ -314,6 +314,14 @@ import UIKit ) ) + let styleConfig: ElementsSessionContext.StyleConfig = { + switch configuration.style { + case .automatic: return .automatic + case .alwaysLight: return .alwaysLight + case .alwaysDark: return .alwaysDark + } + }() + return ElementsSessionContext( amount: mode.amount, currency: mode.currency, @@ -321,7 +329,8 @@ import UIKit intentId: nil, linkMode: nil, billingDetails: billingDetails, - eligibleForIncentive: false + eligibleForIncentive: false, + styleConfig: styleConfig ) } diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift index d0ee9ee63a9..b4d8eec65f8 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentMethodFormViewController.swift @@ -275,6 +275,13 @@ extension PaymentMethodFormViewController { ) let linkMode = elementsSession.linkSettings?.linkMode let billingDetails = instantDebitsFormElement?.billingDetails + let styleConfig: ElementsSessionContext.StyleConfig = { + switch configuration.style { + case .automatic: return .automatic + case .alwaysLight: return .alwaysLight + case .alwaysDark: return .alwaysDark + } + }() return ElementsSessionContext( amount: intent.amount, @@ -283,7 +290,8 @@ extension PaymentMethodFormViewController { intentId: intentId, linkMode: linkMode, billingDetails: billingDetails, - eligibleForIncentive: instantDebitsFormElement?.displayableIncentive != nil + eligibleForIncentive: instantDebitsFormElement?.displayableIncentive != nil, + styleConfig: styleConfig ) }