Commit Graph

1449 Commits

Author SHA1 Message Date
Davide d0f25d6d6e
Add translations for the former 12 languages (#1005)
Closes #588
2024-12-12 23:32:27 +01:00
Davide 76a570b7b3
Autogenerate framed screenshots from HTML/CSS (#1000)
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
2024-12-11 20:33:58 +01:00
Davide 16a59c6de1
Reuse .pause() in screenshots 2024-12-10 18:59:27 +01:00
Davide 7d327b21d7
Reuse some iOS code in tvOS UI tests 2024-12-10 18:51:51 +01:00
Davide d8447ddb38
Fix a few things about screenshots
- Postpone "Connected" screenshot
- Disable "Only favorites" to avoid iOS failure
- Prefix screenshot filename with device name and "0"
2024-12-10 18:37:53 +01:00
Davide f441a2eed0
Autogenerate screenshots for all platforms (#998)
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
2024-12-10 18:06:23 +01:00
Davide 6f9c78b257
Track module preferences history in Core Data (#994)
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)
2024-12-10 14:13:10 +01:00
Davide aeec943c58
Move ModulePreferences to Profile.userInfo (#993)
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
2024-12-10 11:18:52 +01:00
Davide 93a15cd766
Review incorrect behavior in preferences (#989)
- 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
2024-12-09 08:44:13 +01:00
Davide fae0200995
Exclude OpenVPN endpoints (#987)
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
2024-12-09 02:00:55 +01:00
Davide edaa151911
Fix compile errors from #984 2024-12-08 19:02:31 +01:00
Davide f7013a98a9
Separate App/Tunnel responsibilities (#984)
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
2024-12-08 18:56:39 +01:00
Davide aac04c4008
Move processor implementations to concrete objects (#983)
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
2024-12-08 16:24:23 +01:00
Davide a4ebea1f95
Handle load/save preferences inside ProfileEditor (#982)
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
2024-12-08 16:05:23 +01:00
Davide 14847b2de5
Fix missing test targets 2024-12-06 15:52:25 +01:00
Davide e663f48bc3
Update library
- Make userInfo AnyHashable
- Prepare for profile processing in tunnel
2024-12-06 11:25:54 +01:00
Davide dfae6afcb4
Store complex preferences to Core Data (#981)
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.
2024-12-06 11:24:51 +01:00
Davide 355974292e
Update library with provider entities (#978) 2024-12-04 12:40:47 +01:00
Davide 2d93fa64c6
Embrace simplifications in PassepartoutProviders (#975)
Update library with the new domain reorganization.
2024-12-03 16:18:05 +01:00
Davide 7611f6f7d2
Fix a tunnel crash during DNS resolution 2024-12-02 18:59:18 +01:00
Davide 3540e1cb1a
Redesign confusing paywall (#973)
- Split suggested product and full version
- Hide sections with no products
- Hide full features if no full products
- Fail if no purchasable products
2024-12-02 10:40:25 +01:00
Davide 0a1886fe31
Handle all connection attempts in AppCoordinator (#968)
Let the AppCoordinator take care of the connection requirements via
modals:

- onInteractiveLogin() - now presented on AppError
- onProviderEntityRequired()
- onPurchaseRequired()
- Any other connection error

Subviews must not use tunnel.connect(), rather they route connection
requests via the ConnectionFlow callbacks. In particular, migrate to the
AppCoordinator the connection logic from:

- TunnelToggleButton.perform()
- ProviderEntitySelector.onSelect()

onInteractiveLogin() and onPurchaseRequired() are now handled
internally, while onProviderEntityRequired() is kept public because it's
how subviews may present the entity selector.

Extras:

- Avoid modals overlap with a 500ms delay
- Shrink interactive login size on macOS
2024-12-01 22:34:41 +01:00
Davide 63496725c8
Transparent logo in version screen (#963)
Looks better on macOS and allows gradient on tvOS.
2024-11-28 22:59:37 +01:00
Davide ed413a748e
Update SwiftLint/SwiftGen YAML 2024-11-28 19:54:50 +01:00
Davide 7af703c164
Move app library to the root (#962)
Makes it easier to search among app files and library files.
2024-11-28 17:45:18 +01:00
Davide 2a467e0c7e
Separate AppContext for previews and UI testing (#961)
Clarify the use of contexts:

- **Production** (.shared)
- **Previews** (.mock → .forPreviews)
  - ONLY use it in UILibrary for, well, previews
  - This context has dumb profiles with UUIDs as names
  - Registry is fake
- **UI Tests** (.forUITesting)
  - Add new context for UI testing
  - Selected based on command line arguments
  - This context has mock data tuned for decent screenshots
  - Registry is real

Share the same InAppProcessor in .shared and .forTesting contexts
because the app behavior was inconsistent regarding e.g. in-app
purchases.
2024-11-28 17:31:17 +01:00
Davide 962361cb9f
Automate screenshots via UI tests (#960)
Ready for screenshots generation, except for the tests themselves and
the TV target.

- More customizations while UI testing
  - Act as full version user in IAPManager
  - Override layout with default to .grid if isBigDevice
  - Show module names in profile list/grid
- Improve mock Profile/ProfileManager
  - Meaningful profile names
  - iCloud/TV icons
  - Initial modules
- Improve XCTest extensions
  - Screenshot destination (attachment/temporary)
  - Screenshot target (window/sheet)
  - Print saved temporary URL at the end (may help with CI)
  - Append device name to screenshot filename
- Tests
- Refactor actions with the [Page Object
pattern](https://swiftwithmajid.com/2021/03/24/ui-testing-using-page-object-pattern-in-swift/)
  - Perform iPad screenshots in landscape
  - Split simple flow tests and screenshots
  - Add "Connect to" test

Closes #681
2024-11-28 15:51:03 +01:00
Davide f6c93fc2f7
Use provider description as profile name 2024-11-28 11:14:23 +01:00
Davide 42c0d7e932
Customize user level from bundle 2024-11-28 02:19:44 +01:00
Davide 581673c617
Add target for UI tests (#959)
Create UITesting target with:

- AppCommandLine/AppEnvironment: strongly typed refactoring of PP_*
environment values
- AccessibilityInfo: identifies and locates elements for UI testing

Make the app behave differently when launched with `.uiTesting`, and
expose the flag to SwiftUI via `.environment(\.isUITesting)` to:

- Use the mock AppContext
- Skip onboarding

Add PassepartoutUITests target with two screenshot tests:

- Connected screen
- Profile modal
2024-11-28 01:30:26 +01:00
Davide 8f778faa5d
Inform about use of profile name in Shortcuts (#954)
Now that Siri is superseded by the more general Shortcuts automations,
add an informational footer below the "Name" field of the profile
editor.
2024-11-27 15:30:15 +01:00
Davide b4caa26a47
Improve layout of installed profile (#953)
When none, fill the whitespace with an informational placeholder.
2024-11-27 14:49:23 +01:00
Davide eac1e028b2
Add version view in About/Settings (#952)
Restored from v2. Refactor LogoView for reuse.
2024-11-27 13:24:44 +01:00
Davide 14aae4e02a
Define common PreferenceProtocol 2024-11-27 09:40:32 +01:00
Davide b3c90b6802
Drop animations on reload servers on iOS 2024-11-27 01:22:54 +01:00
Davide 4fcac3c95a
Fix modals not re-appearing in iOS 16
- Paywall
- Error handler

Expose setLater/enableLater.
2024-11-27 01:22:53 +01:00
Davide a92c2c2c64
Fix profile menus
- Omit duplicate/delete from current profile
- Replace .infoButton with .installedProfile if current
- Drop dots from direct actions
- Disable trailing dots on iOS/tvOS
- Disable "Connect to" if ineligible (decouple to own view)
2024-11-27 01:20:42 +01:00
Davide 91f4e510c4
Split app and UI domains (#949)
CommonLibrary had some undesired knowledge of UI. Split AppPreference
and UIPreference. Then move some more stuff from AppUI* to UILibrary.

WARNING: this forgets existing UI preferences (e.g. favorite servers).
2024-11-26 21:21:49 +01:00
Davide d8753f21da
Different styles for profile menu based on context (#947)
Hide "Duplicate" and "Delete" from the info button menu because they are
disruptive actions, misclick is likely.
2024-11-26 20:10:03 +01:00
Davide e0f16cbb3e
Mitigate overlap of sheet/alert during onboarding 2024-11-26 19:19:15 +01:00
Davide b34019e4eb
Add provider profile from toolbar (#946)
Create profile with a provider module and an on-demand module (disabled)
to speed up initial provider selection and configuration. Supports
OpenVPN for now.

Fixes #899
2024-11-26 19:14:56 +01:00
Davide 2dad04f241
Do not present server selector if ineligible (#945)
Verification was only performed for interactive login, not for provider
server selection. Do that before a connection attempt, so that the
paywall always appears first.
2024-11-26 18:44:23 +01:00
Davide 7d8055f044
Do not dismiss abruptly on "Donate" error 2024-11-26 17:28:49 +01:00
Davide b455701daa
Improve appearance of "Purchased"
- Animate load
- Handle load errors
2024-11-26 17:28:19 +01:00
Davide b9f3500f31
Fix regressions in L&F (#944)
- Text appearance on iOS/macOS (broken by #943)
- Visual ambiguity in "Purchased" when no feature is eligible
- "Purchased" must be a form on macOS
2024-11-26 16:50:37 +01:00
Davide 40741ebf2b
Receive tests on ImmediateScheduler 2024-11-26 16:20:16 +01:00
Davide 80d40c3161
Improve TV settings screen (#943)
- Show detail side by side rather than navigate
- Fix scrolling in purchased view
2024-11-26 15:55:04 +01:00
Davide e49e8881b3
Share tests timeout and set to .infinity 2024-11-26 12:33:28 +01:00
Davide 829bde865e
Retain on-demand flag on save profile (#942)
Regressed recently in library. When a profile was "Inactive
(on-demand)", saving it would revert to "Inactive" because the
underlying manager was being disabled.
2024-11-26 11:05:02 +01:00
Davide 55dbd5cb84
Try to fix wait() in ProfileManager tests
In case condition is immediately met.
2024-11-26 10:33:30 +01:00