Skip to content

Adds prioritized campaigns support#386

Open
ianrumac wants to merge 1 commit intodevelopfrom
ir/feat/prioritized-campaigns
Open

Adds prioritized campaigns support#386
ianrumac wants to merge 1 commit intodevelopfrom
ir/feat/prioritized-campaigns

Conversation

@ianrumac
Copy link
Copy Markdown
Collaborator

@ianrumac ianrumac commented Mar 23, 2026

Changes in this pull request

  • Adds prioritized campaign support

Checklist

  • All unit tests pass.
  • All UI tests pass.
  • Demo project builds and runs.
  • I added/updated tests or detailed why my change isn't tested.
  • I added an entry to the CHANGELOG.md for any breaking changes, enhancements, or bug fixes.
  • I have run ktlint in the main directory and fixed any issues.
  • I have updated the SDK documentation as well as the online docs.
  • I have reviewed the contributing guide

Greptile Summary

This PR introduces prioritized campaign support: a new optional prioritizedCampaignId field is added to Config, and PaywallPreload is updated to detect that field at startup, preload the matching campaign's paywalls first, wait 5 seconds, then preload all remaining paywalls.

The Config.kt change is clean. The PaywallPreload.kt change has two logic issues that should be addressed before merging:

  • Double preloading of prioritized paywalls – the second getAllActiveTreatmentPaywallIds call receives the full triggers set (which still contains the prioritized triggers), so their paywall IDs appear in both batches and are preloaded redundantly.
  • delay(5000) does not synchronize with actual completionpreloadPaywalls launches a fire-and-forget child coroutine and returns immediately; the five-second pause is therefore only a heuristic, not a guarantee that prioritized paywalls are ready before the second batch begins.

Confidence Score: 4/5

Two P1 logic issues should be resolved before merging: duplicate preloading and an unsynchronized delay.

Two P1 findings exist: prioritized paywalls are preloaded twice (wasted network/memory), and the delay does not wait for the first batch to finish (ordering guarantee is broken). Both affect the primary feature being introduced.

PaywallPreload.kt — specifically the trigger-set scoping and the fire-and-forget delay around lines 60–88.

Important Files Changed

Filename Overview
superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt Adds prioritized-campaign preloading with two issues: (1) the second getAllActiveTreatmentPaywallIds call reuses the full trigger set, causing prioritized paywalls to be loaded twice; (2) preloadPaywalls is fire-and-forget so the 5s delay does not guarantee the prioritized batch finishes before the second batch starts.
superwall/src/main/java/com/superwall/sdk/models/config/Config.kt Adds optional prioritizedCampaignId field with correct @SerialName annotation and a nullable default; no issues.

Sequence Diagram

sequenceDiagram
    participant PA as preloadAllPaywalls
    participant CL as ConfigLogic
    participant PP as preloadPaywalls
    participant SC as scope (IOScope)
    participant PM as PaywallManager

    PA->>CL: filterTriggers(config.triggers)
    CL-->>PA: triggers (full set)
    PA->>PA: check prioritizedCampaignId
    PA->>CL: getAllActiveTreatmentPaywallIds(prioritizedTriggers)
    CL-->>PA: prioritizedIds
    PA->>PP: preloadPaywalls(prioritizedIds)
    PP->>SC: launchWithTracking { ... }
    Note over PP,SC: Returns immediately (fire-and-forget)
    PP-->>PA: (returns)
    PA->>PA: delay(5000ms) ← heuristic only
    PA->>CL: getAllActiveTreatmentPaywallIds(triggers) ← full set includes prioritized
    CL-->>PA: paywallIds (includes prioritized IDs again)
    PA->>PP: preloadPaywalls(paywallIds)
    PP->>SC: launchWithTracking { ... }
    SC->>PM: getPaywallView(id) for each id
    PM-->>SC: PaywallView (cached)
Loading

Comments Outside Diff (1)

  1. superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt, line 80-88 (link)

    P1 Prioritized paywalls are preloaded a second time

    The second getAllActiveTreatmentPaywallIds call is passed the full triggers set, which still includes the triggers belonging to the prioritized campaign. The resulting paywallIds set therefore contains all the same identifiers that were just preloaded in the prioritized batch, causing those paywalls to be fetched and cached again unnecessarily.

    To fix this, exclude the already-preloaded prioritized triggers from the second pass by hoisting prioritizedTriggers to the outer scope and subtracting it before the second call.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
    Line: 80-88
    
    Comment:
    **Prioritized paywalls are preloaded a second time**
    
    The second `getAllActiveTreatmentPaywallIds` call is passed the full `triggers` set, which still includes the triggers belonging to the prioritized campaign. The resulting `paywallIds` set therefore contains all the same identifiers that were just preloaded in the prioritized batch, causing those paywalls to be fetched and cached again unnecessarily.
    
    To fix this, exclude the already-preloaded prioritized triggers from the second pass by hoisting `prioritizedTriggers` to the outer scope and subtracting it before the second call.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
Line: 80-88

Comment:
**Prioritized paywalls are preloaded a second time**

The second `getAllActiveTreatmentPaywallIds` call is passed the full `triggers` set, which still includes the triggers belonging to the prioritized campaign. The resulting `paywallIds` set therefore contains all the same identifiers that were just preloaded in the prioritized batch, causing those paywalls to be fetched and cached again unnecessarily.

To fix this, exclude the already-preloaded prioritized triggers from the second pass by hoisting `prioritizedTriggers` to the outer scope and subtracting it before the second call.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
Line: 72-75

Comment:
**`delay(5000)` does not wait for prioritized preloading to complete**

`preloadPaywalls()` is fire-and-forget: it immediately launches a new child coroutine via `scope.launchWithTracking { … }` and returns. Calling `delay(5000)` after it only pauses the outer coroutine for five seconds; it does **not** block until the prioritized paywalls have actually finished loading. If network conditions are slow, the second batch will start before the first finishes, defeating the purpose of the prioritization.

Consider having `preloadPaywalls` return the launched `Job` and then calling `join()` (or `withTimeoutOrNull(5_000) { job.join() }`) to synchronize on actual completion.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
Line: 75

Comment:
**Magic number for delay duration**

The literal `5000` is hard to understand without the comment. Use Kotlin's `Duration` API for clarity:

```suggestion
                        delay(5.seconds)
```

Add `import kotlin.time.Duration.Companion.seconds` alongside the other imports.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Adds prioritized campaigns support" | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

@ianrumac ianrumac marked this pull request as ready for review April 1, 2026 15:23
Comment on lines +72 to +75
preloadPaywalls(paywallIdentifiers = prioritizedIds)

// Delay before preloading the rest to avoid resource contention.
delay(5000)
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.

P1 delay(5000) does not wait for prioritized preloading to complete

preloadPaywalls() is fire-and-forget: it immediately launches a new child coroutine via scope.launchWithTracking { … } and returns. Calling delay(5000) after it only pauses the outer coroutine for five seconds; it does not block until the prioritized paywalls have actually finished loading. If network conditions are slow, the second batch will start before the first finishes, defeating the purpose of the prioritization.

Consider having preloadPaywalls return the launched Job and then calling join() (or withTimeoutOrNull(5_000) { job.join() }) to synchronize on actual completion.

Prompt To Fix With AI
This is a comment left during a code review.
Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
Line: 72-75

Comment:
**`delay(5000)` does not wait for prioritized preloading to complete**

`preloadPaywalls()` is fire-and-forget: it immediately launches a new child coroutine via `scope.launchWithTracking { … }` and returns. Calling `delay(5000)` after it only pauses the outer coroutine for five seconds; it does **not** block until the prioritized paywalls have actually finished loading. If network conditions are slow, the second batch will start before the first finishes, defeating the purpose of the prioritization.

Consider having `preloadPaywalls` return the launched `Job` and then calling `join()` (or `withTimeoutOrNull(5_000) { job.join() }`) to synchronize on actual completion.

How can I resolve this? If you propose a fix, please make it concise.

preloadPaywalls(paywallIdentifiers = prioritizedIds)

// Delay before preloading the rest to avoid resource contention.
delay(5000)
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.

P2 Magic number for delay duration

The literal 5000 is hard to understand without the comment. Use Kotlin's Duration API for clarity:

Suggested change
delay(5000)
delay(5.seconds)

Add import kotlin.time.Duration.Companion.seconds alongside the other imports.

Prompt To Fix With AI
This is a comment left during a code review.
Path: superwall/src/main/java/com/superwall/sdk/config/PaywallPreload.kt
Line: 75

Comment:
**Magic number for delay duration**

The literal `5000` is hard to understand without the comment. Use Kotlin's `Duration` API for clarity:

```suggestion
                        delay(5.seconds)
```

Add `import kotlin.time.Duration.Companion.seconds` alongside the other imports.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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.

1 participant