Skip to content

Conversation

@yusuftor
Copy link
Collaborator

@yusuftor yusuftor commented Jan 28, 2026

Summary

  • Sets presentationController?.delegate for modal/drawer presentation styles so UIKit notifies us on swipe-to-dismiss
  • Adds presentationControllerDidDismiss handler to fire paywall_decline when a modal is dismissed by swipe (without a survey)
  • Guards against double-dismiss when didAttemptToDismiss (survey path) already triggered dismiss

Test plan

  • Present a modal paywall without a survey, swipe down — verify paywall_decline fires
  • Present a modal paywall with a survey, swipe down — verify survey shows and paywall_decline fires only once
  • Present a drawer paywall, swipe down — verify paywall_decline fires
  • Present a fullscreen paywall, close via button — verify existing behavior unchanged

🤖 Generated with Claude Code

Greptile Overview

Greptile Summary

Enables paywall_decline event tracking when users swipe down modal/drawer paywalls by setting the presentation controller delegate and implementing the presentationControllerDidDismiss callback.

Key changes:

  • Captures willShowSurvey state before setting delegate to preserve survey detection logic (fixing previous thread concern)
  • Sets presentationController?.delegate = self for modal/drawer styles to receive swipe-to-dismiss notifications from UIKit
  • Implements presentationControllerDidDismiss to fire paywall_decline when swipe completes
  • Guards against duplicate events by checking if closeReason was already set by didAttemptToDismiss (survey flow)

Survey flow preserved:

  • With survey: isModalInPresentation = true → swipe triggers didAttemptToDismiss → shows survey → subsequent didDismiss is guarded
  • Without survey: isModalInPresentation = false → swipe completes → didDismiss fires paywall_decline

Confidence Score: 4/5

  • Safe to merge with one recommended test to verify edge case behavior
  • The fix correctly addresses the previous review concern by capturing survey state before setting the delegate. The double-dismiss guard prevents duplicate events. Logic is sound for modal/drawer styles.
  • No files require special attention

Important Files Changed

Filename Overview
Sources/SuperwallKit/Paywall/View Controller/PaywallViewController.swift Correctly fixes the delegate-setting order to preserve survey detection, adds swipe-to-dismiss handling for modal/drawer styles

Sequence Diagram

sequenceDiagram
    participant User
    participant UIKit
    participant PaywallVC
    participant Superwall

    Note over PaywallVC: presentationWillBegin()
    PaywallVC->>PaywallVC: Check willShowSurvey (before delegate set)
    alt Modal/Drawer Style
        PaywallVC->>PaywallVC: Set presentationController.delegate = self
        alt Has Survey
            PaywallVC->>PaywallVC: isModalInPresentation = true
        else No Survey
            PaywallVC->>PaywallVC: isModalInPresentation = false
        end
    end

    Note over User,UIKit: User swipes down to dismiss
    
    alt With Survey (isModalInPresentation=true)
        User->>UIKit: Swipe down
        UIKit->>PaywallVC: presentationControllerDidAttemptToDismiss()
        PaywallVC->>PaywallVC: dismiss(result: .declined, closeReason: .manualClose)
        PaywallVC->>PaywallVC: Set paywall.closeReason = .manualClose
        PaywallVC->>Superwall: track(paywall_decline)
        PaywallVC->>User: Show survey
        User->>UIKit: Complete survey & swipe again
        UIKit->>PaywallVC: presentationControllerDidDismiss()
        PaywallVC->>PaywallVC: Guard: closeReason != .none (already set)
        Note over PaywallVC: Early return, no duplicate event
    else Without Survey (isModalInPresentation=false)
        User->>UIKit: Swipe down
        UIKit->>UIKit: Dismissal completes
        UIKit->>PaywallVC: presentationControllerDidDismiss()
        PaywallVC->>PaywallVC: Guard: closeReason == .none (passes)
        PaywallVC->>PaywallVC: dismiss(result: .declined, closeReason: .manualClose)
        PaywallVC->>Superwall: track(paywall_decline)
        PaywallVC->>UIKit: Dismiss paywall
    end
Loading

yusuftor and others added 2 commits January 27, 2026 13:55
Set presentationController delegate for modal/drawer styles so
presentationControllerDidDismiss fires on swipe-down, triggering
the paywall_decline event even when no survey is present.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents paywall_decline from firing twice when didAttemptToDismiss
(survey path) already triggered dismiss before didDismiss is called.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@yusuftor yusuftor merged commit ea28378 into develop Jan 28, 2026
3 checks passed
@yusuftor yusuftor deleted the fix/modal-paywall-decline branch January 28, 2026 13:06
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.

2 participants