Add workflowTrigger to ButtonComponent.Action#6693
Merged
Conversation
Mirrors Android's rename of Action.Workflow → Action.WorkflowTrigger (purchases-android#3380). Decodes backend "type": "workflow" into .workflowTrigger so workflow buttons are rendered (previously decoded as .unknown and hidden) and track as "workflow_trigger" in analytics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vegaro
approved these changes
Apr 24, 2026
Member
|
maybe adding some tests would be a good idea? |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Member
Author
polmiro
pushed a commit
that referenced
this pull request
Apr 24, 2026
* Add workflowTrigger case to ButtonComponent.Action Mirrors Android's rename of Action.Workflow → Action.WorkflowTrigger (purchases-android#3380). Decodes backend "type": "workflow" into .workflowTrigger so workflow buttons are rendered (previously decoded as .unknown and hidden) and track as "workflow_trigger" in analytics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add tests for workflowTrigger action decoding and analytics value Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
JZDesign
pushed a commit
that referenced
this pull request
Apr 24, 2026
* Replace print with Logger.error in ISODurationFormatter (#6691) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Decode reward payload in RewardVerification poll response (#6678) * Decode reward payload in RewardVerification poll response Plumbs the verified-reward payload from the backend response through the internal `pollRewardVerificationStatus` SPI so RC ad adapters can dispatch meaningful "verified" events with the granted reward. * Adds `VirtualCurrencyReward` and `VerifiedReward` (`@_spi(Internal) public`) under `Sources/Ads/RewardVerification/`. * Extends `RewardVerificationStatusResponse` to optionally decode a typed nested reward payload (`{ type, code, amount }`) on `verified` responses. - `reward` absent or null → `.noReward` - `type == "virtual_currency"` with valid `code`+`amount` → `.virtualCurrency` - any other `type` (or malformed `virtual_currency`) → `.unsupportedReward` + warn * `RewardVerificationPollStatus.verified` now carries the `VerifiedReward`. * `Purchases.pollRewardVerificationStatus` returns `.verified(reward)`. * Test mocks injected via a new `BasePurchasesTests.MockBackend` convenience init so `backend.adsAPI` resolves to `MockAdsAPI`. * Add unit tests for VerifiedReward and VirtualCurrencyReward Co-locates the unit tests next to the types this PR introduces under `Sources/Ads/RewardVerification/`: - `Tests/UnitTests/Ads/RewardVerification/VirtualCurrencyRewardTests.swift` Covers field storage, equality (both fields must match), and decimal precision preservation. - `Tests/UnitTests/Ads/RewardVerification/VerifiedRewardTests.swift` Covers `.virtualCurrency(_)` associated-value carrying, `.noReward` vs `.unsupportedReward` distinct-case identity, equality (matching associated reward required), and an exhaustive switch coverage test to guard against silently adding cases. Both tests pass against the existing `Sources/Ads/RewardVerification/` types and require no changes to them. (Originally written on top of #6663; moved to this base PR so the type and its tests ship together rather than splitting across PRs.) * fix: warn when reward verification reward value is not a JSON object Previously, `decodeVerifiedReward` silently returned `.noReward` for any of: missing reward key, null reward, or non-object reward value (e.g. a string/number/array). The first two are expected; the last indicates a backend mismatch and should be surfaced. Now distinguish: - absent or null reward → `.noReward` (silent, expected) - present but not a JSON object → `.unsupportedReward` + `Logger.warn` This matches the existing convention in this file of logging warnings when decoding unrecognized/malformed values into fallback cases. * Fix virtual currency reward amount type to integer. Align reward payload modeling with backend semantics by decoding `amount` as Int and updating tests to reject fractional values as malformed rewards. * fix: address review — couple verified status to reward Make the reward payload part of the verified status case so invalid state combinations are unrepresentable and remove the verified fallback mapping. * fix: address review — reject non-positive reward amounts Treat virtual-currency rewards with non-positive amounts as malformed payloads and return unsupported reward with warning logs. * fix: address review — reject empty reward currency code Validate virtual-currency payloads require a non-empty code and treat empty code values as malformed unsupported rewards. * fix: address review — remove non-actionable enum switch test Drop the exhaustive switch smoke test in VerifiedRewardTests since it did not validate behavior and duplicated compiler guarantees. * fix: address review — remove synthesized equatable assertions Drop VerifiedReward tests that only mirrored compiler-synthesized Equatable behavior and keep behavior-focused coverage. * Delete claude.yml workflow (#6688) * Add workflowTrigger to ButtonComponent.Action (#6693) * Add workflowTrigger case to ButtonComponent.Action Mirrors Android's rename of Action.Workflow → Action.WorkflowTrigger (purchases-android#3380). Decodes backend "type": "workflow" into .workflowTrigger so workflow buttons are rendered (previously decoded as .unknown and hidden) and track as "workflow_trigger" in analytics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add tests for workflowTrigger action decoding and analytics value Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Cache decoded images by file URL in `FileImageLoader` `URL.asImageAndSize` (used by `FileImageLoader.loadFromCache`) previously called `UIImage(contentsOfFile:)` / `NSImage(contentsOfFile:)` on every access. A SwiftUI paywall with many `RemoteImage` instances (e.g. a looping carousel that materialises multiple copies of each page) ends up hitting this path hundreds of times because `StateObject(wrappedValue:)` evaluates its closure on every host view re-init. UIKit/AppKit's internal caches still cost ~0.5–1 ms per call, which adds up to ~100+ ms of main-thread blocking for only a handful of unique URLs. Introduce a process-wide `DecodedImageCache` backed by `NSCache<NSURL, _>` so repeated lookups for the same URL become a dictionary hit. `NSCache` evicts on memory pressure, so we don't pin images forever. Reads/writes are serialised through a concurrent dispatch queue with a barrier on writes to keep the cache thread-safe. Made-with: Cursor --------- Co-authored-by: Facundo Menzella <facumenzella@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Pol Miro <polmiro@gmail.com> Co-authored-by: Cesar de la Vega <664544+vegaro@users.noreply.github.com>
This was referenced Apr 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Mirrors Android's rename of `Action.Workflow` → `Action.WorkflowTrigger` from purchases-android#3380.
This PR just introduces the type — the actual workflow navigation behavior lives in #6692. Without this, buttons with `"type": "workflow"` from the backend decode as `.unknown` and are hidden; with it they render and track correctly.
Changes:
Triggered by
#6692
Test plan
🤖 Generated with Claude Code
Note
Low Risk
Low risk: adds a new enum case and wiring for decoding/analytics, with no behavioral workflow navigation yet (action is currently a no-op).
Overview
Backend paywall button actions now recognize
"type": "workflow"by addingcase workflowTriggertoPaywallComponent.ButtonComponent.Action(includingCodablesupport) and mirroring it inButtonComponentViewModel.Action.UI handling is updated so workflow-trigger buttons are not treated as unknown/hidden and they report analytics as
workflow_trigger(with no URL); cache warming and unit tests are updated accordingly.Reviewed by Cursor Bugbot for commit 2229079. Bugbot is set up for automated code reviews on this repo. Configure here.