Regressed recently in library. When a profile was "Inactive
(on-demand)", saving it would revert to "Inactive" because the
underlying manager was being disabled.
Merge former ContainerView into main view and define platform-specific
subviews:
- ContainerView (composition of content + filters)
- ContentView
- FiltersView
Reuse the same receipt trick from iOS.
Also, fix a regression in IAPManager.fetchLevelIfNeeded() from #903,
where a guard after an await was dropped leading to reentrancy issues.
- PaywallView is the paywall content
- PaywallModifier attaches paywall with optional confirmation
- PurchaseRequiredButton presents paywall explicitly
- PaywallReason is the compound input
Refactoring:
- PurchaseRequiredButton takes a custom view
- PurchaseAlertModifier was merged into PaywallModifier
- PurchaseButtonModifier was merged into PurchaseRequiredButton
- Modal options were packed into a single struct
Confirmation alert presented on:
- Connect to ineligible profile (AppCoordinator)
- Save ineligible profile (ProfileCoordinator)
Includes:
- Credits
- Donations
- Diagnostics
- Version
Had to:
- Wrap tab view into a NavigationStack for full-screen navigation
- Take out navigation titles of about subviews
- Customize donations view layout with modifier
- Fix credits and debug log to support scrolling
Closes#914
- 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.
With some housekeeping.
Bugfixing:
- Do NOT skip empty remote profiles, allow removal when mirroring
- Look up profile in all profiles, not just filtered
- Posptone non-included profile removal
Refactoring:
- Rename ProfileProcessor to InAppProcessor
- Provides ProfileProcessor + TunnelProcessor protocols
- willSave -> willRebuild (because not always called on save)
- Notify ProfileManager import events