From 49a9b6781f2f3eb2b3b1e132dfe17c1ce57016ed Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 12:02:11 +0200 Subject: [PATCH 01/11] Fix attributed string builder crash --- .../AttributedStringBuilder/AttributedStringBuilder.swift | 4 +++- .../AttributedStringMarkdownVisitor.swift | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift index 15701c7a6..e8063e670 100644 --- a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift +++ b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift @@ -7,6 +7,7 @@ import SwiftUI +@available(iOS 14.0, *) struct AttributedStringBuilder { /// The typography of the text. @@ -55,7 +56,7 @@ struct AttributedStringBuilder { let lineHeightMultiple = typography.lineHeight / typography.font.lineHeight attributes[.font] = font attributes[.baselineOffset] = Self.baselineOffset(font: font, lineHeightMultiple: lineHeightMultiple) - attributes[.foregroundColor] = color + attributes[.foregroundColor] = UIColor(color) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.maximumLineHeight = font.lineHeight * lineHeightMultiple paragraphStyle.minimumLineHeight = font.lineHeight * lineHeightMultiple @@ -96,6 +97,7 @@ struct AttributedStringBuilder { } } +@available(iOS 14.0, *) extension AttributedStringBuilder { func with(updates: (inout AttributedStringBuilder) -> Void) -> AttributedStringBuilder { diff --git a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringMarkdownVisitor.swift b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringMarkdownVisitor.swift index f7a4deb98..74cbe349a 100644 --- a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringMarkdownVisitor.swift +++ b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringMarkdownVisitor.swift @@ -8,6 +8,7 @@ import Foundation import UIKit +@available(iOS 14.0, *) final class AttributedStringMarkdownVisitor: MarkdownVisitor { init(builder: AttributedStringBuilder, level: Int = 0) { From a3a274021ae1baaa42a3198149129a94a1c2f80e Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 12:02:35 +0200 Subject: [PATCH 02/11] Avoid using attributed string builder in text field --- .../DesignSystem/TextField/POTextField.swift | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/ProcessOutCoreUI/Sources/DesignSystem/TextField/POTextField.swift b/Sources/ProcessOutCoreUI/Sources/DesignSystem/TextField/POTextField.swift index 812918102..745e66425 100644 --- a/Sources/ProcessOutCoreUI/Sources/DesignSystem/TextField/POTextField.swift +++ b/Sources/ProcessOutCoreUI/Sources/DesignSystem/TextField/POTextField.swift @@ -78,11 +78,17 @@ private enum Constants { @available(iOS 14, *) private struct TextFieldRepresentable: UIViewRepresentable { - @Binding - var text: String + init(text: Binding, formatter: Formatter?, style: POInputStateStyle) { + self._text = text + self.formatter = formatter + self.style = style + _multiplier = .init(wrappedValue: 1, relativeTo: style.text.typography.textStyle) + } let formatter: Formatter? - let style: POInputStateStyle + + @Binding + var text: String // MARK: - UIViewRepresentable @@ -124,13 +130,14 @@ private struct TextFieldRepresentable: UIViewRepresentable { private enum Constants { static let animationDuration: TimeInterval = 0.25 - static let includedTextAttributes: Set = [.foregroundColor, .font] } // MARK: - Private Properties - @Environment(\.sizeCategory) - private var sizeCategory + private let style: POInputStateStyle + + @POBackport.ScaledMetric + private var multiplier: CGFloat @Environment(\.poKeyboardType) private var keyboardType @@ -153,15 +160,8 @@ private struct TextFieldRepresentable: UIViewRepresentable { if textField.text != text { textField.text = text } - let builder = AttributedStringBuilder( - typography: style.text.typography, - sizeCategory: .init(sizeCategory), - color: style.text.color - ) - let textAttributes = builder - .buildAttributes() - .filter { Constants.includedTextAttributes.contains($0.key) } - textField.defaultTextAttributes = textAttributes + textField.font = style.text.typography.font.withSize(style.text.typography.font.pointSize * multiplier) + textField.textColor = UIColor(style.text.color) } } From fef60970050c66a03521a5446aa26bcae91e4b26 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 12:03:28 +0200 Subject: [PATCH 03/11] Make attributes private --- .../AttributedStringBuilder.swift | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift index e8063e670..6095e8c47 100644 --- a/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift +++ b/Sources/ProcessOutCoreUI/Sources/Core/AttributedStringBuilder/AttributedStringBuilder.swift @@ -50,7 +50,9 @@ struct AttributedStringBuilder { return NSAttributedString(string: string, attributes: attributes) } - func buildAttributes() -> [NSAttributedString.Key: Any] { + // MARK: - Private Methods + + private func buildAttributes() -> [NSAttributedString.Key: Any] { let font = font(typography: typography) var attributes: [NSAttributedString.Key: Any] = [:] let lineHeightMultiple = typography.lineHeight / typography.font.lineHeight @@ -70,18 +72,6 @@ struct AttributedStringBuilder { return attributes } - // MARK: - Private Methods - - private static func baselineOffset(font: UIFont, lineHeightMultiple: CGFloat) -> CGFloat { - let offset = (font.lineHeight * lineHeightMultiple - font.capHeight) / 2 + font.descender - if #available(iOS 16, *) { - return offset - } - // Workaround for bug in UIKit. In order to shift baseline to the top, offset should be divided - // by two on iOS < 16. - return offset < 0 ? offset : offset / 2 - } - private func font(typography: POTypography) -> UIFont { var font = typography.font if let textStyle = typography.textStyle { @@ -95,6 +85,16 @@ struct AttributedStringBuilder { } return font.addingFeatures(fontFeatures) } + + private static func baselineOffset(font: UIFont, lineHeightMultiple: CGFloat) -> CGFloat { + let offset = (font.lineHeight * lineHeightMultiple - font.capHeight) / 2 + font.descender + if #available(iOS 16, *) { + return offset + } + // Workaround for bug in UIKit. In order to shift baseline to the top, offset should be divided + // by two on iOS < 16. + return offset < 0 ? offset : offset / 2 + } } @available(iOS 14.0, *) From 1be94f25e2baf5e080e752e6b40c9a916ce5f14f Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 12:16:25 +0200 Subject: [PATCH 04/11] Prevent crash --- .../DynamicCheckout/PODynamicCheckoutPaymentMethod.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/ProcessOut/Sources/Repositories/Invoices/Responses/DynamicCheckout/PODynamicCheckoutPaymentMethod.swift b/Sources/ProcessOut/Sources/Repositories/Invoices/Responses/DynamicCheckout/PODynamicCheckoutPaymentMethod.swift index 411266fe9..8ce253368 100644 --- a/Sources/ProcessOut/Sources/Repositories/Invoices/Responses/DynamicCheckout/PODynamicCheckoutPaymentMethod.swift +++ b/Sources/ProcessOut/Sources/Repositories/Invoices/Responses/DynamicCheckout/PODynamicCheckoutPaymentMethod.swift @@ -296,7 +296,6 @@ extension PODynamicCheckoutPaymentMethod { case .customerToken(let method): return method.id case .unknown(let method): - assertionFailure("It is considered an error to request an ID for unknown payment method.") return method.id } } From de7d609f4e6d1a7649f2bc43fb94b8b33e3ac7c9 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:03:15 +0200 Subject: [PATCH 05/11] Lower precondition to assert --- .../Interactor/NativeAlternativePaymentDefaultInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift index c53011ae3..5b4a4f0ed 100644 --- a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift +++ b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift @@ -513,7 +513,7 @@ final class NativeAlternativePaymentDefaultInteractor: switch parameter.specification.type { case .singleSelect: let availableValues = parameter.specification.availableValues?.map(\.value) ?? [] - precondition(availableValues.contains(value), "Unknown `singleSelect` parameter value.") + assert(availableValues.contains(value), "Unknown `singleSelect` parameter value.") defaultValue = value default: defaultValue = parameter.formatter?.string(for: value) ?? value From 2c6c9a5cf6c86b9e857969a22513d30c0f50cecc Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:03:35 +0200 Subject: [PATCH 06/11] Update message --- .../PassKit/DynamicCheckoutPassKitPaymentDefaultSession.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Sessions/PassKit/DynamicCheckoutPassKitPaymentDefaultSession.swift b/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Sessions/PassKit/DynamicCheckoutPassKitPaymentDefaultSession.swift index d3dafad82..dfe27d0a5 100644 --- a/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Sessions/PassKit/DynamicCheckoutPassKitPaymentDefaultSession.swift +++ b/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Sessions/PassKit/DynamicCheckoutPassKitPaymentDefaultSession.swift @@ -55,7 +55,7 @@ extension DynamicCheckoutPassKitPaymentDefaultSession: POPassKitPaymentAuthoriza func paymentAuthorizationControllerDidFinish(_ controller: POPassKitPaymentAuthorizationController) { guard let didFinishContinuation else { - preconditionFailure("Continue must be set.") + preconditionFailure("Continuation must be set.") } didFinishContinuation.resume() } From b7811236950da266548ca71cc4da868bf188f048 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:03:52 +0200 Subject: [PATCH 07/11] Replace assert with main actor --- .../ProcessOut/Sources/Core/Extensions/UIImage+Dynamic.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ProcessOut/Sources/Core/Extensions/UIImage+Dynamic.swift b/Sources/ProcessOut/Sources/Core/Extensions/UIImage+Dynamic.swift index ca5969e16..2e68d34da 100644 --- a/Sources/ProcessOut/Sources/Core/Extensions/UIImage+Dynamic.swift +++ b/Sources/ProcessOut/Sources/Core/Extensions/UIImage+Dynamic.swift @@ -9,9 +9,9 @@ import UIKit extension UIImage { + @MainActor static func dynamic(lightImage: UIImage?, darkImage: UIImage?) -> UIImage? { - assert(Thread.isMainThread) - // When image with scale greater than 3 is registed asset created explicitly produced image + // When image with scale greater than 3 is registered asset created explicitly produced image // is malformed and doesn't contain images for light nor dark styles. guard let image = lightImage ?? darkImage else { return nil From 342131ee0a185235dd7442391c3f5f174409830b Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:04:09 +0200 Subject: [PATCH 08/11] Fix input submission crash --- .../Sources/Backports/OnSubmit/View+OnSubmit.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ProcessOutCoreUI/Sources/Backports/OnSubmit/View+OnSubmit.swift b/Sources/ProcessOutCoreUI/Sources/Backports/OnSubmit/View+OnSubmit.swift index 16d97b214..2a9d6a3aa 100644 --- a/Sources/ProcessOutCoreUI/Sources/Backports/OnSubmit/View+OnSubmit.swift +++ b/Sources/ProcessOutCoreUI/Sources/Backports/OnSubmit/View+OnSubmit.swift @@ -10,7 +10,7 @@ import SwiftUI extension POBackport where Wrapped: Any { @MainActor - final class SubmitAction: Sendable { + struct SubmitAction: Sendable { typealias Action = () -> Void // swiftlint:disable:this nesting @@ -22,7 +22,7 @@ extension POBackport where Wrapped: Any { actions.forEach { $0() } } - func append(action: @escaping Action) { + mutating func append(action: @escaping Action) { actions.append(action) } From 33722fb85b8f9c8ba7c4455297c076868c9614d4 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:06:56 +0200 Subject: [PATCH 09/11] Use main actor instead of assert --- .../DynamicCheckout/DynamicCheckoutDefaultInteractor.swift | 2 +- .../Interactor/NativeAlternativePaymentDefaultInteractor.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Interactor/DynamicCheckout/DynamicCheckoutDefaultInteractor.swift b/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Interactor/DynamicCheckout/DynamicCheckoutDefaultInteractor.swift index f5ff8ae7c..b1d6cab76 100644 --- a/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Interactor/DynamicCheckout/DynamicCheckoutDefaultInteractor.swift +++ b/Sources/ProcessOutUI/Sources/Modules/DynamicCheckout/Interactor/DynamicCheckout/DynamicCheckoutDefaultInteractor.swift @@ -690,8 +690,8 @@ final class DynamicCheckoutDefaultInteractor: // MARK: - Events + @MainActor private func send(event: PODynamicCheckoutEvent) { - assert(Thread.isMainThread, "Method should be called on main thread.") logger.debug("Did send event: '\(event)'") delegate?.dynamicCheckout(didEmitEvent: event) } diff --git a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift index 5b4a4f0ed..52f387ac4 100644 --- a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift +++ b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift @@ -403,8 +403,8 @@ final class NativeAlternativePaymentDefaultInteractor: // MARK: - Events + @MainActor private func send(event: PONativeAlternativePaymentEvent) { - assert(Thread.isMainThread, "Method should be called on main thread.") logger.debug("Did send event: '\(event)'") delegate?.nativeAlternativePaymentDidEmitEvent(event) } From d44563e68421ba6cf3bae6dc428013a4b7a53e44 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Tue, 13 Aug 2024 13:18:55 +0200 Subject: [PATCH 10/11] Bump Xcode --- .github/actions/bootstrap-project/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/bootstrap-project/action.yml b/.github/actions/bootstrap-project/action.yml index 58b5cca45..67af23f13 100644 --- a/.github/actions/bootstrap-project/action.yml +++ b/.github/actions/bootstrap-project/action.yml @@ -17,7 +17,7 @@ runs: shell: bash - name: Select Xcode Version # todo(andrii-vysotskyi): Migrate to public release once available - run: sudo xcode-select -s '/Applications/Xcode_16_beta_4.app/Contents/Developer' + run: sudo xcode-select -s '/Applications/Xcode_16_beta_5.app/Contents/Developer' shell: bash - name: Bootstrap Project run: ./Scripts/BootstrapProject.sh From 94c2e49c71523d65d96094f9eb341dc513591449 Mon Sep 17 00:00:00 2001 From: Andrii Vysotskyi Date: Wed, 14 Aug 2024 11:50:16 +0200 Subject: [PATCH 11/11] Revert "Bump Xcode" This reverts commit d44563e68421ba6cf3bae6dc428013a4b7a53e44. --- .github/actions/bootstrap-project/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/bootstrap-project/action.yml b/.github/actions/bootstrap-project/action.yml index 67af23f13..58b5cca45 100644 --- a/.github/actions/bootstrap-project/action.yml +++ b/.github/actions/bootstrap-project/action.yml @@ -17,7 +17,7 @@ runs: shell: bash - name: Select Xcode Version # todo(andrii-vysotskyi): Migrate to public release once available - run: sudo xcode-select -s '/Applications/Xcode_16_beta_5.app/Contents/Developer' + run: sudo xcode-select -s '/Applications/Xcode_16_beta_4.app/Contents/Developer' shell: bash - name: Bootstrap Project run: ./Scripts/BootstrapProject.sh