- Simplify badges
- Drop app description, annoying to maintain (refer to the website)
- Drop screenshots (refer to the App Store)
- Update Credits
- Inform about private PassepartoutKit
Fixes#613
Revert #996 and do something midway:
- When set, use preset filter as selection (disambiguate compatible
presets)
- Set initial preset filter with current selected server preset
Server selection still picks a random preset if:
- Preset filter is "Any"
- More than one preset is compatible
Could not create the Preferences Core Data container in the App Group
because sub-directories did not exist. Create them upfront when using
App Group URLs.
This was not an issue with other Core Data containers because they are
stored in the app directories, where "Library/Documents" already exists.
Add TV screenshots and organize PassepartoutUITests with two test plans
for generating iOS/macOS (Main) and tvOS (TV) screenshots. Revert to the
.attachment destination and use `xcparse` to export the screenshots.
Change iPad screenshots to portrait.
Then autogenerate framed screenshots in two steps:
- Export the UITests screenshots per device (`export.sh`)
- Embed the results in a HTML/CSS template and take snapshots with
Chrome headless (`compose.sh`)
- Repeat for all devices (iPhone, iPad, Mac and Apple TV)
- Save framed screenshots to the `fastlane` screenshots directory
Unframed for now.
- Split Main/TV targets
- Extend ProfileManager for screenshot scenarios
- Rename UITesting to UIAccessibility
Active profile looks very big on TV simulator, temporarily commented
`.padding(.top, 50)` in ActiveProfileView.
Closes#974
Drop "Any" to rather make the preset filter an explicit preset
selection.
Regardless of `filtersWithSelection`, _always_ enforce the preset filter
to:
- The preset of the currently selected entity
- The first among available presets (normally non-empty)
Fixes#995
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)
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
- 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
Exclude endpoints from OpenVPN modules and providers with the generic
Blacklist<T> observable. Eventually, rebuild the Profile in
PacketTunnelProvider (via DefaultTunnelProcessor) with the applied
exclusions from preferences.
Revisit approach to preferences:
- Module preferences
- Tied to the module and therefore to the parent profile
- Load/save in ProfileEditor on request (rather than on
ProfileEditor.load)
- Provider preferences
- Shared globally across profiles
- Load/save in module view if needed
For more consistency with Core Data:
- Revert to observables for both module and provider preferences
- Treat excluded endpoints as relationships rather than a serialized
Array
- Add/remove single relationships over bulk delete + re-add
- Do not map the relationships, Blacklist only needs exists/add/remove:
- isExcludedEndpoint
- addExcludedEndpoint
- removeExcludedEndpoint
Some clean-up:
- Move the importer logic to OpenVPNView.ImportModifier
- Move the preview data to OpenVPN.Configuration.Builder.forPreviews
- Drop objectWillChange.send() on .repository didSet to avoid potential
recursion during SwiftUI updates
Closes#971
The list was not animating e.g. on iCloud updates. Move
.themeAnimation() from ProfileContainerView (ContainerModifier) to
ProfileListView/ProfileGridView.
Sort out the increasing mess coming from:
- AppContext*
- Dependencies
- Shared*
by doing the following:
- Keep in the "Shared" folder only the entities actually shared by
App/Tunnel
- Create TunnelContext
- Move AppContext and related to the App/Context folder
- Move TunnelContext and related to the Tunnel/Context folder
- Delete Shared+* extensions, use AppContext/TunnelContext singletons
from the app
- Create a Dependencies factory singleton to create entities in a single
place
- Split extensions by domain
- Make it clear with `func` vs `var` when a dependency method returns a
new instance
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
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
Replace favorites entities with a PreferencesManager, that returns
observables for:
- Module preferences (by module UUID)
- Provider preferences (by ProviderID)
Automate preferences availability in:
- Module views (empty for now)
- VPN server view (favorites)
Synchronize preferences by making this a CloudKit container. Preferences
are also available in the Tunnel by storing the container in the App
Group.