Commit Graph

26 Commits

Author SHA1 Message Date
Davide f13a292b4b
Refactor String identifiers (#920)
- Group all views under "views.*"
- Split global strings into actions and nouns
- Use underscores
- Clean up unused

Fixes #835
2024-11-23 20:31:22 +01:00
Davide 2a46173169
Move more views to UILibrary (#919)
- Move about subviews to UILibrary
- Refactor about to single coordinator + platform views
- Refactor debug log to single view + content views
- Take out debug log routes from about routes
- Rename Settings* to Preferences*
- Reuse empty modifier in debug log
- Fix a visual bug in .themeTrailingValue() (extra Spacer)

Preparation for #914
2024-11-23 19:26:33 +01:00
Davide 9b366dcaa0
Minor UI fixes (#910)
Update library with some more meaningful names for Profile accessors.

Refactor a few things about TV here and there.
2024-11-22 10:05:46 +01:00
Davide 74ed93a966
Check provider requirements before connecting (#896)
E.g. interactive login must be presented afterwards.
2024-11-19 20:51:55 +01:00
Davide 9528cecc27
Verify profile before presenting interactive login (#893)
If the profile is ineligible for features other than .interactiveLogin,
the interactive prompt would still be presented, but the user would hit
the paywall right afterwards.
2024-11-19 11:46:42 +01:00
Davide 35c10309a7
Reload receipt on purchase (#892)
StoreKit ProductView performs the purchases internally without calling
IAPManager.purchase(), which causes the IAPManager state to be
momentarily outdated.

Leverage PaywallView.onComplete() to reload the receipt and eventually
trigger IAPManager.objectWillChange, so that the app is immediately
unlocked on a successful purchase.
2024-11-19 11:36:36 +01:00
Davide bac1d494a4
Upscale upgrade icon only on macOS 2024-11-19 11:18:00 +01:00
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 3a5e3889d3
Add more view modifiers (#838)
1. ThemeProgressViewModifier to replace content with a progress view
while a condition is active
2. ThemeEmptyContentModifier to replace content with a message if an
empty condition is met
3. Replace .opacity(bool ? 1.0 : 0.0) with .opaque(bool)

Reuse:

- 1 in PaywallView and DonateView
- 2 in ProfileContainerView
2024-11-10 12:00:07 +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 2c1ccbcbfd
Finalize paywall UI (#831)
- Use StoreKit views when available
- Offer one-time purchase
- Recurring subscriptions for all features
- Restore purchases

Remove .siri (Shortcuts), now free.

Closes #819
Closes #469
2024-11-07 18:27:36 +01:00
Davide 22a5cb9af2
Update FIXMEs 2024-11-07 12:48:10 +01:00
Davide d5ac785bb8
Simulate in-app purchases (#818)
Integrate in-app helper into IAPManager and simulate purchases with an
in-memory receipt.
2024-11-05 18:55:57 +01:00
Davide 9286ead348
Improve logging on ineligible features 2024-11-05 14:10:17 +01:00
Davide 735d3b2fbe
Improve footers in macOS form sections (#814)
Revisit the use of informational footers in forms because:

- iOS uses Section footers
- macOS uses a secondary label below the main row label

Therefore:

- Add .themeRow() modifier to accomplish macOS behavior
- iOS: leave .themeSection() as is, and add a dummy .themeRow() that
does nothing
- macOS: make footer ineffective in .themeSection(), but add .themeRow()
modifiers to move footers to rows
2024-11-05 13:32:09 +01:00
Davide 346aaec441
Reuse PurchaseButtonModifier in restricted areas (#815)
Fixes #687
2024-11-05 13:27:05 +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 2790a2aac2
Merge AppLibrary into CommonLibrary (#806)
CommonLibrary barely used as standalone, almost always together with
AppLibrary.
2024-11-03 13:16:13 +01:00
Davide 1d2de39d49
Use profile name as interactive view title 2024-11-03 11:44:14 +01:00
Davide fbe2d84113
Submit on OpenVPN fields (#805)
Submit on password or OTP depending on the selected method.
2024-11-03 11:27:12 +01:00
Davide 15959d2422
Resolve some focus issues (#802)
- [x] tvOS: When profile selector appears, if it's closed without
selecting any profile, it instantly reopens
- [x] Set initial focus in OpenVPN credentials
2024-11-03 08:17:19 +01:00
Davide aba5081450
Refactor and improve interactive login (#801)
Define two styles for interactive login:

- Modal (iOS/macOS) - Form inside NavigationStack
- Inline (tvOS) - VStack

Requires OpenVPN credentials view to be container-agnostic.

Play with focus to improve the overall TV experience.
2024-11-02 15:24:41 +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