Commit Graph

9 Commits

Author SHA1 Message Date
Davide
89d7af4df7
Rethink eligibility checks (#889)
- Allow unrestricted save, but show PurchaseRequiredButton
- Warn however about paid features (FIXME)
- Redesign features in paywall
- Strip already eligible features from paywall
- List required features in restricted alert
- Localize feature descriptions
- Review propagation of paywall modifiers/reasons

Extra:

- Move more domain entities from UILibrary to CommonLibrary
- Default on-demand policy to .any (free feature)
- Fix modals not reappearing after closing with gesture
- Extend UILibrary start-up assertions
2024-11-18 17:43:01 +01:00
Davide
008b78cc7c
Upgrade to Xcode 16 (#858)
- Address further restrictions on actor-isolation by using `nonisolated`
on:
  - Combine subjects
  - Core Data context/controller
  - Blocks
- In previews using inline `@State`, create a custom view instead
- Use `@retroactive` in l10n extensions
- Fix compile error in WireGuardKit
2024-11-13 12:07:30 +01:00
Davide
21340e9f56
Rewrite AppContext event handlers (#839)
Loading remote profiles before local profiles may cause duplicated NE
managers. This happened because if local profiles are empty, any remote
profile is imported regardless of their former existence in the local
store. The importer just doesn't know.

Therefore, revisit the sequence of AppContext registrations:

- First off
- Skip Tunnel prepare() because NEProfileRepository.fetch() does it
already
- NE is both Tunnel and ProfileRepository, so calling tunnel.prepare()
loads local NE profiles twice
- onLaunch() - **run this once and before anything else**
  - Read local profiles
  - Reload in-app receipt
  - Observe in-app eligibility → Triggers onEligibleFeatures()
  - Observe profile save → Triggers onSaveProfile()
  - Fetch providers index
- onForeground()
  - Read local profiles
  - Read remote profiles, and toggle CloudKit sync based on eligibility
- onEligibleFeatures()
  - Read remote profiles, and toggle CloudKit sync based on eligibility
- onSaveProfile()
  - Reconnect if necessary
2024-11-10 17:51:28 +01:00
Davide
e07833b2a4
Revisit in-app eligibility for iCloud sharing (#837)
Restore .sharing feature:

- Merge "Apple TV" into "iCloud" section
  - "Enabled", disabled if ineligible for .sharing
  - "Apple TV", disabled if ineligible for .appleTV || !isShared
- Footer about TV restrictions

Paywalls:

- "Share on iCloud" if ineligible for .sharing
- "Drop TV restriction" if eligible for .sharing but not for .appleTV
  - Applies to full version products (user level 2)
  - Suggest Apple TV product

Restrictions:

- Toggle CloudKit sync on remote repository based on .sharing
eligibility
- Do not start tunnel on Apple TV if ineligible for .appleTV

Fixes:

- Incorrect zip() publishers in remote repository
- Resolve duplicates in Core Data, first profile wins sorted by
lastUpdate descending
- Reload receipt on OOB IAPManager events
2024-11-09 15:20:59 +01:00
Davide
8fbccc6d80
Add donations UI and in-app error handling (#833)
- Reuse same product views from paywall
- Handle errors in fetch products
- Hide views on fetch products error
- Disable views during purchase

Closes #830
2024-11-07 23:02:10 +01:00
Davide
bba661f104
Implement TV profile expiration (#811)
Based on in-app eligibility, expire TV profiles after 10 minutes.
Refactor/redesign general sections and offer .sharing feature for free,
it makes it simpler to focus on Apple TV product.
2024-11-05 10:03:54 +01:00
Davide
f3d13d0cdf
Refactor AppContext creation and profile processing (#810)
Streamline initialization of AppContext objects without singletons,
especially because some are interconnected.

Rethink ProfileProcessor to be the only gateway of profile processing
for:

- Include
- Save
- Connect

Provide closures with access to the IAPManager for eligibility checks.

Finally, take a ProfileProcessor parameter in:

- ProfileManager (for isIncluded and willSave)
- ExtendedTunnel (for willConnect)

so that it's used implicitly without having to put it into the SwiftUI
environment.

Other than that:

- Move AppError to CommonLibrary
- Skip decoding of attributes from Core Data because they are already
part of the profile
2024-11-04 23:34:22 +01:00
Davide
454efb8e50
Refactor ModuleType to be a single source of truth (#800)
Rather than defining a new enum, tie ModuleType to ModuleHandler names
from PassepartoutKit.

Also a way to reuse ModuleType.localizedDescription on both Module and
ModuleBuilder implementations.
2024-11-02 15:23:36 +01:00
Davide
070b661c43
Refactor library targets (#799)
Renames:

- AppUI → UILibrary
- AppUIPlatform → AppUI (conditional umbrella) + AppUI[Main|TV]
- APILibrary/CommonLibrary/UtilsLibrary → Common[API|Library|Utils]

Dependencies:

- AppUI → UILibrary
- UILibrary → AppLibrary, CommonAPI
- AppLibrary → CommonLibrary, CommonUtils
2024-11-02 10:11:59 +01:00