* add refreshable action to paywalls list in PaywallsTester app
* fix: disable refreshable action in PaywallView
* chore: add comment explaining why `refreshable` action was added to `APIKeyDashboardList`
* A mixture of changes while putting the demo together
* Doing some manual fixes for max image height
* Removed unused file and renamed struct
* Fixed lint
* Fix tests
* Image default value on component and not localization
* Fixed sample paywall
* A few more small fixes
* Fix lint
Since iOS version cannot change at runtime, we can make it a stored
variable so we only compute it once.
---------
Co-authored-by: Toni Rico <toni.rico.diez@revenuecat.com>
### Motivation
Template 5 but with multiple tiers 😊
### Description
Enabling Template 7 by changing `7_disabled` to `7`
- Changed a `header.jpg` to `header.heic` to try and fix issue with
weirdly failing snapshot UI test
- Changed visibility on `TestData` from `public` to `internal`
- Hides tier selector if only one tier
- Changed `color_overrides_by_tier` to `colors_by_tier` and
`image_overrides_by_tier` to `images_by_tier`
- The original implementation was going to default to existing color and
images configurations and then override by tier
- However, this turned out to be harder to implement on the
configuration side
- `Colors` got four new optional values
- `tier_control_background`
- `tier_control_foreground`
- `tier_control_selected_background`
- `tier_control_selected_foreground`
### Demo
#### Full Screen
https://github.com/RevenueCat/purchases-ios/assets/401294/e5317a53-428c-415e-a1a1-b4231d32a776
### Footer
https://github.com/RevenueCat/purchases-ios/assets/401294/8905b55e-0fa2-49f0-aa1c-d4c1e694fb5b
### Footer Condensed
https://github.com/RevenueCat/purchases-ios/assets/401294/311d78fb-bdeb-43cd-b601-9c60a8a54b6f
This PR allows the Paywalls Tester app to access some items internal to
purchases-ios by temporarily marking them public during complication.
Items that need to be public have been annotated with
`\\@PublicForExternalTesting`.
The Paywalls Tester project runs a script, Preprocessor.sh, as a
pre-action to add `public` to all classes/structs/enums/functions/inits
that have been annotated.
After compilation it runs a second script, Postprocessor.sh, as a
post-action to undo these changes so that they don't accidentally get
checked in.
The first script is run as a scheme pre-action rather than as a run
script build phase, because when run as a build phase the changes to the
files aren't picked up until the next compilation attempt.
<img width="669" alt="image"
src="https://github.com/RevenueCat/purchases-ios/assets/109382862/0b0bacdb-79de-441d-8d61-2a5dd03b1b53">
It also changes the archive step to be built with a release
configuration, and removes the use of `@testable import` for debug
builds.
resolves PWL-459
The previous implementation used `ScrollableIfNecessaryModifier` which
is a hacky work around for iOS 15 not having `ViewThatFits`.
To work around issues with that, specific to template 5, this new
approach avoids the "if necessary" part on iOS 15 which removes the
problematic usage of `GeometryReader`.
Fixes#3516.
This logic only existed for `.presentPaywallIfNeeded`. However, it
should apply to `PaywallView` when presented manually as well.
This is also consistent with how Android works, reduces boilerplate code
required by users, and removes the possibility that a paywall is still
presented after a purchase, which doesn't make sense since our paywalls
don't have a mode for "already subscribed".
This only reproduces on iOS 16 and using the new `displayCloseButton:
true` (because it embeds `PaywallView` in a `NavigationView`).

The problem was that the template used `ViewDimentionPreferenceKey` in
several parts of the hierarchy and `SwiftUI` mixes both.
I work around it by separating `onWidthChange` and `onHeightChange`.
This abstracts away the logic to ensure layouts are consistent when
selecting different packages in multi-package templates, in a way that
the content doesn't move around.
## Motivation
It was a little unclear how and when to use the different `PaywallView`
modes (`.fullscreen`, `.card`, and `.condensedCard`). The actual
functionality of the modes is great but they seemed like three different
components in one view and it was just trying to do too much for one
public API.
This change will...
- Remove modes from being a public parameter in `PaywallView` and only
allow it to be full screen
- Create a new `PaywallFooterView` which will combine `.footer`
(previously `.card`) and `.condensedFooter` (previously
`.condensedCard`)
- Removed the `modes` parameter from `PaywallView`
### New `PaywallFooterView`
- Wraps `PaywallView` and will only choose between `.footer` and
`.footerCondensed`
- Currently offers a `condensed` parameter but this might be switched to
being a remote setting inside of `PaywalData`
### New `.paywallFooter()` view modifier
- Easy way for developers to place `PaywallFooterView` where it is
supposed to be placed
- This places the view in `.safeAreaInset(edge: .bottom)`
- This works on any view but is ideal in `ScrollView` as it will
automatically handle adjusting the scroll insets with the paywalls size
### New footer structure and animation (with some hacks)
- No parts of `PaywallFooterView` uses `.overlay` anymore
- The whole grows in `.condensedFooter` when "All Plans" is toggled
## Demo
### My sample app
https://github.com/RevenueCat/purchases-ios/assets/401294/17c52bba-956d-404e-b991-a2272e7fc4f1
### Simple sample app
https://github.com/RevenueCat/purchases-ios/assets/401294/4ea94156-8367-4dea-9640-0cce8ffa1deb
---------
Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
Rename "card" to "footer" to because that is how we expect developers to
use the current implementation of the non-fullscreen modes as a footer
to their custom paywalls.
- Renamed `card` to `footer`
- Renamed `condensedCard` to `condensedFooter`
---------
Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
`PaywallView` and `PaywallViewController` (along with the extensions)
still require iOS 16, but this paves the way to support iOS 15 down the
road if we need to.
### Main Changes:
- Changed all `@available` annotations
- Added CI tests
- Replaced `ViewThatFits` with the "biggest" version
- Because of that, `scrollableIfNeeded` is always scrollable
- Double `Regex` implementation (keeping the modern one), so once we
drop support for iOS 15 we can just keep the modern one.
### TODO:
- [x] Add snapshots
- [x] Test paywalls
- [x] Updated APITester to verify this
Follow up to #2796.
This also makes `PaywallData.Configuration`'s intro strings optional.
- Injected `TrialOrIntroEligibilityChecker`
- Created mock `TrialOrIntroEligibilityChecker` for previews
- Handling state and transitions for loading eligibility
- Snapshot tests for the different new cases
- Improved `SnapshotTesting` delay management
- Expanded `DebugErrorView` to customize release behavior
- Added `PaywallData.assetBaseURL` and
`PaywallData.Configuration.headerImageName`
- Changed template to fetch image from network
- Updated snapshot testing to support asynchronous checking, necessary
for `AsyncImageView`
- Added support for overriding images for snapshot tests
- Extracted `DebugErrorView`