- 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
To get access to modules, try to avoid full Profile objects. Instead,
replace the coupled ProfileHeader occurrences with a new intermediary
ProfilePreview everywhere.
This way, a ProfileProcessor can inject the localized modules
descriptions from above with the preview() method.
First, rename `force` parameter of ProfileManager.save() to `isLocal`,
because it's meant to be used when saving local profiles. In such
scenario, a profile that is also remotely shared _must_ be re-saved to
the remote repository.
This was not being done when selecting a provider server, and it could
be noticed because the other devices would only receive the iCloud
update after editing the profile and re-doing a manual "Save". Only at
that point would the new profile be re-shared on iCloud.
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.
Visually clarify that a profile requires a purchase to be enabled.
- Implement AppFeatureRequiring in Profile
- Refactor IAPManager.verify() accordingly
- Pre-compute required features in ProfileManager via ProfileProcessor
- 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
Finalize migration flow:
- Add entry to "Add" menu
- Suggest to migrate old profiles when there are no profiles
- Add informational message
- Keep included profiles on top
- Allow deletion of migratable profiles
- Fix duplicated Form in preview
- Rename views and models
Improve some Theme modifiers:
- Empty message with full screen option
- Progress modifier with custom view
- Confirmation dialog with custom message
- Do not observe tunnel in grid/list
- Only observe .$currentProfile for grid selection
- Move row tunnel updates to MarkerView
- Debug InstalledProfileView
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
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
Move the following dependencies:
- OpenVPN/OpenSSL
- WireGuard/Go
up the chain until the main App/Tunnel targets, so that UILibrary and
CommonLibrary can abstract from these unnecessary details. Instead, give
module views access to generic implementations via Registry.
Incidentally, this fixes an issue preventing TV previews from working
due to OpenSSL linkage.
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
Add profile attribute `isAvailableForTV` and set specific behavior to:
- Observe shared profiles and delete locally when unshared
- Only keep locally those profiles with the TV attribute enabled
- Add toggle in UI
Additions to the domain:
- Update rather than replace existing Core Data profile
- Attach ProfileAttributes to Profile.userInfo
- Store one-off `fingerprint` UUID on each save
With the above in place, fix and improve ProfileManager to:
- Use `fingerprint` to compare local/remote profiles in history and thus
avoid local re-import of shared profiles
- Use `deletingRemotely` to delete local profiles when removed from the
remote repository (default false)
- Use `isIncluded` filter to exclude certain profiles from the local
repository (default nil)
The dismissal action waited until the current connection was
disconnected.
Consider that AppContext makes the explicit .connect() redundant,
reconnection is already happening after saving a profile while
connected.
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.
Start with the profile tab. Left to do: search and settings.
Fixes and refactoring:
- Listen to changes in current profile in ExtendedTunnel
- Externalize style from TunnelToggleButton and ConnectionStatusText
(renamed from View)
- Add ThemeCountryText for convenience
- Move InteractiveView to AppUI for use in TV, with
OpenVPNCredentialsView
- Move non-UI entities to AppLibrary (IAP, ExtendedTunnel,
ProfileProcessor)
- Take API out of CommonLibrary (tunnel extension does not need it)
- Reorganize theme views/modifiers into separate files
The biggest issue is the hidden and scattered use of both Tunnel and
ConnectionObserver. Only use the latter, and rename it to ExtendedTunnel
for being now a full wrapper around Tunnel (e.g. for .connectionStatus).
In general, restrict the use of EnvironmentObject to:
- Theme
- IAPManager
- ProfileProcessor
- ProviderManager
Always be explicit about:
- ProfileManager
- ExtendedTunnel
Contextually, move some UI entities to the base AppUI target.
- Refactor AppUI initialization in all platforms (sort of template
method pattern)
- Make AppMenu specific to macOS by wrapping it into a folder for
consistency
- Add SizeClassProviding for repeated checks on hsClass/vsClass
Fixes#659
Split AppUI into AppUI and AppUIMain to allow for a new, simplified
AppUITV target tailored for the Apple TV.
As a PoC, present a view with a list of the shared profiles.