Suggest whenever .fullTV is suggested. For this reason, subscriptions
are not suggested to existing full version purchasers, because they only
miss the one-time .appleTV purchase. Group purchases by feature products
and full version products, e.g.:
- Features
- Apple TV
- Full version
- Yearly
- Monthly
- Full
- Full + TV
Additionally, fix reloadReceipt() slowing down onLaunch() sometimes. The
warning sign would appear on restricted profiles until the receipt is
loaded.
- Present paywall only on save/connect because PurchaseRequiredButton
instances were presenting paywalls with partial requirements
- Retain PurchaseRequiredButton just to flag paid features visually, but
do nothing on tap
- Suggest paywall products via IAPManager and required features, rather
than from views
- Handle .sharing/.appleTV requirements in ProfileCoordinator, rather
than in StorageSection
- Discontinue platform purchases, but treat as full if iOS + macOS
Restore CDModulePreferencesV3 to track the history of module prefrences.
This way, excluded endpoints may be saved globally to Core Data as a
starting point. Then in Profile.userInfo we only save the relevant
exclusions for the current configuration.
The .excludedEndpoints relationship is therefore moved out of
CDProviderPreferencesV3.
Further refactoring:
- ModuleViewParameters now includes a ModulePreferences observable that
module views can observe
- Tunnel doesn't need access to PreferencesManager anymore (exclusions
are in Profile.userInfo)
Store module preferences in the Profile.userInfo field for atomicity.
Access and modification are dramatically simplified, and synchronization
comes for free.
On the other side, fix provider preferences synchronization by using
viewContext for the CloudKit container.
Fixes#992
Formerly via blocks, now with final classes.
App:
- ProfileProcessor
- AppTunnelProcessor
- Implemented by DefaultAppProcessor in app
- Implemented by MockAppProcessor in UILibrary (for previews)
Tunnel:
- PacketTunnelProcessor
- Implemented by DefaultTunnelProcessor
Especially for flaky tests:
- Do objectWillChange.send() _before_ performing the change
- Send more events to .didChange to be more deterministic about test
expectations