Skip to content

fix: [SDK-5662] scroll tall IAM content that doesn't fit - #1793

Merged
fadi-george merged 4 commits into
iam-fixesfrom
fadi/sdk-5662
Nov 6, 2026
Merged

fadi-george merged 4 commits into
iam-fixesfrom
fadi/sdk-5662

Conversation

@fadi-george

@fadi-george fadi-george commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Description

One Line Summary

Let IAM content scroll when it's taller than the space available, such as on a short landscape screen.

Details

Motivation

A tall IAM in landscape had its bottom clipped and couldn't be scrolled. Swiping dragged the whole card instead. The web view's scrolling has been disabled since 2018, and the message height is capped at the available space, so any overflow was unreachable.

Scope

  • Web view scrolling turns on only while its content overflows by more than 1pt. It's driven by the scroll view's contentSize and layout, not the JS height, because full screen messages report a height of 0.
  • The drag-to-dismiss pan gives way to scrolling unless the content fits or is already at the edge being dragged away from. When the card starts moving, the content's scroll is cancelled.
  • Only messages taller than the screen may scroll: never banners, center modals only when their JS height is over the available height, and full screen messages when their content overflows. Everything else keeps today's touch handling.
  • Scrolling cancels the display timer, like dragging does, and the content can't drift sideways.
  • Going from scrolling to dragging the card takes a second swipe, like iOS sheets.
  • The decision logic lives in a new pure helper, OSInAppMessageScroll.

Testing

Unit testing

OSInAppMessageScrollTests covers the overflow threshold, fitting content, top and bottom edges, the middle of the content, near-edge tolerance and zero vertical movement. Ran locally on an iOS 26.5 simulator (the unit test host app doesn't launch on the iOS 27 runtime, which is unrelated to this change).

Manual testing

Demo app built from this branch, Xcode 27.1:

  • iPhone 17 Pro sim (iOS 27.0), landscape: the HTML message scrolls to its bottom button. Swiping back to the top and then down again dismisses it. The center modal still drags to dismiss and the carousel still swipes between pages. The HTML message in portrait fits and drags to dismiss.
  • iPhone Duo sim (iOS 27.1): folded landscape scrolls and dismisses from the edge. Unfolded landscape and portrait fit and drag to dismiss as before.

Before / After

iPhone Duo folded, landscape, HTML message.

Before

html-old-bug.mov

After

html-fix.mov

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fadi-george
fadi-george requested review from abdulraqeeb33 and nan-li and removed request for nan-li November 6, 2026 01:15

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-model review of 69bae311...a15e006 (788 substantive lines; project.pbxproj excluded). Models: Claude Opus 5.5, GPT 5.6 Sol, Grok 4.7.

The overflow helper and edge-gated dismiss idea look right for tall landscape IAMs. A few gesture/layout gaps should be fixed before merge.

Act on

  • updateScrollEnabled has no banner / height-cap check (3/3). contentSize overflow can turn scrolling on for banners and fitting modals; a top banner then only dismisses after the leftover scroll is at the bottom.
  • While the user is scrolling, gestureRecognizerShouldBegin rejects the dismiss pan, so maxDisplayTime is never cancelled (GPT, verified). A tall IAM can auto-dismiss mid-read.
  • beginPanAtLocation always toggles contentPan.enabled (Opus, verified). After the first drag of a fitting message, the web view pan stays enabled even though scrollEnabled is still NO.

Consider

  • Reserved-region calls have no class/selector checks (Opus+Grok). A mismatch with the older-SDK shims is an unrecognized-selector crash on every layout.
  • Demo LogView uses iOS 17 .background(_:ignoresSafeAreaEdges:) with a 16.0 deploy target (Grok).
  • scrollEnabled unlocks horizontal pans; a slightly-too-wide document can drift or steal carousel swipes (Grok).
  • Vertical MAX(margin, safeArea) sits existing portrait banners/modals flush to the notch vs today's margin + safe-area sum (Opus).

Noted

  • Unit tests only cover the two pure helpers, not the gesture/timer paths.
  • displayBounds / sceneView still key off keyWindow.
  • Duplicate #import <UIKit/UIKit.h> in OSInAppMessageScroll.h.

Dismissed

  • Fullscreen skipping region frames is documented as HTML handling insets itself.
  • Nested contentOffset from layoutSubviews looks bounded by the early return.
Open in Web View Automation 

Sent by Cursor Automation: PR Reviews

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fadi-george
fadi-george changed the base branch from main to iam-fixes November 6, 2026 01:54
…view

Only height-capped messages scroll, scrolling cancels the display timer,
the drag no longer re-enables a disabled content pan, and horizontal
drift is pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fadi-george

Copy link
Copy Markdown
Collaborator Author

Addressed in 2997060: horizontal drift is pinned and the duplicate UIKit import is gone. The vertical margin note is from #1789, not this PR.

@abdulraqeeb33 abdulraqeeb33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 2997060 against iam-fixes. The three earlier "act on" items are fixed, the helper is pure and correct, KVO and gesture target wiring are clean, and the header stays out of the umbrella.

Approving with nits. Inline:

  1. contentScrollAllowed is snapshotted once in addConstraintsForMessage while the height cap keeps tracking the vertical guide, so a later safe area change can clip a center modal with scrolling still off. Cheap to recompute in viewDidLayoutSubviews.
  2. Fullscreen position is always allowed to scroll, so a middle swipe only dismisses if WebKit's contentSize matches the card within 1pt. Please confirm on a real fullscreen template before merge; the test list covers HTML, center modal and carousel but not fullscreen.
  3. The x pin in scrollViewDidScroll judders on a wide document rather than locking. Fine for now.
  4. Tests leave kEdgeTolerance unpinned in (1.0, 1.5). Three asserts close it.

… tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fadi-george
fadi-george merged commit 082989d into iam-fixes Nov 6, 2026
3 of 4 checks passed
@fadi-george
fadi-george deleted the fadi/sdk-5662 branch November 6, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants