diff --git a/CHANGELOG.md b/CHANGELOG.md index 63cb3d942..a0380d9e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next +- fix: mangled wireframe layouts ([#250](https://github.com/PostHog/posthog-ios/pull/250)) + ## 3.15.2 - 2024-11-13 - fix: allow changing person properties after identify ([#249](https://github.com/PostHog/posthog-ios/pull/249)) diff --git a/PostHog/Replay/PostHogReplayIntegration.swift b/PostHog/Replay/PostHogReplayIntegration.swift index a2b6e7757..68fce3d83 100644 --- a/PostHog/Replay/PostHogReplayIntegration.swift +++ b/PostHog/Replay/PostHogReplayIntegration.swift @@ -146,14 +146,19 @@ style.paddingLeft = Int(insets.left) } - private func createBasicWireframe(_ window: UIView) -> RRWireframe { + private func createBasicWireframe(_ view: UIView) -> RRWireframe { let wireframe = RRWireframe() - wireframe.id = window.hash - wireframe.posX = Int(window.frame.origin.x) - wireframe.posY = Int(window.frame.origin.y) - wireframe.width = Int(window.frame.size.width) - wireframe.height = Int(window.frame.size.height) + // since FE will render each node of the wireframe with position: fixed + // we need to convert bounds to global screen coordinates + // otherwise each view of depth > 1 will likely have an origin of 0,0 (which is the local origin) + let frame = view.toAbsoluteRect(view.window) + + wireframe.id = view.hash + wireframe.posX = Int(frame.origin.x) + wireframe.posY = Int(frame.origin.y) + wireframe.width = Int(frame.size.width) + wireframe.height = Int(frame.size.height) return wireframe } @@ -380,8 +385,8 @@ } let wireframe = createBasicWireframe(view) - let style = RRStyle() + var skipChildren = false if let textView = view as? UITextView { wireframe.type = "text" @@ -447,8 +452,14 @@ wireframe.inputType = "button" wireframe.disabled = !button.isEnabled + // UIButton has a UILabel subview that displays the button's text + // We want to skip visiting children if button is sensitive + // Otherwise, we capture the button's title through its child UILabel if let text = button.titleLabel?.text { - wireframe.value = isButtonSensitive(button) ? text.mask() : text + if isButtonSensitive(button) { + skipChildren = true + wireframe.value = text.mask() + } } } @@ -496,7 +507,7 @@ wireframe.style = style - if !view.subviews.isEmpty { + if !view.subviews.isEmpty, !skipChildren { var childWireframes: [RRWireframe] = [] for subview in view.subviews { if let child = toWireframe(subview) { diff --git a/PostHog/Replay/UIView+Util.swift b/PostHog/Replay/UIView+Util.swift index 283782197..35e9f1c0c 100644 --- a/PostHog/Replay/UIView+Util.swift +++ b/PostHog/Replay/UIView+Util.swift @@ -59,7 +59,7 @@ } // you need this because of SwiftUI otherwise the coordinates always zeroed for some reason - func toAbsoluteRect(_ window: UIWindow) -> CGRect { + func toAbsoluteRect(_ window: UIWindow?) -> CGRect { convert(bounds, to: window) } }