Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paywalls: created PaywallEventStore #3157

Merged
merged 3 commits into from
Sep 7, 2023
Merged

Conversation

NachoSoto
Copy link
Contributor

@NachoSoto NachoSoto commented Sep 6, 2023

Changes:

@NachoSoto NachoSoto added refactor A code change that neither fixes a bug nor adds a feature RevenueCatUI labels Sep 6, 2023
@NachoSoto NachoSoto requested a review from a team September 6, 2023 23:28
@NachoSoto NachoSoto force-pushed the paywalls-events-model branch 2 times, most recently from c12d84b to 5b5ffd8 Compare September 6, 2023 23:35
NachoSoto added a commit that referenced this pull request Sep 6, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 7, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 7, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
Copy link
Contributor

@joshdholtz joshdholtz left a comment

Choose a reason for hiding this comment

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

Being able to reuse that FileHandler is 💯

private static var documentsDirectory: URL {
get throws {
if #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *) {
return URL.documentsDirectory
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a thing?! About time 😅

Copy link
Contributor Author

@NachoSoto NachoSoto Sep 7, 2023

Choose a reason for hiding this comment

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

I know seriously 🙈
Since we need the fallback we could remove this, but this API is so much more reliable...

do {
return try await self.handler.readLines()
.prefix(count)
.compactMap { try? PaywallEventSerializer.decode($0) }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This lazily decodes each event line by line without creating copies of everything in memory all at once :)

@NachoSoto NachoSoto force-pushed the paywalls-events-model branch 2 times, most recently from c0300f9 to 446fd68 Compare September 7, 2023 18:53
Base automatically changed from paywalls-events-model to paywalls September 7, 2023 20:02
NachoSoto added a commit that referenced this pull request Sep 7, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 7, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
Comment on lines 20 to 22
/// - Note: this loads the entire file in memory
/// For newer versions, consider using `readLines` instead.
func readFile() async throws -> Data
Copy link
Member

Choose a reason for hiding this comment

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

do we even need a version compatible with older OS version?

Copy link
Member

Choose a reason for hiding this comment

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

I imagine that it may be intended for things other than Paywalls, but I'd vote to remove it since the vast majority of devices are going to be on 15+ anyway.

If we want to keep it, I think we should be able to structure it in a way that we don't need to read the whole file at once

Copy link
Member

Choose a reason for hiding this comment

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

last note, total nitpick: feels like this note is very implementation-dependent, but we're putting it on the protocol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yeah thanks. I did this on the initial implementation when I wasn't sure if I was gonna be able to use the stream method (and yeah not so relevant on the protocol).

I'll delete the method now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I'm going to leave this on FileHandler (just not the protocol) because it makes testing it a lot simpler.

}

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
internal actor PaywallEventStore: PaywallEventStoreType {
Copy link
Member

Choose a reason for hiding this comment

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

😻


@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
internal actor PaywallEventStore: PaywallEventStoreType {

Copy link
Member

Choose a reason for hiding this comment

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

there isn't a way to establish priorities on an actor level, right? Only at Task? Ideally we'd make everything events-related super low priority

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have to do it manually creating a separate Task. I could put it at the top level (PaywallEventsManager), but I wonder if internally the other actors will override that priority 🤔

Comment on lines +41 to +49
func store(_ storedEvent: PaywallStoredEvent) async {
do {
Logger.verbose(PaywallEventStoreStrings.storing_event(storedEvent.event))

await self.handler.append(line: try PaywallEventSerializer.encode(storedEvent))
} catch {
Logger.error(PaywallEventStoreStrings.error_storing_event(error))
}
}
Copy link
Member

Choose a reason for hiding this comment

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

we're not exactly an MMP, so this is probably fine for now. But writing to disk on every event is probably something we'll want to avoid in the future. For now we should make sure this gets very low priority

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This uses FileHandle.write(contentsOf:) (the Foundation type).
I obviously haven't done a lot of performance testing yet, but based on the docs it seems like it doesn't immediately write to disk.

See also:

func synchronize()
Causes all in-memory data and attributes of the file represented by the file handle to write to permanent storage.
Programs that require the file to always be in a known state should call this method. An invocation of this method doesn’t return until memory is flushed.

We don't call it, so I think it's safe to assume it gets put in a buffer first.

Copy link
Member

Choose a reason for hiding this comment

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

oh awesome!


/// Deletes the first N lines from the file, without loading the entire file in memory.
func removeFirstLines(_ count: Int) async throws

Copy link
Member

Choose a reason for hiding this comment

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

protocols + mock implementations is what we should always have done, I'm glad we're moving away from inherit / replace for these. Much easier to isolate behavior

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Totally. And these being actors + async made mocking these and creating fake in-memory implementations so easy to work with.

}

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
actor FileHandler: FileHandlerType {
Copy link
Member

Choose a reason for hiding this comment

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

Can't comment on the code that's not modified in the PR, but it looks great. The only way I can think of for improving it would be using a circular buffer for removing lines instead of an aux file to avoid extra disk reads

Copy link
Member

Choose a reason for hiding this comment

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

which maybe we can revisit one day if we start having a lot of events

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way removing lines is implemented is sort of like a circular buffer though (it reads and writes in chunks to prevent the entire file in memory all at once).

Sources/Paywalls/Events/PaywallEventStore.swift Outdated Show resolved Hide resolved
- New `PaywallEventStore` using `FileHandler` (#2673)
- `MockFileHandler`
- `PaywallStoredEvent`: this contains the necessary information to store an event: `PaywallEvent` + user ID
- `Created PaywallEventSerializer`
@NachoSoto NachoSoto merged commit 65c692b into paywalls Sep 7, 2023
2 of 8 checks passed
@NachoSoto NachoSoto deleted the paywalls-events-store branch September 7, 2023 23:30
NachoSoto added a commit that referenced this pull request Sep 7, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 8, 2023
- New `PaywallEventStore` using `FileHandler` (#2673)
- `MockFileHandler`
- `PaywallStoredEvent`: this contains the necessary information to store
an event: `PaywallEvent` + user ID
- Created `PaywallEventSerializer`
NachoSoto added a commit that referenced this pull request Sep 8, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 8, 2023
This combines the types created in prior PRs (#3157, #3158) to store and post events.
NachoSoto added a commit that referenced this pull request Sep 8, 2023
This combines the types created in prior PRs (#3157, #3158) to store and
post events.
NachoSoto added a commit that referenced this pull request Sep 14, 2023
- New `PaywallEventStore` using `FileHandler` (#2673)
- `MockFileHandler`
- `PaywallStoredEvent`: this contains the necessary information to store
an event: `PaywallEvent` + user ID
- Created `PaywallEventSerializer`
NachoSoto added a commit that referenced this pull request Sep 14, 2023
This combines the types created in prior PRs (#3157, #3158) to store and
post events.
NachoSoto added a commit that referenced this pull request Sep 14, 2023
- New `PaywallEventStore` using `FileHandler` (#2673)
- `MockFileHandler`
- `PaywallStoredEvent`: this contains the necessary information to store
an event: `PaywallEvent` + user ID
- Created `PaywallEventSerializer`
NachoSoto added a commit that referenced this pull request Sep 14, 2023
This combines the types created in prior PRs (#3157, #3158) to store and
post events.
NachoSoto added a commit that referenced this pull request Sep 15, 2023
- New `PaywallEventStore` using `FileHandler` (#2673)
- `MockFileHandler`
- `PaywallStoredEvent`: this contains the necessary information to store
an event: `PaywallEvent` + user ID
- Created `PaywallEventSerializer`
NachoSoto added a commit that referenced this pull request Sep 15, 2023
This combines the types created in prior PRs (#3157, #3158) to store and
post events.
NachoSoto added a commit that referenced this pull request Sep 15, 2023
**This is an automatic release.**
### New Features
#### ✨ Introducing RevenueCatUI 📱

RevenueCat's Paywalls allow you to to remotely configure your entire
paywall view without any code changes or app updates.
Our paywall templates use native code to deliver smooth, intuitive
experiences to your customers when you’re ready to deliver them an
Offering; and you can use our Dashboard to pick the right template and
configuration to meet your needs.

To use RevenueCat Paywalls on iOS, simply:

1. Create a Paywall on the Dashboard for the `Offering` you intend to
serve to your customers
2. Add the `RevenueCatUI` SPM dependency to your project
3. `import RevenueCatUI` at the point in the user experience when you
want to display a paywall:

```swift
import RevenueCatUI
import SwiftUI

struct YourApp: View {

    var body: some View {
        YourContent()
            .presentPaywallIfNeeded(
                requiredEntitlementIdentifier: "pro",
                purchaseCompleted: { customerInfo in
                    print("Purchase completed: \(customerInfo)")
                },
                restoreCompleted: { customerInfo in
                    print("Purchases restored: \(customerInfo)")
                }
            )
    }

}
```

You can find more information in [our
documentation](https://rev.cat/paywalls).

<details>

<summary>List of changes</summary>
* NachoSoto: `Paywalls`: renamed `PaywallEvent.view` to `.impression`
(#3212)
* NachoSoto: `Paywalls`: loading indicator for in-progress purchases
(#3217)
*  NachoSoto: `Paywalls`: fixed template 4 bottom padding (#3211)
* NachoSoto: `Paywalls`: only pre-warm images/intro-eligibility for
`Offerings.current` (#3210)
* NachoSoto: `Paywalls`: fixed mock intro eligibility on snapshot tests
(#3205)
*  NachoSoto: `Paywalls`: fixed SimpleApp release build (#3203)
*  NachoSoto: `Paywalls`: improved `DebugErrorView` layout (#3204)
* NachoSoto: `Paywalls`: refactored `PurchaseHandler` extracting
protocol (#3196)
*  NachoSoto: `Paywalls`: automatically flush events (#3177)
* NachoSoto: `Paywalls`: fixed `TemplateBackgroundImageView` aspect
ratio (#3201)
*  NachoSoto: `Paywalls`: fixed broken layout on template 4 (#3202)
*  NachoSoto: `Paywalls`: events unit and integration tests (#3169)
*  NachoSoto: `Paywalls`: send events to `Purchases` (#3164)
*  NachoSoto: `Paywalls`: convert empty images into `nil` (#3195)
*  NachoSoto: `Paywalls`: new `onRestoreCompleted` handler (#3190)
* NachoSoto: `Paywalls`: fixed `IntroEligibilityViewModel` data lifetime
(#3194)
* NachoSoto: `Paywalls`: test plan for running non-snapshot tests
(#3188)
*  NachoSoto: `Paywalls`: polish template 4 (#3183)
* NachoSoto: `Paywalls`: fixed data flow resulting in multiple
`PurchaseHandler` instances (#3187)
* Cesar de la Vega: `Paywalls`: update `blurred_background_image` key in
`PaywallData` test fixture (#3186)
*  NachoSoto: `Paywalls`: added `Purchases.track(paywallEvent:)` (#3160)
* NachoSoto: `Paywalls`: don't apply dark appearance with no dark mode
colors (#3184)
* NachoSoto: `Paywalls`: fixed template 2 + `.condensedFooter` + iPad
(#3185)
* NachoSoto: `Paywalls`: new `{{ sub_duration_in_months }}` variable
(#3173)
*  NachoSoto: `Paywalls`: created `PaywallEventsManager` (#3159)
* NachoSoto: `Paywalls`: implemented `PostPaywallEventsOperation`
(#3158)
* NachoSoto: `Paywalls`: new `{{ sub_relative_discount }}` variable
(#3131)
*  Charlie Chapman: `Paywalls`: improved `FooterView` (#3171)
* NachoSoto: `Paywalls`: fixed `FooterView` horizontal centering (#3172)
*  NachoSoto: `Paywalls`: created `PaywallEventStore` (#3157)
*  NachoSoto: `Paywalls`: add `PaywallEvent` model (#3156)
*  NachoSoto: `Paywalls`: add `PaywallData.revision` (#3155)
* NachoSoto: `Paywalls`: support fuzzy-Locale search in `iOS 15` (#3162)
* NachoSoto: `PaywallData`: added `@NonEmptyString` to `subtitle` and
`offerName` (#3150)
* NachoSoto: `Paywalls`: add paywall for Load Shedder integration tests
(#3151)
* NachoSoto: `Paywalls`: fixed error view being displayed on release
builds (#3141)
* NachoSoto: `Paywalls`: improved `{{ total_price_and_per_month }}` to
include period (#3136)
* NachoSoto: `Paywalls`: `{{ price_per_period }}` now takes
`SubscriptionPeriod.value` into account (#3133)
*  NachoSoto: `Paywalls`: add Arabic to SimpleApp for testing (#3132)
* NachoSoto: `Paywalls`: update snapshot generation with new separate
git repo (#3116)
*  NachoSoto: `Paywalls`: add support for CTA button gradients (#3121)
*  NachoSoto: `Paywalls`: template 5 (#3095)
* NachoSoto: `Paywalls`: replaced submodule with `gitignore`d reference
(#3125)
* NachoSoto: `Catalyst`: fixed a couple of Catalyst build warnings
(#3120)
* NachoSoto: `Paywalls`: reference test snapshots from submodule (#3115)
*  NachoSoto: `Paywalls`: removed `presentedPaywallViewMode` (#3109)
* NachoSoto: `Paywalls`: remove duplicate `RevenueCat` scheme to fix
Carthage (#3105)
*  NachoSoto: `Paywalls`: fixed iOS 12 build (#3104)
*  NachoSoto: `Paywalls`: fixed template 2 inconsistent spacing (#3091)
*  NachoSoto: `Paywalls`: improved test custom paywall (#3089)
*  NachoSoto: `Paywalls`: avoid warming up cache multiple times (#3068)
*  NachoSoto: `Paywalls`: added all localization (#3080)
* NachoSoto: `Paywalls`: temporarily disable `PaywallTemplate.template4`
(#3088)
*  NachoSoto: `Paywalls`: enabled `Catalyst` support (#3087)
*  NachoSoto: `Paywalls`: iPad polish (#3061)
*  NachoSoto: `Paywalls`: added MIT license to all headers (#3084)
* NachoSoto: `Paywalls`: improved unselected package background color
(#3079)
*  NachoSoto: `Paywalls`: handle already purchased state (#3046)
* NachoSoto: `Paywalls`: only dismiss `PaywallView` when explicitly
presenting it with `.presentPaywallIfNeeded` (#3075)
* NachoSoto: `Paywalls`: add support for generating snapshots on CI
(#3055)
* NachoSoto: `Paywalls`: removed unnecessary `PaywallFooterView` (#3064)
* Josh Holtz: `Paywalls`: new `PaywallFooterView` to replace `modes`
(#3051)
*  Josh Holtz: `Paywalls`: rename card to footer (#3049)
* NachoSoto: `Paywalls`: changed `total_price_and_per_month` to include
period (#3044)
* NachoSoto: `Paywalls`: internal documentation for implementing
templates (#3053)
*  NachoSoto: `Paywalls`: finished `iOS 15` support (#3043)
* NachoSoto: `Paywalls`: validate `PaywallData` to ensure displayed data
is always correct (#3019)
* NachoSoto: `Paywalls`: fixed `total_price_and_per_month` for custom
monthly packages (#3027)
*  NachoSoto: `Paywalls`: tweaking colors on template 2&3 (#3011)
*  NachoSoto: `Paywalls`: changed snapshots to scale 1 (#3016)
* NachoSoto: `Paywalls`: replaced `defaultLocale` with
`preferredLocales` (#3003)
* NachoSoto: `Paywalls`: improved `PaywallDisplayMode.condensedCard`
layout (#3001)
*  NachoSoto: `Paywalls`: `.card` and `.condensedCard` modes (#2995)
*  NachoSoto: `Paywalls`: prevent multiple concurrent purchases (#2991)
*  NachoSoto: `Paywalls`: improved variable warning (#2984)
*  NachoSoto: `Paywalls`: fixed horizontal padding on template 1 (#2987)
* NachoSoto: `Paywalls`: changed `FooterView` to always use `text1`
color (#2992)
*  NachoSoto: `Paywalls`: retry test failures (#2985)
* NachoSoto: `Paywalls`: send presented `PaywallViewMode` with purchases
(#2859)
*  NachoSoto: `Paywalls`: added support for custom fonts (#2988)
* NachoSoto: `Paywalls`: improved template 2 unselected packages (#2982)
* Josh Holtz: `Paywalls`: fix template 2 selected text offer details
color (#2975)
*  NachoSoto: `Paywalls`: warm-up image cache (#2978)
*  NachoSoto: `Paywalls`: extracted `PaywallCacheWarming` (#2977)
*  NachoSoto: `Paywalls`: fixed color in template 3 (#2980)
*  NachoSoto: `Paywalls`: improved default template (#2973)
*  NachoSoto: `Paywalls`: added links to documentation (#2974)
*  NachoSoto: `Paywalls`: updated template names (#2971)
*  NachoSoto: `Paywalls`: updated variable names (#2970)
* NachoSoto: `Paywalls`: added JSON debug screen to
`debugRevenueCatOverlay` (#2972)
*  NachoSoto: `Paywalls`: multi-package horizontal template  (#2949)
*  NachoSoto: `Paywalls`: fixed template 3 icon aspect ratio (#2969)
*  NachoSoto: `Paywalls`: iOS 17 tests on CI (#2955)
*  NachoSoto: `Paywalls`: deploy `debug` sample app (#2966)
*  NachoSoto: `Paywalls`: sort offerings list in sample app (#2965)
*  NachoSoto: `Paywalls`: initial iOS 15 support (#2933)
* NachoSoto: `Paywalls`: changed default `PaywallData` to display
available packages (#2964)
*  NachoSoto: `Paywalls`: changed `offerDetails` to be optional (#2963)
*  NachoSoto: `Paywalls`: markdown support (#2961)
*  NachoSoto: `Paywalls`: updated icon set to match frontend (#2962)
*  NachoSoto: `Paywalls`: added support for `PackageType.custom` (#2959)
* NachoSoto: `Paywalls`: fixed `tvOS` compilation by making it
explicitly unavailable (#2956)
* NachoSoto: `Paywalls`: fix crash when computing localization with
duplicate packages (#2958)
*  NachoSoto: `Paywalls`: UIKit `PaywallViewController` (#2934)
* NachoSoto: `Paywalls`: `presentPaywallIfNecessary` ->
`presentPaywallIfNeeded` (#2953)
* NachoSoto: `Paywalls`: added support for custom and lifetime products
(#2941)
* NachoSoto: `Paywalls`: changed `SamplePaywallsList` to work offline
(#2937)
* NachoSoto: `Paywalls`: fixed header image mask on first template
(#2936)
*  NachoSoto: `Paywalls`: new `subscription_duration` variable (#2942)
* NachoSoto: `Paywalls`: removed `mode` parameter from
`presentPaywallIfNecessary` (#2940)
*  NachoSoto: `Paywalls`: improved `RemoteImage` error layout (#2939)
* NachoSoto: `Paywalls`: added default close button when using
`presentPaywallIfNecessary` (#2935)
* NachoSoto: `Paywalls`: added ability to preview templates in a
`.sheet` (#2938)
*  NachoSoto: `Paywalls`: avoid recomputing variable `Regex` (#2944)
*  NachoSoto: `Paywalls`: improved `FooterView` scaling (#2948)
* NachoSoto: `Paywalls`: added ability to calculate and localize
subscription discounts (#2943)
*  NachoSoto: `Offering`: improved description (#2912)
*  NachoSoto: `Paywalls`: fixed `FooterView` color in template 1 (#2951)
*  NachoSoto: `Paywalls`: fixed `View.scrollableIfNecessary` (#2947)
* NachoSoto: `Paywalls`: improved `IntroEligibilityStateView` to avoid
layout changes (#2946)
* NachoSoto: `Paywalls`: updated offerings snapshot with new asset base
URL (#2950)
* NachoSoto: `Paywalls`: extracted `TemplateBackgroundImageView` (#2945)
*  NachoSoto: `Paywalls`: more polish from design feedback (#2932)
*  NachoSoto: `Paywalls`: more unit tests for purchasing state (#2931)
*  NachoSoto: `Paywalls`: new `.onPurchaseCompleted` modifier (#2930)
* NachoSoto: `Paywalls`: fixed `LoadingPaywallView` displaying a
progress view (#2929)
* NachoSoto: `Paywalls`: added default template to `SamplePaywallsList`
(#2928)
*  NachoSoto: `Paywalls`: added a few more logs (#2927)
*  NachoSoto: `Paywalls` added individual previews for templates (#2924)
*  NachoSoto: `Paywalls`: improved default paywall configuration (#2926)
* NachoSoto: `Paywalls`: moved purchasing state to `PurchaseHandler`
(#2923)
*  NachoSoto: `Paywalls`: updated Integration Test snapshot (#2921)
* NachoSoto: `Paywalls`: pre-warm intro eligibility in background thread
(#2925)
*  NachoSoto: `Paywalls`: removed "couldn't find package" log (#2922)
* NachoSoto: `Paywalls`: SimpleApp reads API key from Xcode Cloud
environment (#2919)
* NachoSoto: `Paywalls`: improved template accessibility support (#2920)
* NachoSoto: `Paywalls`: work around SwiftUI bug to allow embedding
`PaywallView` inside `NavigationStack` (#2918)
*  NachoSoto: `Paywalls`: some basic polish from design feedback (#2917)
* NachoSoto: `Paywalls`: added `OfferingsList` to preview all paywalls
(#2916)
* NachoSoto: `Paywalls`: fixed tappable area for a couple of buttons
(#2915)
*  NachoSoto: `Paywalls`: new `text1` and `text2` colors (#2903)
* NachoSoto: `Paywalls`: updated multi-package bold template design
(#2908)
*  NachoSoto: `Paywalls`: added sample paywalls to `SimpleApp` (#2907)
*  NachoSoto: `Paywalls`: one package with features template (#2902)
*  NachoSoto: `Paywalls`: initial support for icons (#2882)
* NachoSoto: `Paywalls`: extracted intro eligibility out of templates
(#2901)
*  NachoSoto: `Paywalls`: changed `subtitle` to be optional (#2900)
* NachoSoto: `Paywalls`: added "features" to `LocalizedConfiguration`
(#2899)
* NachoSoto: `Paywalls`: fixed `{{ total_price_and_per_month }}` (#2881)
*  NachoSoto: `Paywalls`: updated template names (#2878)
*  NachoSoto: `Paywalls`: added accent colors (#2883)
* NachoSoto: `Paywalls`: changed images representation to an object
(#2875)
*  NachoSoto: `Paywalls`: added `offerName` parameter (#2877)
*  NachoSoto: `Paywalls`: new `{{ period }}` variable (#2876)
*  NachoSoto: `Paywalls`: disabled `PaywallViewMode`s for now (#2874)
* NachoSoto: `Paywalls`: added new `defaultPackage` configuration
(#2871)
*  NachoSoto: `Paywalls`: fixed tests on CI (#2872)
* NachoSoto: `Paywalls`: pre-fetch intro eligibility for paywalls
(#2860)
*  Andy Boedo: `Paywalls`: clean up the error view (#2873)
* NachoSoto: `Paywalls`: new API for easily displaying `PaywallView`
with just one line (#2869)
*  NachoSoto: `Paywalls`: handle missing paywalls gracefully (#2855)
* NachoSoto: `Paywalls`: temporarily disable non-fullscreen
`PaywallView`s (#2868)
* NachoSoto: `Paywalls`: added test to ensure package selection
maintains order (#2853)
* NachoSoto: `Paywalls`: added new `blurredBackgroundImage`
configuration (#2852)
*  NachoSoto: `Paywalls`: fuzzy `Locale` lookups (#2847)
*  NachoSoto: `Paywalls`: basic localization support (#2851)
*  NachoSoto: `Paywalls`: added `FooterView` (#2850)
*  NachoSoto: `Paywalls`: multi-package template (#2840)
*  NachoSoto: `Paywalls`: disable animations during unit tests (#2848)
* NachoSoto: `Paywalls`: `TrialOrIntroEligibilityChecker.eligibility(for
packages:)` (#2846)
* NachoSoto: `Paywalls`: added new `total_price_and_per_month` variable
(#2845)
*  NachoSoto: `Paywalls`: extracted `PurchaseButton` (#2839)
*  NachoSoto: `Paywalls`: extracted `IntroEligibilityStateView` (#2837)
* NachoSoto: `Paywalls`: support for multiple `PaywallViewMode`s (#2834)
* NachoSoto: `Paywalls`: add support for multiple images in template
configuration (#2832)
* NachoSoto: `Paywalls`: extracted configuration processing into a new
`TemplateViewConfiguration` (#2830)
* NachoSoto: `Paywalls`: improved support for dynamic type with
snapshots (#2827)
* NachoSoto: `Paywalls`: disable `macOS`/`macCatalyst`/`watchOS` for now
(#2821)
* NachoSoto: `Paywalls`: using new color information in template (#2823)
*  NachoSoto: `Paywalls`: set up CI tests and API Tester (#2816)
*  NachoSoto: `Paywalls`: added support for decoding colors (#2822)
* NachoSoto: `Paywalls`: ignore empty strings in
`LocalizedConfiguration` (#2818)
*  NachoSoto: `Paywalls`: updated `PaywallData` field names (#2817)
*  NachoSoto: `Paywalls`: added support for purchasing (#2812)
* NachoSoto: `Paywalls`: added tests for `PackageType` filtering (#2810)
* Andy Boedo: `Paywalls`: changed variable handling to use Swift `Regex`
(#2811)
*  NachoSoto: `Paywalls`: added `price` variable (#2809)
*  NachoSoto: `Paywalls`: determine intro eligibility (#2808)
*  NachoSoto: `Paywalls`: added header image to configuration (#2800)
*  NachoSoto: `Paywalls`: added `packages` to configuration (#2798)
* NachoSoto: `Paywalls`: add support for displaying
`StoreProductDiscount`s (#2796)
*  NachoSoto: `Paywalls`: added support for variables (#2793)
* NachoSoto: `Paywalls`: using `PaywallData` and setting up basic
template loading (#2781)
*  NachoSoto: `Paywalls`: initial configuration types (#2780)
*  NachoSoto: `Paywalls`: initial `RevenueCatUI` target setup (#2776)

</details>

### Other Changes

* `Debug`: add `Offering` metadata to debug screen (#3137) via NachoSoto
(@NachoSoto)
* `TestStoreProduct`: new `locale` parameter (#3134) via NachoSoto
(@NachoSoto)
* `Integration Tests`: fixed more flaky failures (#3218) via NachoSoto
(@NachoSoto)

---------

Co-authored-by: NachoSoto <ignaciosoto90@gmail.com>
Co-authored-by: NachoSoto <NachoSoto@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor A code change that neither fixes a bug nor adds a feature RevenueCatUI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants