Skip to content

feat(paywalls-v2): port InputSingleChoice and InputOption components from iOS#3498

Draft
facumenzella wants to merge 3 commits into
mainfrom
port/6820-input-single-choice-option
Draft

feat(paywalls-v2): port InputSingleChoice and InputOption components from iOS#3498
facumenzella wants to merge 3 commits into
mainfrom
port/6820-input-single-choice-option

Conversation

@facumenzella
Copy link
Copy Markdown
Member

Summary

Android port of purchases-ios#6820.

  • Adds InputSingleChoiceComponent and InputOptionComponent data classes (with partial variants) and JSON deserializer registration
  • Adds InputSingleChoiceComponentStyle / InputOptionComponentStyle and StyleFactory wiring
  • Adds InputSingleChoiceComponentView (delegates to its stack) and InputOptionComponentView (updates selectedOptionIdsByFieldId, fires WorkflowTrigger on tap)
  • Tracks selection state in PaywallState.Loaded.Components.selectedOptionIdsByFieldId — a SnapshotStateMap<String, String?> keyed by fieldId, updated via state.update(fieldId, optionId)
  • Adds PaywallComponentType.INPUT_OPTION event type and InputOptionNotInInputSingleChoice validation error
  • Wires both component types into BFS traversal (PaywallComponentFilterExtension), image pre-downloader, and OfferingToStateMapper.containsUnsupportedCondition()

Test plan

  • InputSingleChoiceComponentTests — JSON deserialization for all 4 data classes
  • InputSingleChoiceStateTests — selection state: initial empty, select, replace, deselect (null), multi-field isolation

Note: The iOS PR is still open — this port may need updates once it merges.

🤖 Generated with Claude Code

facumenzella and others added 2 commits May 20, 2026 05:47
Port of RevenueCat/purchases-ios#6820

Adds InputSingleChoiceComponent and InputOptionComponent to the
Paywalls V2 component model and rendering pipeline:

- Data model: InputSingleChoiceComponent (field_id, required, stack,
  overrides) and InputOptionComponent (option_id, option_value, stack,
  triggers, overrides) with their Partial counterparts
- PaywallComponentSerializer: dispatch for "input_single_choice" and
  "input_option" types
- BFS traversal (PaywallComponentFilterExtension) and image
  pre-downloader updated for both new types
- PaywallComponentType.INPUT_OPTION added for interaction tracking
- Style layer: InputSingleChoiceComponentStyle / InputOptionComponentStyle
  wrapping StackComponentStyle; fieldId propagated via StyleFactoryScope
- PaywallState.Loaded.Components: selectedOptionIdsByFieldId map +
  update(fieldId, selectedOptionId) method for selection state
- InputSingleChoiceComponentView delegates rendering to StackComponentView
- InputOptionComponentView updates selection state on tap and fires a
  WorkflowTrigger(optionId, ON_PRESS) action
- Validation error InputOptionNotInInputSingleChoice for orphaned options
- JSON decode tests for all four data class types

Deviation from iOS: iOS uses @EnvironmentObject (CompositionLocal) to
propagate InputSingleChoiceContext. Android stores per-field selection
in PaywallState.Loaded.Components.selectedOptionIdsByFieldId to comply
with the project's no-new-CompositionLocal rule.

Still pending: InputSingleChoiceStateTests, lint, unit test run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hoice/InputOption

- Add InputSingleChoiceStateTests: covers initial state, select, replace,
  deselect, and multi-field isolation for selectedOptionIdsByFieldId
- Fix non-exhaustive when in OfferingToStateMapper.containsUnsupportedCondition
  for InputSingleChoiceComponent and InputOptionComponent
- Fix non-exhaustive when in TabsComponentViewTests BFS helper for same types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant