Skip to content

Conversation

@facumenzella
Copy link
Contributor

@facumenzella facumenzella commented Dec 11, 2025

Motivation

  • Fix bug where tabs without packages did not properly inherit the parent's selected package
  • Ensure proper package selection behavior when switching between tabs
  • Track user selections separately from tab propagations to restore correct state

Description

Problem

When a Tabs component contained:

  • Parent packages (outside the tabs)
  • Tab 1 with its own package
  • Tab 2 without packages (should inherit from parent)

Several issues occurred:

  1. Tab 2 would show no package (variable text not replaced)
  2. Tab 2 would not update when the parent's selected package changed
  3. When switching from Tab 1 back to Tab 2, Tab 2 would show Tab 1's package instead of the parent's selection

Solution

The fix has three parts:

1. Direct reference sharing for tabs without packages

  • Tabs WITH packages: Create their own PackageContext instance
  • Tabs WITHOUT packages: Use parentPackageContext directly (same reference)

2. Tab switching logic
When switching to a tab:

  • Tab has NO packages → Restore parentOwnedPackage (the user's last selection in parent scope)
  • Tab HAS packages, parent's package IS in tab → Keep parent's selection
  • Tab HAS packages, parent's package NOT in tab → Use tab's default package

3. Parent selection tracking
Track parentOwnedPackage to distinguish user selections from tab propagations:

  • Tab propagation (newPackage == tab's current package) → Don't update tracking
  • User selection (newPackage != tab's current package) → Update tracking

This ensures that when switching back to a package-less tab, we restore the user's actual selection, not a package that was propagated from another tab.

Copy link
Member

@ajpallares ajpallares left a comment

Choose a reason for hiding this comment

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

Great investigation for this! 🙌
This is certainly a tricky scenario to solve. I think we're very close, but I have one doubt about a specific case and I also think that the current implementation is not propagating down the selected packages into the tab without packages.

But we're getting there!

Comment on lines 120 to 124
// Requirements:
// 1. Tabs WITH packages: use their own package context, propagate to parent for purchase button
// 2. Tabs WITHOUT packages: inherit from parent's selected package
// 3. Tabs WITHOUT packages should NOT be affected when tabs WITH packages propagate their package
// 4. Tabs WITHOUT packages SHOULD update when user selects a different parent package
Copy link
Member

Choose a reason for hiding this comment

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

Reading this I wonder what happens in this scenario, same example structure:

  • Initially, Package A is the default.
  • Select Tab 1, and then select Package C in that tab --> "propagate to parent for purchase button".
  • Select Tab 2.
    What package is shown in Tab 2?

According to the explanation below

This context will be kept in sync with parent changes via onChangeOf in the body, which filters out propagations from tabs with packages.

This means that Tab 1 would always show the latest Parent package selected (A or B) even when Package C could be the latest package selected (from tab 2).

Is that what we want? That's what I gather from

Tabs WITHOUT packages should NOT be affected when tabs WITH packages propagate their package

But in the scenario above, what package is shown in Tab 2?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here's a video of the behavior:
Uploading Simulator Screen Recording - iPhone 16 Pro - 2025-12-12 at 10.38.25.mov…

For Tab2, the "active" package will be first the default in the parent scope, or the latest selected one.

let packageContext = PackageContext(
package: parentPackageContext.package,
variableContext: parentPackageContext.variableContext
)
Copy link
Member

Choose a reason for hiding this comment

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

Here we're creating a new instance of PackageContext, which means that the onChangeOf won't really work because the @Published package of the new PackageContext won't change when the parent's package changes. In other words, this requirement

Tabs WITHOUT packages SHOULD update when user selects a different parent package
would not work right now.

I'm not 100% sure about this, but, if the Tab component doesn't have any package itself at this point (tabViewModel.packages.isEmpty), I think you could just do

return (key, parentPackageContext)

But we'd need to test it thoroughly, as I'm not sure that this behavior would match the desired behavior (mostly about not propagating the selected package inside Tab 1 to Tab 2)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this works because:

  1. self.packageContext (line 73) is the parent's @EnvironmentObject
  2. onChangeOf(self.packageContext.package) watches THIS parent context
  3. When parent changes, syncParentPackageToTabsWithoutPackages updates the separate tier contexts

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.

3 participants