diff --git a/CHANGES.md b/CHANGES.md index 08a1f11f..a4677219 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,8 @@ Use list notation, and following prefixes: - Docs - for any improvement to documentation ### Changes -- Fix: issue with no size found text +- Bugfix: set button height to zero on error +- Bugfix: Virtusize button state when loading a new product ### 2.12.21 - Bugfix: Added async Task cancellation to fix concurrency crash diff --git a/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageMini.swift b/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageMini.swift index 92866118..73271c1c 100644 --- a/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageMini.swift +++ b/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageMini.swift @@ -56,7 +56,10 @@ public struct SwiftUIVirtusizeInPageMini: View { uiKitView: uiView, defaultStyle: virtusizeDefaultStyle ) - .frame(width: desiredSize.width, height: max(desiredSize.height, 35), alignment: .center) + .frame(width: desiredSize.width, height: desiredSize.height == 0 ? 0.1 : max(desiredSize.height, 35), alignment: .center) + .opacity(desiredSize.height == 0 ? 0 : 1) + .frame(height: desiredSize.height == 0 ? 0.1 : nil) + .clipped() } } @@ -122,9 +125,12 @@ private struct VirtusizeInPageMiniWrapper: UIViewRepresentable { uiView.setContentViewListener(listener: { view in if let label = (view as? VirtusizeInPageMini)?.inPageMiniMessageLabel { + // Set height to 0 if product is invalid, there's an error, or view is hidden + let calculatedHeight = label.text?.height(width: label.frame.width, font: label.font) ?? 35 + let height = (view.invalidProduct || view.isError || view.isHidden) ? 0 : calculatedHeight desiredSize = CGSize( width: UIScreen.main.bounds.size.width - uiView.userSetMargin * 2, - height: label.text?.height(width: label.frame.width, font: label.font) ?? 35 + height: height ) } }) diff --git a/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageStandard.swift b/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageStandard.swift index 400e99c7..0e2a5792 100644 --- a/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageStandard.swift +++ b/Virtusize/Sources/SwiftUI/SwiftUIVirtusizeInPageStandard.swift @@ -52,13 +52,16 @@ public struct SwiftUIVirtusizeInPageStandard: View { VirtusizeInPageStandardWrapper( product: product, desiredSize: $desiredSize, - horizontalMargin: $horizontalMargin, + horizontalMargin: $horizontalMargin, action: action, uiView: uiView, defaultStyle: virtusizeDefaultStyle ) - .offset(x: horizontalMargin) - .frame(width: desiredSize.width, height: max(desiredSize.height, 92), alignment: .center) + .offset(x: horizontalMargin) + .frame(width: desiredSize.width, height: desiredSize.height == 0 ? 0.1 : max(desiredSize.height, 92), alignment: .center) + .opacity(desiredSize.height == 0 ? 0 : 1) + .frame(height: desiredSize.height == 0 ? 0.1 : nil) + .clipped() } } @@ -133,9 +136,11 @@ private struct VirtusizeInPageStandardWrapper: UIViewRepresentable { uiView.setContentViewListener(listener: { view in horizontalMargin = view.userSetMargin + // Set height to 0 if product is invalid, there's an error, or view is hidden + let height = (view.invalidProduct || view.isError || view.isHidden) ? 0 : view.frame.height desiredSize = CGSize( width: UIScreen.main.bounds.size.width, - height: view.frame.height + height: height ) }) } diff --git a/Virtusize/Sources/UI/VirtusizeInPageMini.swift b/Virtusize/Sources/UI/VirtusizeInPageMini.swift index be33e8fa..252ff52e 100644 --- a/Virtusize/Sources/UI/VirtusizeInPageMini.swift +++ b/Virtusize/Sources/UI/VirtusizeInPageMini.swift @@ -162,13 +162,19 @@ public class VirtusizeInPageMini: VirtusizeInPageView { "messageAndButtonMargin": messageAndButtonMargin ] - let horizontalConstraints = NSLayoutConstraint.constraints( + var horizontalConstraints = NSLayoutConstraint.constraints( // swiftlint:disable:next line_length withVisualFormat: "H:|-horizontalMargin-[inPageMiniImageView]-0-[messageLabel]-(>=messageAndButtonMargin)-[sizeCheckButton]-horizontalMargin-|", options: NSLayoutConstraint.FormatOptions(rawValue: 0), metrics: metrics, views: views ) + // Lower the priority of leading and trailing constraints to prevent conflicts during initial layout + for constraint in horizontalConstraints { + if constraint.firstItem === self || constraint.secondItem === self { + constraint.priority = UILayoutPriority(999) + } + } let inPageMiniImageViewVerticalConstraints = NSLayoutConstraint.constraints( withVisualFormat: "V:|-(>=verticalMargin)-[inPageMiniImageView(18)]-(>=verticalMargin)-|", @@ -267,6 +273,10 @@ public class VirtusizeInPageMini: VirtusizeInPageView { inPageMiniImageView.image = loading ? VirtusizeAssets.icon : nil inPageMiniMessageLabel.textColor = loading ? .vsGray900Color : .white setupTextsStyle(messageLabelIsBold: loading) + + // Re-enable user interaction when loading valid product + isUserInteractionEnabled = true + if loading { startLoadingTextAnimation( label: inPageMiniMessageLabel, diff --git a/Virtusize/Sources/UI/VirtusizeInPageView.swift b/Virtusize/Sources/UI/VirtusizeInPageView.swift index eb5610dd..b5b78f78 100644 --- a/Virtusize/Sources/UI/VirtusizeInPageView.swift +++ b/Virtusize/Sources/UI/VirtusizeInPageView.swift @@ -72,6 +72,7 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto internal var isLoading: Bool = false internal var isError: Bool = false internal var invalidProduct: Bool = false + private var heightConstraint: NSLayoutConstraint? private func addSubviews() { // Add loading GIF image view @@ -104,6 +105,19 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto isLoading = show loadingGifImageView.isHidden = !show contentContainerView.isHidden = show + + // Set height to 0 for invalid product or error + if invalidProduct || isError { + if heightConstraint == nil { + heightConstraint = heightAnchor.constraint(equalToConstant: 0) + heightConstraint?.priority = .defaultHigh + heightConstraint?.isActive = true + } + } else { + // Remove height constraint for valid product + heightConstraint?.isActive = false + heightConstraint = nil + } } /// Add observers to listen to notification data from the sender (Virtusize.self) @@ -155,6 +169,8 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto @objc internal func didReceiveProductCheckData(_ notification: Notification) { shouldUpdateProductCheckData(notification) { productWithPDCData in self.clientProduct = productWithPDCData + self.invalidProduct = false + self.isError = false showLoadingGif(false) setLoadingScreen(loading: true) isLoading = true @@ -171,10 +187,18 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto @objc internal func didReceiveSizeRecommendationData(_ notification: Notification) { isLoading = false isError = false + // Remove height constraint when data is successfully loaded + heightConstraint?.isActive = false + heightConstraint = nil } @objc func productCheckDidFail(_ notification: Notification) { invalidProduct = true + showLoadingGif(false) + // Notify SwiftUI wrappers to update height + DispatchQueue.main.async { + self.contentViewListener?(self) + } } internal func shouldUpdateInPageRecommendation( @@ -204,6 +228,16 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto /// A parent function for showing the error screen @objc internal func didReceiveInPageError(_ notification: Notification) { isError = true + // Update height constraint for error state + if heightConstraint == nil { + heightConstraint = heightAnchor.constraint(equalToConstant: 0) + heightConstraint?.priority = .defaultHigh + heightConstraint?.isActive = true + } + // Notify SwiftUI wrappers to update height + DispatchQueue.main.async { + self.contentViewListener?(self) + } } /// Sets up the styles for the loading screen and the screen after finishing loading @@ -212,6 +246,9 @@ public class VirtusizeInPageView: UIView, VirtusizeView, VirtusizeViewEventProto /// - loading: Pass true when it's loading, and pass false when finishing loading internal func setLoadingScreen(loading: Bool) { isError = false + // Remove height constraint when loading valid product + heightConstraint?.isActive = false + heightConstraint = nil } internal func setup() {}