Commit Graph

60 Commits

Author SHA1 Message Date
Davide De Rosa 18b933d36e
Respect global macOS accent (#490) 2024-02-03 11:52:29 +01:00
Davide De Rosa 7f5b84c72b
Override profile list selection color (#486)
Both List and Toggle use accent color for their tint. Instead:

- Set grayish .tint on List to customize selection color
- Retain global accent in VPNToggle

Fixes #458
2024-01-27 15:59:40 +01:00
Davide De Rosa 64d1131fdd
Update copyright
Closes #473
2024-01-14 14:36:55 +01:00
Davide De Rosa 5c5697762b
Add minimal TV app
Closes #315
2023-12-31 01:21:38 +01:00
Davide De Rosa a4ca8cc996
Support iCloud sync as an option (#350)
Sync will be enabled on upgrade for consistency with current behavior,
and disabled for new installs.

Fixes #227
2023-09-09 20:29:04 +02:00
Davide De Rosa 2d046181b0
Only migrate if current version is higher (#349) 2023-09-08 22:45:04 +02:00
Davide De Rosa bd6340ce77
Split reusable views into extensions (#322)
Like in #321
2023-07-03 17:37:16 +02:00
Davide De Rosa d7ebcb23ba
Split views into extensions (#321)
Nothing but moving code around to reorganize views into the following
sections (MARK):

- Properties/Body
- Subviews
- Actions
2023-07-03 16:54:43 +02:00
Davide De Rosa b89328b5c3
Only show 'Reconnect' on active profile (#311)
It doesn't make sense anywhere else.
2023-05-28 11:23:07 +02:00
Davide De Rosa b4ad8dea0d Do some code clean up
- Use guard in validators

- Rename URL.openURL() to URL.open()

- Sort imports (SwiftLint)

- Drop unused VPNProtocolType.allTypes

- Drop unused imports
2023-05-21 11:48:03 +02:00
Davide De Rosa 7f9ae7c3bc
Always show "Reconnect" button (#278)
Will do nothing if VPN is disabled. Suboptimal, but consistent
with Mac menu.
2023-04-01 22:46:12 +02:00
Davide De Rosa 1e0d522010
Drop #available condition on iOS 15 (#274) 2023-03-25 17:05:53 +01:00
Davide De Rosa f06f097f27
Add SwiftLint phase (#262) 2023-03-17 21:55:47 +01:00
Davide De Rosa 37354d1b87 Update copyright 2023-03-17 16:56:19 +01:00
Davide De Rosa 2e10aab039
Extend authentication methods (#259)
* Add profile authentication method

- Persistent (default, fallback)

- Interactive (may expire through reconnections)

- TOTP (seed-based) - currently disabled

* Disable on-demand if login is interactive

* Present interactive prompt on VPN toggle
2023-03-17 16:49:35 +01:00
Davide De Rosa 44ccd21536
Fetch full profiles from Core Data (#258)
* Fetch full profiles

* Manage full profiles in organizer
2023-03-16 16:49:09 +01:00
Davide De Rosa c0cc10ab94
Restore reconnect action (#232)
* Add "Reconnect" in profile view

* Add "Reconnect" in profile context menu

* Update CHANGELOG

* Restrict "Reconnect" in context menu to iOS 16

SwiftUI does not react properly to state updates.
2022-10-17 17:36:32 +02:00
Davide De Rosa 5627e6c4a9
Address UI race conditions (#229)
* Make some managers concurrency-safe

- IntentsManager: @MainActor, non-shared, continuation

- SSIDReader: @MainActor, continuation

- Reviewer: main queue, non-shared

* Review wrong use of Concurrency framework

There were background thread calls e.g. in VPNToggle, because
ProfileManager was used inside a VPNManager async call.

Annotate @MainActor wherever a Task involves UI.

* Make main managers MainActor

* Apply MainActor to Mac menus

* [ci skip] Update CHANGELOG

* Set MainActor consistently on Mac menu view models
2022-10-13 08:53:50 +02:00
Davide De Rosa 4c4b3ee0c9 Revert to concrete-only managers
Abstraction was overcomplicated. Strategy pattern is enough.
2022-09-03 12:47:40 +02:00
Davide De Rosa ebe8ae3d29 Retain profiles order, no active on top 2022-07-04 00:32:06 +02:00
Davide De Rosa 9a8477225e Refactor library into domain + impl 2022-06-23 23:31:01 +02:00
Davide De Rosa 14b42fbea5 Persist managers state to generic key-value store
Move all persisted state out of AppManager to where it really
belongs. To do that, inject a shared KeyValueStore object into
managers that need to persist part of their state in a strongly
typed manner.

Below are persisted states:

- PersistenceManager
    - persistenceAuthor

- ProfileManager
    - activeProfileId

- UpgradeManager (formerly AppManager)
    - didMigrateToV2 (migrate former value)

- VPNManager
    - tunnelLogFormat
    - masksPrivateData

A similar approach is used for app-specific preferences, by using
a strongly typed enum (AppPreference) together with SwiftUI
@AppStorage property wrapper.

Worth moving logging logic into a specific LogManager.

Finally, drop any former view dependency on AppManager, as states
are now accessed through specific managers.
2022-06-16 13:42:37 +02:00
Davide De Rosa a2d4ed370e Revisit sidebar with per-profile VPN toggles 2022-05-21 19:15:37 +02:00
Davide De Rosa d6866e8e95 Fix iPad multitasking condition 2022-05-20 11:58:25 +02:00
Davide De Rosa e87ad06c5d Drop old observables from profiles list
List was being reloaded e.g. on ProductManager receipt updates,
but profile in-app eligibility is not a thing anymore.
2022-05-16 10:59:12 +02:00
Davide De Rosa 137bacb542 Add contextual profile delete
Without confirmation alert though.
2022-05-15 22:24:36 +02:00
Davide De Rosa eaaa1fe260 Move device checks to Theme
Drop unused code along the way.
2022-05-15 22:24:36 +02:00
Davide De Rosa 9984c56084 Drop unnecessary async from migration code
Providers are not fetched at migration time, they only are after
opening a profile (marked non-ready until then).

Still retain Task for migration to be executed asynchronously.
2022-05-05 11:04:12 +02:00
Davide De Rosa 4cb18965c9 Set duplicate as current inside ProfileManager
When setting duplicate as current, batch save original profile and
duplicate in a single call via profilesToSave. This is to avoid a
double call to willUpdateProfiles() when saving Core Data context.

In order to set current profile to one that has not been persisted
yet (the duplicate), we need to resort to a pendingProfiles map
where to look the duplicate up when setting currentProfileId.

Either way, iOS 14 cannot handle updating a "hot" change in a
presented NavigationLink. Changing currentProfileId binding while
in ProfileView messes up navigation completely (multiple push and
pop events). Avoid.
2022-05-03 18:35:19 +02:00
Davide De Rosa 943bce5515 Bind navigation to ProfileManager directly
- Do the profile loading inside the model

- Allow setting current profile to a transient profile

- Check .placeholder before saving current profile

XXX: avoid loading active profile on iPad portrait.
2022-05-03 18:35:17 +02:00
Davide De Rosa b9248cbb89 Animate profile removal
Fade into WelcomeView.
2022-05-03 15:44:47 +02:00
Davide De Rosa 8230666ab2 Only use wrapping Section to fix iPad multitasking 2022-05-03 15:43:15 +02:00
Davide De Rosa 3c0e511e84 Split again OrganizerView and ProfilesList
On iOS 14, Organizer scrolls abruptly on profile selection. It
looks like this was introduced by merging ProfilesList into
OrganizerView.

Try to revert merge to split observation responsibilities.

Drop unused AppManager in +Scene along the way.
2022-05-03 14:40:41 +02:00
Davide De Rosa edc7cdf045 Merge List into OrganizerView
- Restore wrapping Section as it seems to fix multitasking

- Hide profiles section if empty
2022-05-01 19:19:31 +02:00
Davide De Rosa 9af67e12ce Drop profiles Section wrapper 2022-04-29 19:51:18 +02:00
Davide De Rosa 0047d095fb Adjust navigation style to all devices
- Mac
    - Drop all styles
    - Tweak hide title bar
    - Hide navigation bar

- Restore single section for all profiles
    - Allows using NavigationLink safely
    - Indirectly fixes multitasking
    - Retains selection on profile activation
    - Clean up presentActiveProfile

- Leave active profile in its position
    - Fixes Mac flashing row selection on profile activation

- Unify profile row appearance
    - Use fixed .headline font
    - Add subtitles to inactive profiles
    - Use padding rather than fixed row height

CAVEATS:

- Do not preselect active profile on iPad launch, as doing so
seems to present two ProfileView on top of each other, one from
MainView and one from the NavigationLink.

- Do not touch .listStyle() of master view, as it seems to break
navigation esp. in iPad multitasking.
2022-04-29 19:29:47 +02:00
Davide De Rosa 4d13d8bf6b Do not observe AppManager, just use for migrations 2022-04-29 18:58:07 +02:00
Davide De Rosa 2c2e794b00 Revert async loadCurrentProfile()
Make action sync, but internally async (makeProfileReady). If not
doing so, UI on launch will not be able to show active profile
immediately. WelcomeView would appear for a moment.

Observe isReloadingCurrentProfile.

See 2b1efb8fec
2022-04-28 19:00:36 +02:00
Davide De Rosa 2b1efb8fec Make load*Profile() async
- Handle Task in consumers

- Drop makeReady, always make loaded profile ready

- Rename misleading loadProfile() to profileEx()
2022-04-27 17:13:03 +02:00
Davide De Rosa 02b2e3194e Add duplicate to profile menu
Contextually switch current profile to duplicate.
2022-04-27 16:59:33 +02:00
Davide De Rosa cd854f8ebf Group profile actions into menus
- Organizer
    - Duplicate

- Profile
    - Rename
    - Siri
    - Uninstall (+ confirmation)
    - Delete (+ confirmation)
2022-04-27 09:53:42 +02:00
Davide De Rosa 03fdab4833 Duplicate profile from context menu 2022-04-26 22:39:47 +02:00
Davide De Rosa ac1239daa8 Add headers to active/inactive profile sections
Hide inactive section if empty.
2022-04-25 16:34:13 +02:00
Davide De Rosa 0b1e465143 Share animation type in theme 2022-04-23 12:11:01 +02:00
Davide De Rosa 7eb2b3bd0e Drop button accent on Organizer rows 2022-04-23 11:48:43 +02:00
Davide De Rosa 6aee88e69a Refactor theme styles
- Hide colors behind styles

- Add "Style" suffix
2022-04-23 11:48:43 +02:00
Davide De Rosa dc66f514d9 Restore presentation conditions of active profile
On iPad it's already loaded in MainView().
2022-04-23 10:25:31 +02:00
Davide De Rosa 4037b983cb Move active profile on top to its own section 2022-04-23 10:25:31 +02:00
Davide De Rosa b37ff03e4b Refactor hidden navlinks and send behind in ZStack 2022-04-23 10:25:31 +02:00
Davide De Rosa 2432f0d97a Rewrite ProfileView as a view of currentProfile
Do not load profile in View, instead:

- Load active profile on app launch

- Load selected profile on organizer selection
2022-04-23 10:25:31 +02:00