Commit Graph

17 Commits

Author SHA1 Message Date
Davide
f8e623e1fe
Fix regressions with CloudKit synchronization (#1029)
The remote container is shared by ProfileManager and
PreferencesManager, but it must be the same for CloudKit sync
to work properly.

Externalize the logic of onEligibleFeatures() so that the
AppContext singleton can update the managers (and their
repositories) with the new remote store.

Now that the remote profile repository is reloaded every time that
eligible features change, the .removeDuplicates() may also be
restored. Just add a .dropFirst() to skip the initially empty
value of eligible features. Even when features are eventually empty,
a value is always emitted after IAPManager.reloadReceipt()

Lastly, enable Core Data lightweight migration.

Regressions from #1017
2024-12-20 10:05:07 +01:00
Davide
810b8e4bd4
Fix compile errors on iOS 2024-12-18 10:30:02 +01:00
Davide
c527171957
Simplify products (#1024)
Only offer compensations to former purchasers:

- .appleTV to .full purchasers
- .full to .appleTV purchasers

Always suggest .fullTV to new purchasers.

Finally rename:

- .full to .iOS_macOS
- .fullTV to .allFeatures (lifetime)
2024-12-18 10:15:58 +01:00
Davide
6255a273fe
Add recurring products to paywall (#1019)
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.
2024-12-17 18:23:27 +01:00
Davide
789f6ad515
Unify paywall and eligibility (#1018)
- 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
2024-12-16 21:45:36 +01:00
Davide
3a1ef87b95
Fix ProfileManagerTests waiting for wrong event 2024-12-15 14:06:17 +01:00
Davide
81aa3a2714
Skip onboarding migration if no migratable profiles (#1002)
Annoying!
2024-12-11 22:20:14 +01:00
Davide
ff88b3562d
Clean up dangling module preferences (#999)
Erase on module removal, reference is otherwise lost forever.
2024-12-10 20:33:35 +01:00
Davide
6f9c78b257
Track module preferences history in Core Data (#994)
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)
2024-12-10 14:13:10 +01:00
Davide
aeec943c58
Move ModulePreferences to Profile.userInfo (#993)
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
2024-12-10 11:18:52 +01:00
Davide
93a15cd766
Review incorrect behavior in preferences (#989)
- Save/rollback was done outside of MOC
- Use different contexts for module/provider preferences
  - Save providers → also saves modules
  - Discard modules → also discards providers
- Use background context because it's not automatically merged (can
rollback)
- Expose ModulePreferences in OpenVPNView as StateObject
- Rework Blacklist to a more reusable ObservableList
- Reapply #988
2024-12-09 08:44:13 +01:00
Davide
aac04c4008
Move processor implementations to concrete objects (#983)
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
2024-12-08 16:24:23 +01:00
Davide
a4ebea1f95
Handle load/save preferences inside ProfileEditor (#982)
Simplify preferences model by doing a bulk load/save together with
load/save Profile. ModulePreferences is now a struct rather than an
ObservableObject, because it doesn't need ad hoc observation. It's just
a binding to ProfileEditor.preferences

Fix:

- Disable CloudKit in tunnel singleton of PreferencesManager
(.sharedForTunnel)

Additionally:

- Replace MainActor in PreferencesManager with Sendable (immutable)
- Replace MainActor from ProviderPreferencesRepository with Sendable
(syncs on NSManagedObjectContext)
- Drop ModuleMetadata for good
2024-12-08 16:05:23 +01:00
Davide
14847b2de5
Fix missing test targets 2024-12-06 15:52:25 +01:00
Davide
f87cc1da0b
Fix OpenVPN/WireGuard import error messages (#967)
OpenVPN parser was indirectly swallowing WireGuard errors.
2024-12-01 21:33:58 +01:00
Davide
e761979134
Extend ProfileManager events (#964)
Especially for flaky tests:

- Do objectWillChange.send() _before_ performing the change
- Send more events to .didChange to be more deterministic about test
expectations
2024-11-28 22:56:12 +01:00
Davide
7af703c164
Move app library to the root (#962)
Makes it easier to search among app files and library files.
2024-11-28 17:45:18 +01:00