|
@ -0,0 +1,7 @@
|
||||||
|
INFO_PLIST_ROOT="Passepartout/App"
|
||||||
|
MATCH_PLATFORM="tvos"
|
||||||
|
GYM_SCHEME="Passepartout"
|
||||||
|
DELIVER_PLATFORM="appletvos"
|
||||||
|
DELIVER_METADATA_PATH="Passepartout/App/fastlane/tvos/metadata"
|
||||||
|
DELIVER_SCREENSHOTS_PATH="Passepartout/App/fastlane/tvos/screenshots"
|
||||||
|
CHANGELOG="CHANGELOG.md"
|
|
@ -17,7 +17,7 @@ env:
|
||||||
jobs:
|
jobs:
|
||||||
build_upload:
|
build_upload:
|
||||||
name: Distribute Private Beta
|
name: Distribute Private Beta
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
environment:
|
environment:
|
||||||
name: private_beta
|
name: private_beta
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -50,7 +50,7 @@ jobs:
|
||||||
go-version: "^1.17"
|
go-version: "^1.17"
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
- uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: latest-stable
|
xcode-version: "15.1"
|
||||||
- name: Create keychain
|
- name: Create keychain
|
||||||
uses: ./.github/actions/create-keychain
|
uses: ./.github/actions/create-keychain
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -16,7 +16,7 @@ env:
|
||||||
jobs:
|
jobs:
|
||||||
build_upload:
|
build_upload:
|
||||||
name: Upload to ASC
|
name: Upload to ASC
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -48,7 +48,7 @@ jobs:
|
||||||
go-version: "^1.17"
|
go-version: "^1.17"
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
- uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: latest-stable
|
xcode-version: "15.1"
|
||||||
- name: Store app version
|
- name: Store app version
|
||||||
id: app_version
|
id: app_version
|
||||||
if: ${{ matrix.use_version }}
|
if: ${{ matrix.use_version }}
|
||||||
|
|
|
@ -18,7 +18,7 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
run_tests:
|
run_tests:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@ -26,7 +26,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- uses: maxim-lobanov/setup-xcode@v1
|
- uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: latest-stable
|
xcode-version: "15.1"
|
||||||
- uses: ruby/setup-ruby@v1
|
- uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- App for tvOS. [#315](https://github.com/passepartoutvpn/passepartout-apple/issues/315)
|
||||||
- WireGuard: Show data count. [#312](https://github.com/passepartoutvpn/passepartout-apple/issues/312)
|
- WireGuard: Show data count. [#312](https://github.com/passepartoutvpn/passepartout-apple/issues/312)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 55;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
0E0838FA2877325A00A34EC0 /* LightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838F92877325A00A34EC0 /* LightProviderManager.swift */; };
|
0E0838FA2877325A00A34EC0 /* LightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838F92877325A00A34EC0 /* LightProviderManager.swift */; };
|
||||||
0E0838FB2877325A00A34EC0 /* LightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838F92877325A00A34EC0 /* LightProviderManager.swift */; };
|
0E0838FB2877325A00A34EC0 /* LightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838F92877325A00A34EC0 /* LightProviderManager.swift */; };
|
||||||
0E0838FD2877334300A34EC0 /* DefaultLightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838FC2877334300A34EC0 /* DefaultLightProviderManager.swift */; };
|
0E0838FD2877334300A34EC0 /* DefaultLightProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0838FC2877334300A34EC0 /* DefaultLightProviderManager.swift */; };
|
||||||
0E09E35D2834172800BE1BAE /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 0E09E35C2834172800BE1BAE /* Credits.rtf */; };
|
0E09E35D2834172800BE1BAE /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 0E09E35C2834172800BE1BAE /* Credits.rtf */; platformFilter = maccatalyst; };
|
||||||
0E0BD27327B2EA2C00583AC5 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27227B2EA2C00583AC5 /* MainView.swift */; };
|
0E0BD27327B2EA2C00583AC5 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27227B2EA2C00583AC5 /* MainView.swift */; };
|
||||||
0E0BD27627B2EB2200583AC5 /* DonateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27527B2EB2200583AC5 /* DonateView.swift */; };
|
0E0BD27627B2EB2200583AC5 /* DonateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27527B2EB2200583AC5 /* DonateView.swift */; };
|
||||||
0E0BD27927B2EBE500583AC5 /* ShortcutsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27827B2EBE500583AC5 /* ShortcutsView.swift */; };
|
0E0BD27927B2EBE500583AC5 /* ShortcutsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0BD27827B2EBE500583AC5 /* ShortcutsView.swift */; };
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
0E0F4C6629C84CF60022E884 /* LogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F4C6529C84CF60022E884 /* LogoView.swift */; };
|
0E0F4C6629C84CF60022E884 /* LogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F4C6529C84CF60022E884 /* LogoView.swift */; };
|
||||||
0E1AD5CE2A268645002AE6E6 /* Errors+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1AD5CD2A268645002AE6E6 /* Errors+L10n.swift */; };
|
0E1AD5CE2A268645002AE6E6 /* Errors+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1AD5CD2A268645002AE6E6 /* Errors+L10n.swift */; };
|
||||||
0E1B5F5C29C506AD00FE7D18 /* DiagnosticsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B5F5B29C506AC00FE7D18 /* DiagnosticsSection.swift */; };
|
0E1B5F5C29C506AD00FE7D18 /* DiagnosticsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B5F5B29C506AC00FE7D18 /* DiagnosticsSection.swift */; };
|
||||||
|
0E1DC1BF2B3618EE008B755E /* ProfileView+TV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1DC1BE2B3618EE008B755E /* ProfileView+TV.swift */; };
|
||||||
0E1F5628287F0ECB00F8ADD7 /* ProviderProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1F5627287F0ECB00F8ADD7 /* ProviderProfileItem.swift */; };
|
0E1F5628287F0ECB00F8ADD7 /* ProviderProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1F5627287F0ECB00F8ADD7 /* ProviderProfileItem.swift */; };
|
||||||
0E1F562B287F0EF100F8ADD7 /* ProviderProfileItem+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1F5629287F0EEE00F8ADD7 /* ProviderProfileItem+ViewModel.swift */; };
|
0E1F562B287F0EF100F8ADD7 /* ProviderProfileItem+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1F5629287F0EEE00F8ADD7 /* ProviderProfileItem+ViewModel.swift */; };
|
||||||
0E293857285A73BC002A6E0E /* AppContext+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E293856285A73BC002A6E0E /* AppContext+Shared.swift */; };
|
0E293857285A73BC002A6E0E /* AppContext+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E293856285A73BC002A6E0E /* AppContext+Shared.swift */; };
|
||||||
|
@ -47,6 +48,9 @@
|
||||||
0E2E0B762B335AAB00E3204A /* UpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B722B335AAB00E3204A /* UpgradeManagerStrategy.swift */; };
|
0E2E0B762B335AAB00E3204A /* UpgradeManagerStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B722B335AAB00E3204A /* UpgradeManagerStrategy.swift */; };
|
||||||
0E2E0B772B335AAB00E3204A /* UpgradeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B732B335AAB00E3204A /* UpgradeManager.swift */; };
|
0E2E0B772B335AAB00E3204A /* UpgradeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B732B335AAB00E3204A /* UpgradeManager.swift */; };
|
||||||
0E2E0B782B335AAB00E3204A /* PersistenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B742B335AAB00E3204A /* PersistenceManager.swift */; };
|
0E2E0B782B335AAB00E3204A /* PersistenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2E0B742B335AAB00E3204A /* PersistenceManager.swift */; };
|
||||||
|
0E330F532B30469700930C7C /* MockProfileRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E330F522B30469700930C7C /* MockProfileRepository.swift */; };
|
||||||
|
0E330F552B30946600930C7C /* ActiveProfileView+TV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E330F542B30946600930C7C /* ActiveProfileView+TV.swift */; };
|
||||||
|
0E330F572B30952300930C7C /* ProfilesList+TV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E330F562B30952300930C7C /* ProfilesList+TV.swift */; };
|
||||||
0E34A2B627CAA8CC00C73B67 /* Core+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2B527CAA8CC00C73B67 /* Core+L10n.swift */; };
|
0E34A2B627CAA8CC00C73B67 /* Core+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2B527CAA8CC00C73B67 /* Core+L10n.swift */; };
|
||||||
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2AF27CAA84500C73B67 /* OpenVPN+L10n.swift */; };
|
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2AF27CAA84500C73B67 /* OpenVPN+L10n.swift */; };
|
||||||
0E34A2CF27CADA6300C73B67 /* GenericVersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2CE27CADA6300C73B67 /* GenericVersionView.swift */; };
|
0E34A2CF27CADA6300C73B67 /* GenericVersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34A2CE27CADA6300C73B67 /* GenericVersionView.swift */; };
|
||||||
|
@ -108,6 +112,7 @@
|
||||||
0E7A8C0C2A1D4A6100780F4B /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0E7A8C0B2A1D4A6100780F4B /* PassepartoutLibrary */; };
|
0E7A8C0C2A1D4A6100780F4B /* PassepartoutLibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 0E7A8C0B2A1D4A6100780F4B /* PassepartoutLibrary */; };
|
||||||
0E7A8C0F2A1D54DE00780F4B /* Picker+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */; };
|
0E7A8C0F2A1D54DE00780F4B /* Picker+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */; };
|
||||||
0E7A8C102A1D54DE00780F4B /* Picker+Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */; };
|
0E7A8C102A1D54DE00780F4B /* Picker+Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */; };
|
||||||
|
0E859B832B2EE08700F80D92 /* OrganizerView+TV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E859B822B2EE08700F80D92 /* OrganizerView+TV.swift */; };
|
||||||
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */; };
|
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */; };
|
||||||
0E92D7C627F103300033CB7B /* ProfileView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */; };
|
0E92D7C627F103300033CB7B /* ProfileView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */; };
|
||||||
0E92D7C927F1042A0033CB7B /* ProfileView+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */; };
|
0E92D7C927F1042A0033CB7B /* ProfileView+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */; };
|
||||||
|
@ -184,10 +189,12 @@
|
||||||
0ED89C1727DE0E05008B36D6 /* IntentEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1627DE0E05008B36D6 /* IntentEditView.swift */; };
|
0ED89C1727DE0E05008B36D6 /* IntentEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1627DE0E05008B36D6 /* IntentEditView.swift */; };
|
||||||
0ED89C1C27DE3ABC008B36D6 /* ShortcutsView+Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */; };
|
0ED89C1C27DE3ABC008B36D6 /* ShortcutsView+Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */; };
|
||||||
0ED89C1E27DE3F8D008B36D6 /* IntentAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */; };
|
0ED89C1E27DE3F8D008B36D6 /* IntentAddView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */; };
|
||||||
0EDDEC7D28D0DC140017802E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EDDEC7C28D0DC130017802E /* LaunchScreen.storyboard */; };
|
|
||||||
0EDE02C227F61C79000FBE3C /* EditableTextList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE02C127F61C79000FBE3C /* EditableTextList.swift */; };
|
0EDE02C227F61C79000FBE3C /* EditableTextList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE02C127F61C79000FBE3C /* EditableTextList.swift */; };
|
||||||
0EE11CD2280D8317003BE431 /* SettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE11CD1280D8317003BE431 /* SettingsButton.swift */; };
|
0EE11CD2280D8317003BE431 /* SettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE11CD1280D8317003BE431 /* SettingsButton.swift */; };
|
||||||
|
0EE562782B2EE3EC000C52F6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EE562772B2EE3EC000C52F6 /* LaunchScreen.storyboard */; platformFilters = (ios, maccatalyst, ); };
|
||||||
|
0EE79B2F2B2ED99500C1220C /* MainView+TV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE79B2E2B2ED99500C1220C /* MainView+TV.swift */; };
|
||||||
0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */; };
|
0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */; };
|
||||||
|
0EED5B9D2B3700AB009D1E97 /* TunnelError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF656402B36C00E00CEFC96 /* TunnelError.swift */; };
|
||||||
0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF527DD0211007EB181 /* PaywallView.swift */; };
|
0EF0FAF627DD0211007EB181 /* PaywallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF527DD0211007EB181 /* PaywallView.swift */; };
|
||||||
0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591122733DD4E0096F796 /* IntentDispatcher.swift */; };
|
0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA591122733DD4E0096F796 /* IntentDispatcher.swift */; };
|
||||||
0EF0FAF927DD212C007EB181 /* IntentActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF827DD212C007EB181 /* IntentActivity.swift */; };
|
0EF0FAF927DD212C007EB181 /* IntentActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF0FAF827DD212C007EB181 /* IntentActivity.swift */; };
|
||||||
|
@ -195,6 +202,10 @@
|
||||||
0EF2212D27E66EB5001D0BD7 /* AddProviderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2212C27E66EB5001D0BD7 /* AddProviderView.swift */; };
|
0EF2212D27E66EB5001D0BD7 /* AddProviderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2212C27E66EB5001D0BD7 /* AddProviderView.swift */; };
|
||||||
0EF2212F27E66F60001D0BD7 /* AddProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */; };
|
0EF2212F27E66F60001D0BD7 /* AddProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */; };
|
||||||
0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */; };
|
0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */; };
|
||||||
|
0EF6563E2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6563D2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift */; };
|
||||||
|
0EF6563F2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6563D2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift */; };
|
||||||
|
0EF656422B36C01200CEFC96 /* TunnelError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF656402B36C00E00CEFC96 /* TunnelError.swift */; };
|
||||||
|
0EF656432B36C01200CEFC96 /* TunnelError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF656402B36C00E00CEFC96 /* TunnelError.swift */; };
|
||||||
0EF8C5A828213C510053CE89 /* OrganizerView+Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */; };
|
0EF8C5A828213C510053CE89 /* OrganizerView+Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */; };
|
||||||
A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38D607628AFCFD20005C271 /* SettingsView.swift */; };
|
A38D607728AFCFD20005C271 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A38D607628AFCFD20005C271 /* SettingsView.swift */; };
|
||||||
A3A7CC462878DC8300172D7D /* ProviderServerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A7CC452878DC8300172D7D /* ProviderServerItem.swift */; };
|
A3A7CC462878DC8300172D7D /* ProviderServerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3A7CC452878DC8300172D7D /* ProviderServerItem.swift */; };
|
||||||
|
@ -248,6 +259,13 @@
|
||||||
remoteGlobalIDString = 0ECF71F327B6D9CD00CDB528;
|
remoteGlobalIDString = 0ECF71F327B6D9CD00CDB528;
|
||||||
remoteInfo = WireGuardGo;
|
remoteInfo = WireGuardGo;
|
||||||
};
|
};
|
||||||
|
0EE79B342B2EDB9C00C1220C /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 0E57F63020C83FC5008323CF /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 0EE79B302B2EDB5D00C1220C;
|
||||||
|
remoteInfo = WireGuardGoTV;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
@ -311,6 +329,7 @@
|
||||||
0E1AD5CD2A268645002AE6E6 /* Errors+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Errors+L10n.swift"; sourceTree = "<group>"; };
|
0E1AD5CD2A268645002AE6E6 /* Errors+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Errors+L10n.swift"; sourceTree = "<group>"; };
|
||||||
0E1B5F5B29C506AC00FE7D18 /* DiagnosticsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiagnosticsSection.swift; sourceTree = "<group>"; };
|
0E1B5F5B29C506AC00FE7D18 /* DiagnosticsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiagnosticsSection.swift; sourceTree = "<group>"; };
|
||||||
0E1C0A52238FFF97009FC087 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
0E1C0A52238FFF97009FC087 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
0E1DC1BE2B3618EE008B755E /* ProfileView+TV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+TV.swift"; sourceTree = "<group>"; };
|
||||||
0E1F5627287F0ECB00F8ADD7 /* ProviderProfileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProfileItem.swift; sourceTree = "<group>"; };
|
0E1F5627287F0ECB00F8ADD7 /* ProviderProfileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProfileItem.swift; sourceTree = "<group>"; };
|
||||||
0E1F5629287F0EEE00F8ADD7 /* ProviderProfileItem+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProviderProfileItem+ViewModel.swift"; sourceTree = "<group>"; };
|
0E1F5629287F0EEE00F8ADD7 /* ProviderProfileItem+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProviderProfileItem+ViewModel.swift"; sourceTree = "<group>"; };
|
||||||
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
0E23B4A12298559800304C30 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||||
|
@ -329,6 +348,9 @@
|
||||||
0E2E0B722B335AAB00E3204A /* UpgradeManagerStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpgradeManagerStrategy.swift; sourceTree = "<group>"; };
|
0E2E0B722B335AAB00E3204A /* UpgradeManagerStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpgradeManagerStrategy.swift; sourceTree = "<group>"; };
|
||||||
0E2E0B732B335AAB00E3204A /* UpgradeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpgradeManager.swift; sourceTree = "<group>"; };
|
0E2E0B732B335AAB00E3204A /* UpgradeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpgradeManager.swift; sourceTree = "<group>"; };
|
||||||
0E2E0B742B335AAB00E3204A /* PersistenceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceManager.swift; sourceTree = "<group>"; };
|
0E2E0B742B335AAB00E3204A /* PersistenceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceManager.swift; sourceTree = "<group>"; };
|
||||||
|
0E330F522B30469700930C7C /* MockProfileRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProfileRepository.swift; sourceTree = "<group>"; };
|
||||||
|
0E330F542B30946600930C7C /* ActiveProfileView+TV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActiveProfileView+TV.swift"; sourceTree = "<group>"; };
|
||||||
|
0E330F562B30952300930C7C /* ProfilesList+TV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfilesList+TV.swift"; sourceTree = "<group>"; };
|
||||||
0E34A2AF27CAA84500C73B67 /* OpenVPN+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenVPN+L10n.swift"; sourceTree = "<group>"; };
|
0E34A2AF27CAA84500C73B67 /* OpenVPN+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenVPN+L10n.swift"; sourceTree = "<group>"; };
|
||||||
0E34A2B527CAA8CC00C73B67 /* Core+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Core+L10n.swift"; sourceTree = "<group>"; };
|
0E34A2B527CAA8CC00C73B67 /* Core+L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Core+L10n.swift"; sourceTree = "<group>"; };
|
||||||
0E34A2CE27CADA6300C73B67 /* GenericVersionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericVersionView.swift; sourceTree = "<group>"; };
|
0E34A2CE27CADA6300C73B67 /* GenericVersionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericVersionView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -391,6 +413,7 @@
|
||||||
0E7577DE2817E22C00081CBE /* VPNToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNToggle.swift; sourceTree = "<group>"; };
|
0E7577DE2817E22C00081CBE /* VPNToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNToggle.swift; sourceTree = "<group>"; };
|
||||||
0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+OpenVPN.swift"; sourceTree = "<group>"; };
|
0E7A8C072A1D40BA00780F4B /* Picker+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+OpenVPN.swift"; sourceTree = "<group>"; };
|
||||||
0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+Network.swift"; sourceTree = "<group>"; };
|
0E7A8C082A1D40BA00780F4B /* Picker+Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Picker+Network.swift"; sourceTree = "<group>"; };
|
||||||
|
0E859B822B2EE08700F80D92 /* OrganizerView+TV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+TV.swift"; sourceTree = "<group>"; };
|
||||||
0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostViewModel.swift; sourceTree = "<group>"; };
|
0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostViewModel.swift; sourceTree = "<group>"; };
|
||||||
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Configuration.swift"; sourceTree = "<group>"; };
|
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Configuration.swift"; sourceTree = "<group>"; };
|
||||||
0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Extra.swift"; sourceTree = "<group>"; };
|
0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Extra.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -493,13 +516,14 @@
|
||||||
0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShortcutsView+Add.swift"; sourceTree = "<group>"; };
|
0ED89C1B27DE3ABC008B36D6 /* ShortcutsView+Add.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShortcutsView+Add.swift"; sourceTree = "<group>"; };
|
||||||
0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentAddView.swift; sourceTree = "<group>"; };
|
0ED89C1D27DE3F8D008B36D6 /* IntentAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentAddView.swift; sourceTree = "<group>"; };
|
||||||
0EDCEF692B337BEB0023A7FF /* PassepartoutLibrary.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PassepartoutLibrary.xctestplan; sourceTree = "<group>"; };
|
0EDCEF692B337BEB0023A7FF /* PassepartoutLibrary.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PassepartoutLibrary.xctestplan; sourceTree = "<group>"; };
|
||||||
0EDDEC7C28D0DC130017802E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
0EDE02C127F61C79000FBE3C /* EditableTextList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableTextList.swift; sourceTree = "<group>"; };
|
0EDE02C127F61C79000FBE3C /* EditableTextList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableTextList.swift; sourceTree = "<group>"; };
|
||||||
0EDE8DBF20C86910004C739C /* PassepartoutOpenVPNTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassepartoutOpenVPNTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
0EDE8DBF20C86910004C739C /* PassepartoutOpenVPNTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PassepartoutOpenVPNTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
0EDE8DC320C86910004C739C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
0EDE8DC320C86910004C739C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
0EDE8DD220C86978004C739C /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
|
0EDE8DD220C86978004C739C /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
|
||||||
0EDE8DE220C86A13004C739C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
0EDE8DE220C86A13004C739C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||||
0EE11CD1280D8317003BE431 /* SettingsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButton.swift; sourceTree = "<group>"; };
|
0EE11CD1280D8317003BE431 /* SettingsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsButton.swift; sourceTree = "<group>"; };
|
||||||
|
0EE562772B2EE3EC000C52F6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
0EE79B2E2B2ED99500C1220C /* MainView+TV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainView+TV.swift"; sourceTree = "<group>"; };
|
||||||
0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPNProtocolType+FileExtensions.swift"; sourceTree = "<group>"; };
|
0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VPNProtocolType+FileExtensions.swift"; sourceTree = "<group>"; };
|
||||||
0EF0FAF527DD0211007EB181 /* PaywallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallView.swift; sourceTree = "<group>"; };
|
0EF0FAF527DD0211007EB181 /* PaywallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallView.swift; sourceTree = "<group>"; };
|
||||||
0EF0FAF827DD212C007EB181 /* IntentActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentActivity.swift; sourceTree = "<group>"; };
|
0EF0FAF827DD212C007EB181 /* IntentActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentActivity.swift; sourceTree = "<group>"; };
|
||||||
|
@ -507,6 +531,8 @@
|
||||||
0EF2212C27E66EB5001D0BD7 /* AddProviderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderView.swift; sourceTree = "<group>"; };
|
0EF2212C27E66EB5001D0BD7 /* AddProviderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderView.swift; sourceTree = "<group>"; };
|
||||||
0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProfileView.swift; sourceTree = "<group>"; };
|
0EF2212E27E66F60001D0BD7 /* AddProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProfileView.swift; sourceTree = "<group>"; };
|
||||||
0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderViewModel.swift; sourceTree = "<group>"; };
|
0EF2213027E674BD001D0BD7 /* AddProviderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProviderViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
0EF6563D2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NEPacketTunnelProvider+Expiration.swift"; sourceTree = "<group>"; };
|
||||||
|
0EF656402B36C00E00CEFC96 /* TunnelError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelError.swift; sourceTree = "<group>"; };
|
||||||
0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Profiles.swift"; sourceTree = "<group>"; };
|
0EF8C5A728213C510053CE89 /* OrganizerView+Profiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Profiles.swift"; sourceTree = "<group>"; };
|
||||||
A373484D29DC4F4500D1613C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
A373484D29DC4F4500D1613C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
A373484E29DC504000D1613C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
A373484E29DC504000D1613C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
@ -572,6 +598,7 @@
|
||||||
0E021D9B284E68580077EF5D /* AppContext.swift */,
|
0E021D9B284E68580077EF5D /* AppContext.swift */,
|
||||||
0E293856285A73BC002A6E0E /* AppContext+Shared.swift */,
|
0E293856285A73BC002A6E0E /* AppContext+Shared.swift */,
|
||||||
0E021D9A284E68580077EF5D /* CoreContext.swift */,
|
0E021D9A284E68580077EF5D /* CoreContext.swift */,
|
||||||
|
0E330F522B30469700930C7C /* MockProfileRepository.swift */,
|
||||||
);
|
);
|
||||||
path = Context;
|
path = Context;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -630,6 +657,7 @@
|
||||||
0E35C0AE280EF8A80071FA35 /* Views */ = {
|
0E35C0AE280EF8A80071FA35 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0EE79B2D2B2ED96D00C1220C /* TV */,
|
||||||
0E44689B27B11B5300A14CE4 /* AboutView.swift */,
|
0E44689B27B11B5300A14CE4 /* AboutView.swift */,
|
||||||
0ECF71ED27B6A99300CDB528 /* AccountView.swift */,
|
0ECF71ED27B6A99300CDB528 /* AccountView.swift */,
|
||||||
0E039278281890B100827C10 /* AddHostView.swift */,
|
0E039278281890B100827C10 /* AddHostView.swift */,
|
||||||
|
@ -673,6 +701,7 @@
|
||||||
0E3CD482280DAE92007075C0 /* ProfileView+MainMenu.swift */,
|
0E3CD482280DAE92007075C0 /* ProfileView+MainMenu.swift */,
|
||||||
0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */,
|
0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */,
|
||||||
0EBC074B27EB673C00208AD9 /* ProfileView+Rename.swift */,
|
0EBC074B27EB673C00208AD9 /* ProfileView+Rename.swift */,
|
||||||
|
0E1DC1BE2B3618EE008B755E /* ProfileView+TV.swift */,
|
||||||
0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */,
|
0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */,
|
||||||
0E71ACF027C1073800F85C4B /* ProviderLocationView.swift */,
|
0E71ACF027C1073800F85C4B /* ProviderLocationView.swift */,
|
||||||
0E71ACEE27C106B400F85C4B /* ProviderPresetView.swift */,
|
0E71ACEE27C106B400F85C4B /* ProviderPresetView.swift */,
|
||||||
|
@ -889,7 +918,7 @@
|
||||||
0E57F64720C83FC7008323CF /* Info.plist */,
|
0E57F64720C83FC7008323CF /* Info.plist */,
|
||||||
0E0C072B236087A100155AAC /* InfoPlist.strings */,
|
0E0C072B236087A100155AAC /* InfoPlist.strings */,
|
||||||
0E9E5AE227B44CF1008C95DA /* Localizable.strings */,
|
0E9E5AE227B44CF1008C95DA /* Localizable.strings */,
|
||||||
0EDDEC7C28D0DC130017802E /* LaunchScreen.storyboard */,
|
0EE562772B2EE3EC000C52F6 /* LaunchScreen.storyboard */,
|
||||||
0E3FC6852867A3F9009B851C /* AppDelegate.swift */,
|
0E3FC6852867A3F9009B851C /* AppDelegate.swift */,
|
||||||
0E2A8D4727ADF87F00207D04 /* PassepartoutApp.swift */,
|
0E2A8D4727ADF87F00207D04 /* PassepartoutApp.swift */,
|
||||||
0E0F4C5929C761850022E884 /* SceneDelegate.swift */,
|
0E0F4C5929C761850022E884 /* SceneDelegate.swift */,
|
||||||
|
@ -975,6 +1004,8 @@
|
||||||
0ED2B33D27D3C53400FD8EA9 /* WireGuard */,
|
0ED2B33D27D3C53400FD8EA9 /* WireGuard */,
|
||||||
0ED31C3B20CF39510027975F /* Tunnel.entitlements */,
|
0ED31C3B20CF39510027975F /* Tunnel.entitlements */,
|
||||||
0EDE8DC320C86910004C739C /* Info.plist */,
|
0EDE8DC320C86910004C739C /* Info.plist */,
|
||||||
|
0EF6563D2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift */,
|
||||||
|
0EF656402B36C00E00CEFC96 /* TunnelError.swift */,
|
||||||
);
|
);
|
||||||
path = Tunnel;
|
path = Tunnel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -987,6 +1018,17 @@
|
||||||
name = Packages;
|
name = Packages;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0EE79B2D2B2ED96D00C1220C /* TV */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0E330F542B30946600930C7C /* ActiveProfileView+TV.swift */,
|
||||||
|
0EE79B2E2B2ED99500C1220C /* MainView+TV.swift */,
|
||||||
|
0E859B822B2EE08700F80D92 /* OrganizerView+TV.swift */,
|
||||||
|
0E330F562B30952300930C7C /* ProfilesList+TV.swift */,
|
||||||
|
);
|
||||||
|
path = TV;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
374B9F085E1148C37CF9117A /* Frameworks */ = {
|
374B9F085E1148C37CF9117A /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1014,6 +1056,20 @@
|
||||||
passBuildSettingsInEnvironment = 1;
|
passBuildSettingsInEnvironment = 1;
|
||||||
productName = PassepartoutWireGuard;
|
productName = PassepartoutWireGuard;
|
||||||
};
|
};
|
||||||
|
0EE79B302B2EDB5D00C1220C /* WireGuardGoTV */ = {
|
||||||
|
isa = PBXLegacyTarget;
|
||||||
|
buildArgumentsString = "$(ACTION)";
|
||||||
|
buildConfigurationList = 0EE79B312B2EDB5D00C1220C /* Build configuration list for PBXLegacyTarget "WireGuardGoTV" */;
|
||||||
|
buildPhases = (
|
||||||
|
);
|
||||||
|
buildToolPath = "$(PROJECT_DIR)/Passepartout/App/Scripts/build_wireguard_go_bridge.sh";
|
||||||
|
buildWorkingDirectory = "";
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = WireGuardGoTV;
|
||||||
|
passBuildSettingsInEnvironment = 1;
|
||||||
|
productName = PassepartoutWireGuard;
|
||||||
|
};
|
||||||
/* End PBXLegacyTarget section */
|
/* End PBXLegacyTarget section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
@ -1052,9 +1108,10 @@
|
||||||
dependencies = (
|
dependencies = (
|
||||||
0ECB78E7285F5CC400B0E460 /* PBXTargetDependency */,
|
0ECB78E7285F5CC400B0E460 /* PBXTargetDependency */,
|
||||||
0E41BDAB286713F6006346B4 /* PBXTargetDependency */,
|
0E41BDAB286713F6006346B4 /* PBXTargetDependency */,
|
||||||
0ECF71FC27B6DA6700CDB528 /* PBXTargetDependency */,
|
|
||||||
0EB2B14A2733FB6F007705AB /* PBXTargetDependency */,
|
0EB2B14A2733FB6F007705AB /* PBXTargetDependency */,
|
||||||
0ED2B36227D3C99100FD8EA9 /* PBXTargetDependency */,
|
0ED2B36227D3C99100FD8EA9 /* PBXTargetDependency */,
|
||||||
|
0ECF71FC27B6DA6700CDB528 /* PBXTargetDependency */,
|
||||||
|
0EE79B352B2EDB9C00C1220C /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Passepartout;
|
name = Passepartout;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
@ -1210,8 +1267,9 @@
|
||||||
0ECB78D9285F52F700B0E460 /* PassepartoutMac */,
|
0ECB78D9285F52F700B0E460 /* PassepartoutMac */,
|
||||||
0E41BD96286711C3006346B4 /* PassepartoutLauncher */,
|
0E41BD96286711C3006346B4 /* PassepartoutLauncher */,
|
||||||
0EDE8DBE20C86910004C739C /* OpenVPNTunnel */,
|
0EDE8DBE20C86910004C739C /* OpenVPNTunnel */,
|
||||||
0ECF71F327B6D9CD00CDB528 /* WireGuardGo */,
|
|
||||||
0ED2B33E27D3C77800FD8EA9 /* WireGuardTunnel */,
|
0ED2B33E27D3C77800FD8EA9 /* WireGuardTunnel */,
|
||||||
|
0ECF71F327B6D9CD00CDB528 /* WireGuardGo */,
|
||||||
|
0EE79B302B2EDB5D00C1220C /* WireGuardGoTV */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
@ -1229,8 +1287,8 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
0E6059CB27FCC5DE003F4063 /* Flags.xcassets in Resources */,
|
0E6059CB27FCC5DE003F4063 /* Flags.xcassets in Resources */,
|
||||||
|
0EE562782B2EE3EC000C52F6 /* LaunchScreen.storyboard in Resources */,
|
||||||
0E0C0729236087A100155AAC /* InfoPlist.strings in Resources */,
|
0E0C0729236087A100155AAC /* InfoPlist.strings in Resources */,
|
||||||
0EDDEC7D28D0DC140017802E /* LaunchScreen.storyboard in Resources */,
|
|
||||||
0E6059CC27FCC5DE003F4063 /* Providers.xcassets in Resources */,
|
0E6059CC27FCC5DE003F4063 /* Providers.xcassets in Resources */,
|
||||||
0E6059CD27FCC5DE003F4063 /* Assets.xcassets in Resources */,
|
0E6059CD27FCC5DE003F4063 /* Assets.xcassets in Resources */,
|
||||||
0E9E5AEF27B44CF1008C95DA /* Localizable.strings in Resources */,
|
0E9E5AEF27B44CF1008C95DA /* Localizable.strings in Resources */,
|
||||||
|
@ -1376,6 +1434,7 @@
|
||||||
0E2DE71C27DCCFE80067B9E1 /* TunnelKit+Extensions.swift in Sources */,
|
0E2DE71C27DCCFE80067B9E1 /* TunnelKit+Extensions.swift in Sources */,
|
||||||
0ED1D6DE27DBA42100983466 /* DiagnosticsView+WireGuard.swift in Sources */,
|
0ED1D6DE27DBA42100983466 /* DiagnosticsView+WireGuard.swift in Sources */,
|
||||||
0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */,
|
0EF2213127E674BD001D0BD7 /* AddProviderViewModel.swift in Sources */,
|
||||||
|
0EED5B9D2B3700AB009D1E97 /* TunnelError.swift in Sources */,
|
||||||
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */,
|
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */,
|
||||||
0E3A593C2A50975700B3FE40 /* ErrorHandler.swift in Sources */,
|
0E3A593C2A50975700B3FE40 /* ErrorHandler.swift in Sources */,
|
||||||
0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */,
|
0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */,
|
||||||
|
@ -1411,6 +1470,7 @@
|
||||||
0ED89C1E27DE3F8D008B36D6 /* IntentAddView.swift in Sources */,
|
0ED89C1E27DE3F8D008B36D6 /* IntentAddView.swift in Sources */,
|
||||||
0E5468002867AC9A00F74D1C /* MacUtils.swift in Sources */,
|
0E5468002867AC9A00F74D1C /* MacUtils.swift in Sources */,
|
||||||
0E0F4C6429C84B5A0022E884 /* LockableView.swift in Sources */,
|
0E0F4C6429C84B5A0022E884 /* LockableView.swift in Sources */,
|
||||||
|
0E330F552B30946600930C7C /* ActiveProfileView+TV.swift in Sources */,
|
||||||
0E96D3052872010A005EFBCF /* DefaultLightVPNManager.swift in Sources */,
|
0E96D3052872010A005EFBCF /* DefaultLightVPNManager.swift in Sources */,
|
||||||
0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */,
|
0EBE880F281B18DE0090D9E6 /* OrganizerView+ProfileRow.swift in Sources */,
|
||||||
0ED30DCF27EA1EF80057D8A3 /* PaywallView+Restricted.swift in Sources */,
|
0ED30DCF27EA1EF80057D8A3 /* PaywallView+Restricted.swift in Sources */,
|
||||||
|
@ -1421,6 +1481,7 @@
|
||||||
0E96D30228720067005EFBCF /* LightVPNManager.swift in Sources */,
|
0E96D30228720067005EFBCF /* LightVPNManager.swift in Sources */,
|
||||||
0ED89C1727DE0E05008B36D6 /* IntentEditView.swift in Sources */,
|
0ED89C1727DE0E05008B36D6 /* IntentEditView.swift in Sources */,
|
||||||
0E70589B28377DC40075D1D2 /* VPNStatusText.swift in Sources */,
|
0E70589B28377DC40075D1D2 /* VPNStatusText.swift in Sources */,
|
||||||
|
0EE79B2F2B2ED99500C1220C /* MainView+TV.swift in Sources */,
|
||||||
0E71ACE927C1055300F85C4B /* NetworkSettingsView.swift in Sources */,
|
0E71ACE927C1055300F85C4B /* NetworkSettingsView.swift in Sources */,
|
||||||
0EB34BCA27C6A70200B126DA /* OnDemandView.swift in Sources */,
|
0EB34BCA27C6A70200B126DA /* OnDemandView.swift in Sources */,
|
||||||
0E0838FA2877325A00A34EC0 /* LightProviderManager.swift in Sources */,
|
0E0838FA2877325A00A34EC0 /* LightProviderManager.swift in Sources */,
|
||||||
|
@ -1432,6 +1493,7 @@
|
||||||
0EB17EBA27D2560300D473B5 /* PassepartoutProviders+Extensions.swift in Sources */,
|
0EB17EBA27D2560300D473B5 /* PassepartoutProviders+Extensions.swift in Sources */,
|
||||||
0E3B7FDA27E51A0200C66F13 /* ProfileView+Provider.swift in Sources */,
|
0E3B7FDA27E51A0200C66F13 /* ProfileView+Provider.swift in Sources */,
|
||||||
0E2E0B6F2B335A8E00E3204A /* AppPreference.swift in Sources */,
|
0E2E0B6F2B335A8E00E3204A /* AppPreference.swift in Sources */,
|
||||||
|
0E859B832B2EE08700F80D92 /* OrganizerView+TV.swift in Sources */,
|
||||||
0E5468062867AEC500F74D1C /* MacMenu.swift in Sources */,
|
0E5468062867AEC500F74D1C /* MacMenu.swift in Sources */,
|
||||||
0E71ACE327C0F2E400F85C4B /* Providers+L10n.swift in Sources */,
|
0E71ACE327C0F2E400F85C4B /* Providers+L10n.swift in Sources */,
|
||||||
0E2E0B752B335AAB00E3204A /* IntentsManager.swift in Sources */,
|
0E2E0B752B335AAB00E3204A /* IntentsManager.swift in Sources */,
|
||||||
|
@ -1457,6 +1519,7 @@
|
||||||
0E2A8D4927ADF87F00207D04 /* PassepartoutApp.swift in Sources */,
|
0E2A8D4927ADF87F00207D04 /* PassepartoutApp.swift in Sources */,
|
||||||
0EBC075527EBC83800208AD9 /* MailComposerView.swift in Sources */,
|
0EBC075527EBC83800208AD9 /* MailComposerView.swift in Sources */,
|
||||||
0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */,
|
0EF0FAF727DD159C007EB181 /* IntentDispatcher.swift in Sources */,
|
||||||
|
0E330F572B30952300930C7C /* ProfilesList+TV.swift in Sources */,
|
||||||
0E0838FD2877334300A34EC0 /* DefaultLightProviderManager.swift in Sources */,
|
0E0838FD2877334300A34EC0 /* DefaultLightProviderManager.swift in Sources */,
|
||||||
0E2E0B772B335AAB00E3204A /* UpgradeManager.swift in Sources */,
|
0E2E0B772B335AAB00E3204A /* UpgradeManager.swift in Sources */,
|
||||||
0E0F4C6629C84CF60022E884 /* LogoView.swift in Sources */,
|
0E0F4C6629C84CF60022E884 /* LogoView.swift in Sources */,
|
||||||
|
@ -1471,6 +1534,7 @@
|
||||||
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */,
|
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */,
|
||||||
0E2E0B782B335AAB00E3204A /* PersistenceManager.swift in Sources */,
|
0E2E0B782B335AAB00E3204A /* PersistenceManager.swift in Sources */,
|
||||||
0EF8C5A828213C510053CE89 /* OrganizerView+Profiles.swift in Sources */,
|
0EF8C5A828213C510053CE89 /* OrganizerView+Profiles.swift in Sources */,
|
||||||
|
0E330F532B30469700930C7C /* MockProfileRepository.swift in Sources */,
|
||||||
0E3CD483280DAE92007075C0 /* ProfileView+MainMenu.swift in Sources */,
|
0E3CD483280DAE92007075C0 /* ProfileView+MainMenu.swift in Sources */,
|
||||||
0E71ACEB27C1060D00F85C4B /* EndpointView.swift in Sources */,
|
0E71ACEB27C1060D00F85C4B /* EndpointView.swift in Sources */,
|
||||||
0E293857285A73BC002A6E0E /* AppContext+Shared.swift in Sources */,
|
0E293857285A73BC002A6E0E /* AppContext+Shared.swift in Sources */,
|
||||||
|
@ -1478,6 +1542,7 @@
|
||||||
0EB4042E27CA136300378B1A /* AddingTextField.swift in Sources */,
|
0EB4042E27CA136300378B1A /* AddingTextField.swift in Sources */,
|
||||||
0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */,
|
0EE8B7E327FF340F00B68621 /* VPNProtocolType+FileExtensions.swift in Sources */,
|
||||||
0EF2212B27E667EA001D0BD7 /* AddProviderView+Name.swift in Sources */,
|
0EF2212B27E667EA001D0BD7 /* AddProviderView+Name.swift in Sources */,
|
||||||
|
0E1DC1BF2B3618EE008B755E /* ProfileView+TV.swift in Sources */,
|
||||||
0E065F112813269500062CAF /* WelcomeView.swift in Sources */,
|
0E065F112813269500062CAF /* WelcomeView.swift in Sources */,
|
||||||
0E2DE71F27DCD0290067B9E1 /* TunnelKit+L10n.swift in Sources */,
|
0E2DE71F27DCD0290067B9E1 /* TunnelKit+L10n.swift in Sources */,
|
||||||
0E49F6BF27D764AF00385834 /* EndpointAdvancedView.swift in Sources */,
|
0E49F6BF27D764AF00385834 /* EndpointAdvancedView.swift in Sources */,
|
||||||
|
@ -1500,9 +1565,11 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0EF6563F2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift in Sources */,
|
||||||
0ED2B35B27D3C94F00FD8EA9 /* PacketTunnelProvider.swift in Sources */,
|
0ED2B35B27D3C94F00FD8EA9 /* PacketTunnelProvider.swift in Sources */,
|
||||||
0ED30DDD27EA35230057D8A3 /* Constants.swift in Sources */,
|
0ED30DDD27EA35230057D8A3 /* Constants.swift in Sources */,
|
||||||
0ED1A5FD2B2B98CC00A0EA90 /* Constants+Tunnel.swift in Sources */,
|
0ED1A5FD2B2B98CC00A0EA90 /* Constants+Tunnel.swift in Sources */,
|
||||||
|
0EF656432B36C01200CEFC96 /* TunnelError.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1510,9 +1577,11 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0EF6563E2B36BFCD00CEFC96 /* NEPacketTunnelProvider+Expiration.swift in Sources */,
|
||||||
0E9AA978259F756A003FAFF1 /* PacketTunnelProvider.swift in Sources */,
|
0E9AA978259F756A003FAFF1 /* PacketTunnelProvider.swift in Sources */,
|
||||||
0EB17EA727D226B400D473B5 /* Constants.swift in Sources */,
|
0EB17EA727D226B400D473B5 /* Constants.swift in Sources */,
|
||||||
0ED30DDB27EA351C0057D8A3 /* Constants+Tunnel.swift in Sources */,
|
0ED30DDB27EA351C0057D8A3 /* Constants+Tunnel.swift in Sources */,
|
||||||
|
0EF656422B36C01200CEFC96 /* TunnelError.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1538,6 +1607,10 @@
|
||||||
};
|
};
|
||||||
0ECF71FC27B6DA6700CDB528 /* PBXTargetDependency */ = {
|
0ECF71FC27B6DA6700CDB528 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
|
platformFilters = (
|
||||||
|
ios,
|
||||||
|
maccatalyst,
|
||||||
|
);
|
||||||
target = 0ECF71F327B6D9CD00CDB528 /* WireGuardGo */;
|
target = 0ECF71F327B6D9CD00CDB528 /* WireGuardGo */;
|
||||||
targetProxy = 0ECF71FB27B6DA6700CDB528 /* PBXContainerItemProxy */;
|
targetProxy = 0ECF71FB27B6DA6700CDB528 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
@ -1551,6 +1624,14 @@
|
||||||
target = 0ECF71F327B6D9CD00CDB528 /* WireGuardGo */;
|
target = 0ECF71F327B6D9CD00CDB528 /* WireGuardGo */;
|
||||||
targetProxy = 0ED2B36A27D3CAB100FD8EA9 /* PBXContainerItemProxy */;
|
targetProxy = 0ED2B36A27D3CAB100FD8EA9 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
0EE79B352B2EDB9C00C1220C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
platformFilters = (
|
||||||
|
tvos,
|
||||||
|
);
|
||||||
|
target = 0EE79B302B2EDB5D00C1220C /* WireGuardGoTV */;
|
||||||
|
targetProxy = 0EE79B342B2EDB9C00C1220C /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
|
@ -1730,7 +1811,8 @@
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
TARGETED_DEVICE_FAMILY = "1,2,3";
|
||||||
|
TVOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -1791,7 +1873,8 @@
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
TARGETED_DEVICE_FAMILY = "1,2,3";
|
||||||
|
TVOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
@ -1801,6 +1884,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=appletvos*]" = TV;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Passepartout/App/App.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Passepartout/App/App.entitlements;
|
||||||
|
@ -1814,11 +1898,12 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID)";
|
||||||
PRODUCT_NAME = Passepartout;
|
PRODUCT_NAME = Passepartout;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst";
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_STRICT_CONCURRENCY = targeted;
|
SWIFT_STRICT_CONCURRENCY = targeted;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -1827,6 +1912,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=appletvos*]" = TV;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = Passepartout/App/App.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Passepartout/App/App.entitlements;
|
||||||
|
@ -1840,10 +1926,11 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID)";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID)";
|
||||||
PRODUCT_NAME = Passepartout;
|
PRODUCT_NAME = Passepartout;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout catalyst";
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_STRICT_CONCURRENCY = targeted;
|
SWIFT_STRICT_CONCURRENCY = targeted;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -1959,8 +2046,10 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).WireGuardTunnel";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).WireGuardTunnel";
|
||||||
PRODUCT_NAME = PassepartoutWireGuardTunnel;
|
PRODUCT_NAME = PassepartoutWireGuardTunnel;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel catalyst";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -1979,8 +2068,10 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).WireGuardTunnel";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).WireGuardTunnel";
|
||||||
PRODUCT_NAME = PassepartoutWireGuardTunnel;
|
PRODUCT_NAME = PassepartoutWireGuardTunnel;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.WireGuardTunnel catalyst";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
@ -1999,8 +2090,10 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).OpenVPNTunnel";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).OpenVPNTunnel";
|
||||||
PRODUCT_NAME = PassepartoutOpenVPNTunnel;
|
PRODUCT_NAME = PassepartoutOpenVPNTunnel;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel catalyst";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -2019,12 +2112,51 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).OpenVPNTunnel";
|
PRODUCT_BUNDLE_IDENTIFIER = "$(CFG_APP_ID).OpenVPNTunnel";
|
||||||
PRODUCT_NAME = PassepartoutOpenVPNTunnel;
|
PRODUCT_NAME = PassepartoutOpenVPNTunnel;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel";
|
PROVISIONING_PROFILE_SPECIFIER = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel tvos";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel catalyst";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match Development com.algoritmico.ios.Passepartout.OpenVPNTunnel catalyst";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
0EE79B322B2EDB5D00C1220C /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUGGING_SYMBOLS = YES;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
DEVELOPMENT_TEAM = DTDYD63ZX9;
|
||||||
|
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
OTHER_CFLAGS = "";
|
||||||
|
OTHER_LDFLAGS = "";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = appletvos;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
0EE79B332B2EDB5D00C1220C /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
DEVELOPMENT_TEAM = DTDYD63ZX9;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
OTHER_CFLAGS = "";
|
||||||
|
OTHER_LDFLAGS = "";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = appletvos;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
@ -2091,6 +2223,15 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
0EE79B312B2EDB5D00C1220C /* Build configuration list for PBXLegacyTarget "WireGuardGoTV" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
0EE79B322B2EDB5D00C1220C /* Debug */,
|
||||||
|
0EE79B332B2EDB5D00C1220C /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
|
|
@ -1,70 +1,67 @@
|
||||||
{
|
{
|
||||||
"object": {
|
"pins" : [
|
||||||
"pins": [
|
{
|
||||||
{
|
"identity" : "dtfoundation",
|
||||||
"package": "DTFoundation",
|
"kind" : "remoteSourceControl",
|
||||||
"repositoryURL": "https://github.com/Cocoanetics/DTFoundation.git",
|
"location" : "https://github.com/Cocoanetics/DTFoundation.git",
|
||||||
"state": {
|
"state" : {
|
||||||
"branch": null,
|
"revision" : "76062513434421cb6c8a1ae1d4f8368a7ebc2da3",
|
||||||
"revision": "76062513434421cb6c8a1ae1d4f8368a7ebc2da3",
|
"version" : "1.7.18"
|
||||||
"version": "1.7.18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "GenericJSON",
|
|
||||||
"repositoryURL": "https://github.com/zoul/generic-json-swift",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "0a06575f4038b504e78ac330913d920f1630f510",
|
|
||||||
"version": "2.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "Kvitto",
|
|
||||||
"repositoryURL": "https://github.com/Cocoanetics/Kvitto",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "88888674d772ddcf19671159ed0022cb0bc37be2",
|
|
||||||
"version": "1.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "openssl-apple",
|
|
||||||
"repositoryURL": "https://github.com/passepartoutvpn/openssl-apple",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "026702febcaebcbf9ea68f2fa66b017eba998cdf",
|
|
||||||
"version": "3.2.105"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "SwiftyBeaver",
|
|
||||||
"repositoryURL": "https://github.com/SwiftyBeaver/SwiftyBeaver",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "12b5acf96d98f91d50de447369bd18df74600f1a",
|
|
||||||
"version": "1.9.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "TunnelKit",
|
|
||||||
"repositoryURL": "https://github.com/passepartoutvpn/tunnelkit",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "bda84bf569792fbb702d0173de3c9c58768f9153",
|
|
||||||
"version": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"package": "WireGuardKit",
|
|
||||||
"repositoryURL": "https://github.com/passepartoutvpn/wireguard-apple",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "73d9152fa0cb661db0348a1ac11dbbf998422a50",
|
|
||||||
"version": "1.0.17"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
"version": 1
|
"identity" : "generic-json-swift",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zoul/generic-json-swift",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0a06575f4038b504e78ac330913d920f1630f510",
|
||||||
|
"version" : "2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "kvitto",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/Cocoanetics/Kvitto",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "88888674d772ddcf19671159ed0022cb0bc37be2",
|
||||||
|
"version" : "1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "openssl-apple",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/passepartoutvpn/openssl-apple",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "026702febcaebcbf9ea68f2fa66b017eba998cdf",
|
||||||
|
"version" : "3.2.105"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftybeaver",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/SwiftyBeaver/SwiftyBeaver",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
|
||||||
|
"version" : "1.9.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "tunnelkit",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/passepartoutvpn/tunnelkit",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "708c785e615f5715ce08386c772c92fb45730a3a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "wireguard-apple",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "develop",
|
||||||
|
"revision" : "b79f0f150356d8200a64922ecf041dd020140aa0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "APP_TYPE"
|
key = "APP_TYPE"
|
||||||
value = "2"
|
value = "2"
|
||||||
isEnabled = "YES">
|
isEnabled = "NO">
|
||||||
</EnvironmentVariable>
|
</EnvironmentVariable>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "LOG_LEVEL"
|
key = "LOG_LEVEL"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iCloud.com.algoritmico.Passepartout</string>
|
<string>iCloud.com.algoritmico.Passepartout</string>
|
||||||
|
<string>iCloud.com.algoritmico.Passepartout.Shared</string>
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.developer.icloud-services</key>
|
<key>com.apple.developer.icloud-services</key>
|
||||||
<array>
|
<array>
|
||||||
|
|
After Width: | Height: | Size: 5.6 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon.png",
|
||||||
|
"idiom" : "tv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"layers" : [
|
||||||
|
{
|
||||||
|
"filename" : "Front.imagestacklayer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Back.imagestacklayer"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon.png",
|
||||||
|
"idiom" : "tv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 8.3 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon@2x.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "2x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"layers" : [
|
||||||
|
{
|
||||||
|
"filename" : "Front.imagestacklayer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Back.imagestacklayer"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon@2x.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "2x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"assets" : [
|
||||||
|
{
|
||||||
|
"filename" : "App Icon - App Store.imagestack",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"role" : "primary-app-icon",
|
||||||
|
"size" : "1280x768"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "App Icon.imagestack",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"role" : "primary-app-icon",
|
||||||
|
"size" : "400x240"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Top Shelf Image Wide.imageset",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"role" : "top-shelf-image-wide",
|
||||||
|
"size" : "2320x720"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Top Shelf Image.imageset",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"role" : "top-shelf-image",
|
||||||
|
"size" : "1920x720"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
18
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image Wide.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "TopShelf.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "TopShelf@2x.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "2x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image Wide.imageset/TopShelf.png
vendored
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image Wide.imageset/TopShelf@2x.png
vendored
Normal file
After Width: | Height: | Size: 118 KiB |
18
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "TopShelf.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "TopShelf@2x.png",
|
||||||
|
"idiom" : "tv",
|
||||||
|
"scale" : "2x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image.imageset/TopShelf.png
vendored
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
Passepartout/App/Assets.xcassets/TV.brandassets/Top Shelf Image.imageset/TopShelf@2x.png
vendored
Normal file
After Width: | Height: | Size: 99 KiB |
|
@ -44,6 +44,8 @@ extension Constants {
|
||||||
enum CloudKit {
|
enum CloudKit {
|
||||||
static let containerId: String = bundleConfig("cloudkit_id")
|
static let containerId: String = bundleConfig("cloudkit_id")
|
||||||
|
|
||||||
|
static let sharedContainerId: String = bundleConfig("cloudkit_shared_id")
|
||||||
|
|
||||||
static let coreDataZone = "com.apple.coredata.cloudkit.zone"
|
static let coreDataZone = "com.apple.coredata.cloudkit.zone"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +86,8 @@ extension Constants {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static let tvLimitedMinutes = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +135,8 @@ extension Constants {
|
||||||
enum Persistence {
|
enum Persistence {
|
||||||
static let profilesContainerName = "Profiles"
|
static let profilesContainerName = "Profiles"
|
||||||
|
|
||||||
|
static let sharedProfilesContainerName = "SharedProfiles"
|
||||||
|
|
||||||
static let providersContainerName = "Providers"
|
static let providersContainerName = "Providers"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import LocalAuthentication
|
import LocalAuthentication
|
||||||
|
#endif
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -33,20 +35,28 @@ extension View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeIsiPadPortrait: Bool {
|
var themeIsiPadPortrait: Bool {
|
||||||
|
#if !os(tvOS)
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
false
|
false
|
||||||
#else
|
#else
|
||||||
let device: UIDevice = .current
|
let device: UIDevice = .current
|
||||||
return device.userInterfaceIdiom == .pad && device.orientation.isPortrait
|
return device.userInterfaceIdiom == .pad && device.orientation.isPortrait
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeIsiPadMultitasking: Bool {
|
var themeIsiPadMultitasking: Bool {
|
||||||
|
#if !os(tvOS)
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
false
|
false
|
||||||
#else
|
#else
|
||||||
UIDevice.current.userInterfaceIdiom == .pad
|
UIDevice.current.userInterfaceIdiom == .pad
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +65,7 @@ extension View {
|
||||||
extension View {
|
extension View {
|
||||||
func themeGlobal() -> some View {
|
func themeGlobal() -> some View {
|
||||||
themeNavigationViewStyle()
|
themeNavigationViewStyle()
|
||||||
|
#if !os(tvOS)
|
||||||
#if !targetEnvironment(macCatalyst)
|
#if !targetEnvironment(macCatalyst)
|
||||||
.themeLockScreen()
|
.themeLockScreen()
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,22 +73,39 @@ extension View {
|
||||||
.listStyle(themeListStyleValue())
|
.listStyle(themeListStyleValue())
|
||||||
.toggleStyle(themeToggleStyleValue())
|
.toggleStyle(themeToggleStyleValue())
|
||||||
.menuStyle(.borderlessButton)
|
.menuStyle(.borderlessButton)
|
||||||
|
#endif
|
||||||
.withErrorHandler()
|
.withErrorHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
func themeTV() -> some View {
|
||||||
|
GeometryReader { geo in
|
||||||
|
self
|
||||||
|
.padding(.horizontal, 0.25 * geo.size.width)
|
||||||
|
.scrollClipDisabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
func themePrimaryView() -> some View {
|
func themePrimaryView() -> some View {
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
navigationBarTitleDisplayMode(.inline)
|
navigationBarTitleDisplayMode(.inline)
|
||||||
.themeSidebarListStyle()
|
.themeSidebarListStyle()
|
||||||
#else
|
#elseif !os(tvOS)
|
||||||
navigationBarTitleDisplayMode(.large)
|
navigationBarTitleDisplayMode(.large)
|
||||||
.navigationTitle(Unlocalized.appName)
|
.navigationTitle(Unlocalized.appName)
|
||||||
.themeSidebarListStyle()
|
.themeSidebarListStyle()
|
||||||
|
#else
|
||||||
|
self
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
func themeSecondaryView() -> some View {
|
func themeSecondaryView() -> some View {
|
||||||
|
#if !os(tvOS)
|
||||||
navigationBarTitleDisplayMode(.inline)
|
navigationBarTitleDisplayMode(.inline)
|
||||||
|
#else
|
||||||
|
self
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
@ -93,6 +121,7 @@ extension View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func themeSidebarListStyle() -> some View {
|
private func themeSidebarListStyle() -> some View {
|
||||||
|
#if !os(tvOS)
|
||||||
switch themeIdiom {
|
switch themeIdiom {
|
||||||
case .phone:
|
case .phone:
|
||||||
listStyle(.insetGrouped)
|
listStyle(.insetGrouped)
|
||||||
|
@ -100,6 +129,9 @@ extension View {
|
||||||
default:
|
default:
|
||||||
listStyle(.sidebar)
|
listStyle(.sidebar)
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
self
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
@ -108,11 +140,19 @@ extension View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func themeListStyleValue() -> some ListStyle {
|
private func themeListStyleValue() -> some ListStyle {
|
||||||
|
#if !os(tvOS)
|
||||||
.insetGrouped
|
.insetGrouped
|
||||||
|
#else
|
||||||
|
PlainListStyle()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private func themeToggleStyleValue() -> some ToggleStyle {
|
private func themeToggleStyleValue() -> some ToggleStyle {
|
||||||
|
#if !os(tvOS)
|
||||||
.switch
|
.switch
|
||||||
|
#else
|
||||||
|
DefaultToggleStyle()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +219,10 @@ extension View {
|
||||||
"eye"
|
"eye"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var themeAppleTVImage: String {
|
||||||
|
"tv"
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Organizer
|
// MARK: Organizer
|
||||||
|
|
||||||
func themeAssetsProviderImage(_ providerName: ProviderName) -> String {
|
func themeAssetsProviderImage(_ providerName: ProviderName) -> String {
|
||||||
|
@ -387,6 +431,7 @@ extension View {
|
||||||
|
|
||||||
// MARK: Shortcuts
|
// MARK: Shortcuts
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
extension ShortcutType {
|
extension ShortcutType {
|
||||||
var themeImageName: String {
|
var themeImageName: String {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -401,6 +446,7 @@ extension ShortcutType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// MARK: Animations
|
// MARK: Animations
|
||||||
|
|
||||||
|
@ -497,6 +543,7 @@ extension View {
|
||||||
|
|
||||||
// MARK: Lock screen
|
// MARK: Lock screen
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
extension View {
|
extension View {
|
||||||
func themeLockScreen() -> some View {
|
func themeLockScreen() -> some View {
|
||||||
@AppStorage(AppPreference.locksInBackground.key) var locksInBackground = false
|
@AppStorage(AppPreference.locksInBackground.key) var locksInBackground = false
|
||||||
|
@ -528,6 +575,7 @@ extension View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// MARK: Validation
|
// MARK: Validation
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ final class AppContext {
|
||||||
persistenceManager = PersistenceManager(
|
persistenceManager = PersistenceManager(
|
||||||
store: store,
|
store: store,
|
||||||
ckContainerId: Constants.CloudKit.containerId,
|
ckContainerId: Constants.CloudKit.containerId,
|
||||||
|
ckSharedContainerId: Constants.CloudKit.sharedContainerId,
|
||||||
ckCoreDataZone: Constants.CloudKit.coreDataZone
|
ckCoreDataZone: Constants.CloudKit.coreDataZone
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,6 +95,10 @@ final class AppContext {
|
||||||
|
|
||||||
private extension AppContext {
|
private extension AppContext {
|
||||||
func configureObjects() {
|
func configureObjects() {
|
||||||
|
coreContext.profileManager.willSaveSharedProfile = { [unowned self] in
|
||||||
|
willSaveSharedProfile(withNewProfile: $0, existingProfile: $1)
|
||||||
|
}
|
||||||
|
|
||||||
coreContext.vpnManager.isOnDemandRulesSupported = {
|
coreContext.vpnManager.isOnDemandRulesSupported = {
|
||||||
self.isEligibleForOnDemandRules()
|
self.isEligibleForOnDemandRules()
|
||||||
}
|
}
|
||||||
|
@ -101,6 +106,13 @@ private extension AppContext {
|
||||||
self.isEligibleForNetworkSettings()
|
self.isEligibleForNetworkSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coreContext.vpnManager.userData = {
|
||||||
|
if let expirationDate = $0.connectionExpirationDate {
|
||||||
|
return [Constants.Tunnel.expirationTimeIntervalKey: expirationDate.timeIntervalSinceReferenceDate]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
coreContext.vpnManager.currentState.$vpnStatus
|
coreContext.vpnManager.currentState.$vpnStatus
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
|
@ -138,4 +150,41 @@ private extension AppContext {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eligibility: expire restricted TV profiles after N minutes
|
||||||
|
func willSaveSharedProfile(withNewProfile newProfile: Profile, existingProfile: Profile?) -> Profile {
|
||||||
|
if let existingProfile {
|
||||||
|
assert(newProfile.id == existingProfile.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard productManager.isEligible(forFeature: .appleTV) else {
|
||||||
|
var restricted = newProfile
|
||||||
|
let remainingMinutes: Int
|
||||||
|
let expirationDate: Date
|
||||||
|
|
||||||
|
// retain current expiration period if any
|
||||||
|
if let currentExpirationDate = existingProfile?.connectionExpirationDate {
|
||||||
|
remainingMinutes = Int(currentExpirationDate.timeIntervalSinceNow / 60.0)
|
||||||
|
expirationDate = currentExpirationDate
|
||||||
|
}
|
||||||
|
// otherwise, expire in N minutes from now
|
||||||
|
else {
|
||||||
|
remainingMinutes = Constants.InApp.tvLimitedMinutes
|
||||||
|
expirationDate = Date()
|
||||||
|
.addingTimeInterval(TimeInterval(remainingMinutes) * 60.0)
|
||||||
|
|
||||||
|
restricted.connectionExpirationDate = expirationDate
|
||||||
|
}
|
||||||
|
|
||||||
|
if remainingMinutes > 0 {
|
||||||
|
pp_log.warning("\(newProfile.logDescription): TV connection expires in \(remainingMinutes) minutes (at \(expirationDate))")
|
||||||
|
} else {
|
||||||
|
pp_log.warning("\(newProfile.logDescription): TV connection expired at \(expirationDate)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return restricted
|
||||||
|
}
|
||||||
|
|
||||||
|
return newProfile
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,14 @@ final class CoreContext {
|
||||||
init(persistenceManager: PersistenceManager) {
|
init(persistenceManager: PersistenceManager) {
|
||||||
store = persistenceManager.store
|
store = persistenceManager.store
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
let vpnPersistence = persistenceManager.loadVPNPersistence(
|
let vpnPersistence = persistenceManager.loadVPNPersistence(
|
||||||
withName: Constants.Persistence.profilesContainerName
|
withName: Constants.Persistence.profilesContainerName
|
||||||
)
|
)
|
||||||
|
#endif
|
||||||
|
let sharedVPNPersistence = persistenceManager.loadSharedVPNPersistence(
|
||||||
|
withName: Constants.Persistence.sharedProfilesContainerName
|
||||||
|
)
|
||||||
let providersPersistence = persistenceManager.loadProvidersPersistence(
|
let providersPersistence = persistenceManager.loadProvidersPersistence(
|
||||||
withName: Constants.Persistence.providersContainerName
|
withName: Constants.Persistence.providersContainerName
|
||||||
)
|
)
|
||||||
|
@ -68,10 +73,20 @@ final class CoreContext {
|
||||||
remoteProvidersStrategy: remoteProvidersStrategy
|
remoteProvidersStrategy: remoteProvidersStrategy
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let tvProfileRepository = sharedVPNPersistence.profileRepository()
|
||||||
|
#if !os(tvOS)
|
||||||
|
let profileRepository = vpnPersistence.profileRepository()
|
||||||
|
let sharedProfileRepository = tvProfileRepository
|
||||||
|
#else
|
||||||
|
let profileRepository = tvProfileRepository
|
||||||
|
let sharedProfileRepository: ProfileRepository? = nil
|
||||||
|
#endif
|
||||||
|
|
||||||
profileManager = ProfileManager(
|
profileManager = ProfileManager(
|
||||||
store: store,
|
store: store,
|
||||||
providerManager: providerManager,
|
providerManager: providerManager,
|
||||||
profileRepository: vpnPersistence.profileRepository(),
|
profileRepository: profileRepository,
|
||||||
|
sharedProfileRepository: sharedProfileRepository,
|
||||||
keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId),
|
keychain: KeychainSecretRepository(appGroup: Constants.App.appGroupId),
|
||||||
keychainEntry: Unlocalized.Keychain.passwordEntry,
|
keychainEntry: Unlocalized.Keychain.passwordEntry,
|
||||||
keychainLabel: Unlocalized.Keychain.passwordLabel
|
keychainLabel: Unlocalized.Keychain.passwordLabel
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// MockProfileRepository.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/18/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import PassepartoutLibrary
|
||||||
|
|
||||||
|
final class MockProfileRepository: ProfileRepository, ObservableObject {
|
||||||
|
@Published var profiles: [UUID: Profile]
|
||||||
|
|
||||||
|
init() {
|
||||||
|
profiles = [:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func allProfiles() -> [UUID: Profile] {
|
||||||
|
profiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func profile(withId id: UUID) -> Profile? {
|
||||||
|
profiles[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveProfiles(_ profiles: [Profile]) throws {
|
||||||
|
profiles.forEach {
|
||||||
|
self.profiles[$0.id] = $0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeProfiles(withIds ids: [UUID]) {
|
||||||
|
ids.forEach {
|
||||||
|
profiles.removeValue(forKey: $0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func willUpdateProfiles() -> AnyPublisher<[UUID: Profile], Never> {
|
||||||
|
$profiles.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,8 @@ enum AppError: Error {
|
||||||
|
|
||||||
case vpn(Passepartout.VPNError)
|
case vpn(Passepartout.VPNError)
|
||||||
|
|
||||||
|
case tunnel(TunnelError)
|
||||||
|
|
||||||
case generic(Error)
|
case generic(Error)
|
||||||
|
|
||||||
init(_ error: Error) {
|
init(_ error: Error) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Foundation
|
import Foundation
|
||||||
import Intents
|
import Intents
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
|
@ -157,3 +158,4 @@ extension IntentDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Foundation
|
import Foundation
|
||||||
import Intents
|
import Intents
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
|
@ -157,3 +158,4 @@ private extension INInteraction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>$(CFG_APP_ID)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
<array>
|
<array>
|
||||||
<string>armv7</string>
|
<string>arm64</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
|
@ -99,10 +99,12 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>appstore_id</key>
|
<key>appstore_id</key>
|
||||||
<string>$(CFG_APPSTORE_ID)</string>
|
<string>$(CFG_APPSTORE_ID)</string>
|
||||||
<key>group_id</key>
|
|
||||||
<string>group.$(CFG_GROUP_ID)</string>
|
|
||||||
<key>cloudkit_id</key>
|
<key>cloudkit_id</key>
|
||||||
<string>iCloud.$(CFG_GROUP_ID)</string>
|
<string>iCloud.$(CFG_GROUP_ID)</string>
|
||||||
|
<key>cloudkit_shared_id</key>
|
||||||
|
<string>iCloud.$(CFG_GROUP_ID).Shared</string>
|
||||||
|
<key>group_id</key>
|
||||||
|
<string>group.$(CFG_GROUP_ID)</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -77,6 +77,12 @@ extension AppError: LocalizedError {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case .tunnel(let tunnelError):
|
||||||
|
switch tunnelError {
|
||||||
|
case .expired:
|
||||||
|
return V.tunnelExpired
|
||||||
|
}
|
||||||
|
|
||||||
case .generic(let error):
|
case .generic(let error):
|
||||||
return error.localizedDescription
|
return error.localizedDescription
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,8 @@ enum Unlocalized {
|
||||||
|
|
||||||
static let iCloud = "iCloud"
|
static let iCloud = "iCloud"
|
||||||
|
|
||||||
|
static let appleTV = "Apple TV"
|
||||||
|
|
||||||
static let totp = "TOTP"
|
static let totp = "TOTP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
@preconcurrency import Intents
|
@preconcurrency import Intents
|
||||||
|
@ -106,3 +107,4 @@ extension IntentsManager: INUIEditVoiceShortcutViewControllerDelegate {
|
||||||
shouldDismissIntentView.send()
|
shouldDismissIntentView.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -35,10 +35,14 @@ final class PersistenceManager: ObservableObject {
|
||||||
|
|
||||||
private let ckContainerId: String
|
private let ckContainerId: String
|
||||||
|
|
||||||
|
private let ckSharedContainerId: String
|
||||||
|
|
||||||
private let ckCoreDataZone: String
|
private let ckCoreDataZone: String
|
||||||
|
|
||||||
private var vpnPersistence: VPNPersistence?
|
private var vpnPersistence: VPNPersistence?
|
||||||
|
|
||||||
|
private var sharedVPNPersistence: VPNPersistence?
|
||||||
|
|
||||||
private var providersPersistence: ProvidersPersistence?
|
private var providersPersistence: ProvidersPersistence?
|
||||||
|
|
||||||
private(set) var isCloudSyncingEnabled: Bool {
|
private(set) var isCloudSyncingEnabled: Bool {
|
||||||
|
@ -52,9 +56,13 @@ final class PersistenceManager: ObservableObject {
|
||||||
|
|
||||||
let didChangePersistence = PassthroughSubject<Void, Never>()
|
let didChangePersistence = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
init(store: KeyValueStore, ckContainerId: String, ckCoreDataZone: String) {
|
init(store: KeyValueStore,
|
||||||
|
ckContainerId: String,
|
||||||
|
ckSharedContainerId: String,
|
||||||
|
ckCoreDataZone: String) {
|
||||||
self.store = store
|
self.store = store
|
||||||
self.ckContainerId = ckContainerId
|
self.ckContainerId = ckContainerId
|
||||||
|
self.ckSharedContainerId = ckSharedContainerId
|
||||||
self.ckCoreDataZone = ckCoreDataZone
|
self.ckCoreDataZone = ckCoreDataZone
|
||||||
isCloudSyncingEnabled = store.canEnableCloudSyncing
|
isCloudSyncingEnabled = store.canEnableCloudSyncing
|
||||||
|
|
||||||
|
@ -65,11 +73,23 @@ final class PersistenceManager: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadVPNPersistence(withName containerName: String) -> VPNPersistence {
|
func loadVPNPersistence(withName containerName: String) -> VPNPersistence {
|
||||||
let persistence = VPNPersistence(withName: containerName, cloudKit: isCloudSyncingEnabled, author: persistenceAuthor)
|
let persistence = VPNPersistence(withName: containerName,
|
||||||
|
cloudKit: isCloudSyncingEnabled,
|
||||||
|
cloudKitIdentifier: nil,
|
||||||
|
author: persistenceAuthor)
|
||||||
vpnPersistence = persistence
|
vpnPersistence = persistence
|
||||||
return persistence
|
return persistence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadSharedVPNPersistence(withName containerName: String) -> VPNPersistence {
|
||||||
|
let persistence = VPNPersistence(withName: containerName,
|
||||||
|
cloudKit: true,
|
||||||
|
cloudKitIdentifier: ckSharedContainerId,
|
||||||
|
author: persistenceAuthor)
|
||||||
|
sharedVPNPersistence = persistence
|
||||||
|
return persistence
|
||||||
|
}
|
||||||
|
|
||||||
func loadProvidersPersistence(withName containerName: String) -> ProvidersPersistence {
|
func loadProvidersPersistence(withName containerName: String) -> ProvidersPersistence {
|
||||||
let persistence = ProvidersPersistence(withName: containerName, cloudKit: false, author: persistenceAuthor)
|
let persistence = ProvidersPersistence(withName: containerName, cloudKit: false, author: persistenceAuthor)
|
||||||
providersPersistence = persistence
|
providersPersistence = persistence
|
||||||
|
@ -86,6 +106,10 @@ extension PersistenceManager {
|
||||||
fromContainerWithId: ckContainerId,
|
fromContainerWithId: ckContainerId,
|
||||||
zoneId: .init(zoneName: ckCoreDataZone)
|
zoneId: .init(zoneName: ckCoreDataZone)
|
||||||
)
|
)
|
||||||
|
await Self.eraseCloudKitStore(
|
||||||
|
fromContainerWithId: ckSharedContainerId,
|
||||||
|
zoneId: .init(zoneName: ckCoreDataZone)
|
||||||
|
)
|
||||||
isErasingCloudKitStore = false
|
isErasingCloudKitStore = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +133,11 @@ private extension KeyValueStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isCloudKitSupported: Bool {
|
private var isCloudKitSupported: Bool {
|
||||||
|
#if !os(tvOS)
|
||||||
cloudKitToken != nil
|
cloudKitToken != nil
|
||||||
|
#else
|
||||||
|
true
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var canEnableCloudSyncing: Bool {
|
var canEnableCloudSyncing: Bool {
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct PassepartoutApp: App {
|
||||||
@SceneBuilder var body: some Scene {
|
@SceneBuilder var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
MainView()
|
MainView()
|
||||||
|
#if !os(tvOS)
|
||||||
.withoutTitleBar()
|
.withoutTitleBar()
|
||||||
.onIntentActivity(IntentDispatcher.connectVPN)
|
.onIntentActivity(IntentDispatcher.connectVPN)
|
||||||
.onIntentActivity(IntentDispatcher.disableVPN)
|
.onIntentActivity(IntentDispatcher.disableVPN)
|
||||||
|
@ -42,6 +43,7 @@ struct PassepartoutApp: App {
|
||||||
.onIntentActivity(IntentDispatcher.trustCurrentNetwork)
|
.onIntentActivity(IntentDispatcher.trustCurrentNetwork)
|
||||||
.onIntentActivity(IntentDispatcher.untrustCellularNetwork)
|
.onIntentActivity(IntentDispatcher.untrustCellularNetwork)
|
||||||
.onIntentActivity(IntentDispatcher.untrustCurrentNetwork)
|
.onIntentActivity(IntentDispatcher.untrustCurrentNetwork)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
@ -38,3 +39,4 @@ struct ActivityView: UIViewControllerRepresentable {
|
||||||
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityView>) {
|
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityView>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -180,7 +180,9 @@ private extension GenericCreditsView {
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
||||||
.padding()
|
.padding()
|
||||||
}.navigationTitle(content.name)
|
}.navigationTitle(content.name)
|
||||||
|
#if !os(tvOS)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Intents
|
import Intents
|
||||||
import IntentsUI
|
import IntentsUI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -41,3 +42,4 @@ struct IntentAddView: UIViewControllerRepresentable {
|
||||||
func updateUIViewController(_ uiViewController: INUIAddVoiceShortcutViewController, context: UIViewControllerRepresentableContext<IntentAddView>) {
|
func updateUIViewController(_ uiViewController: INUIAddVoiceShortcutViewController, context: UIViewControllerRepresentableContext<IntentAddView>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Intents
|
import Intents
|
||||||
import IntentsUI
|
import IntentsUI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -41,3 +42,4 @@ struct IntentEditView: UIViewControllerRepresentable {
|
||||||
func updateUIViewController(_ uiViewController: INUIEditVoiceShortcutViewController, context: UIViewControllerRepresentableContext<IntentEditView>) {
|
func updateUIViewController(_ uiViewController: INUIEditVoiceShortcutViewController, context: UIViewControllerRepresentableContext<IntentEditView>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -29,9 +29,15 @@ struct LongContentView: View {
|
||||||
@Binding var content: String
|
@Binding var content: String
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
#if !os(tvOS)
|
||||||
TextEditor(text: $content)
|
TextEditor(text: $content)
|
||||||
.font(.system(.body, design: .monospaced))
|
.font(.system(.body, design: .monospaced))
|
||||||
// .padding()
|
// .padding()
|
||||||
|
#else
|
||||||
|
Text(content)
|
||||||
|
.font(.system(.body, design: .monospaced))
|
||||||
|
// .padding()
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: layout, add padding an inset, let content extend beyond safe areas
|
// TODO: layout, add padding an inset, let content extend beyond safe areas
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import MessageUI
|
import MessageUI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -82,3 +83,4 @@ extension MailComposerView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -75,17 +75,21 @@ public final class Reviewer: ObservableObject {
|
||||||
defaults.removeObject(forKey: Keys.eventCount)
|
defaults.removeObject(forKey: Keys.eventCount)
|
||||||
defaults.set(currentVersion, forKey: Keys.lastVersion)
|
defaults.set(currentVersion, forKey: Keys.lastVersion)
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
requestReview()
|
requestReview()
|
||||||
|
#endif
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// may or may not appear
|
// may or may not appear
|
||||||
|
#if !os(tvOS)
|
||||||
private func requestReview() {
|
private func requestReview() {
|
||||||
guard let scene = UIApplication.shared.connectedScenes.first(where: { $0 is UIWindowScene }) as? UIWindowScene else {
|
guard let scene = UIApplication.shared.connectedScenes.first(where: { $0 is UIWindowScene }) as? UIWindowScene else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SKStoreReviewController.requestReview(in: scene)
|
SKStoreReviewController.requestReview(in: scene)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public static func urlForReview(withAppId appId: String) -> URL {
|
public static func urlForReview(withAppId appId: String) -> URL {
|
||||||
URL(string: "https://apps.apple.com/app/id\(appId)?action=write-review")!
|
URL(string: "https://apps.apple.com/app/id\(appId)?action=write-review")!
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Foundation
|
import Foundation
|
||||||
import Intents
|
import Intents
|
||||||
|
|
||||||
|
@ -53,3 +54,4 @@ struct Shortcut: Identifiable, Hashable, Comparable {
|
||||||
native.invocationPhrase.lowercased()
|
native.invocationPhrase.lowercased()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -89,3 +90,4 @@ private extension ShortcutType {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -33,10 +33,14 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
MacBundle.shared.utils.sendAppToBackground()
|
MacBundle.shared.utils.sendAppToBackground()
|
||||||
#endif
|
#endif
|
||||||
|
#if !os(tvOS)
|
||||||
rebuildShortcutItems()
|
rebuildShortcutItems()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||||
handleShortcutItem(shortcutItem)
|
handleShortcutItem(shortcutItem)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct DebugLogView: View {
|
||||||
refreshLog(scrollingToLatestWith: scrollProxy)
|
refreshLog(scrollingToLatestWith: scrollProxy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
Button(action: copyDebugLog) {
|
Button(action: copyDebugLog) {
|
||||||
|
@ -82,7 +83,9 @@ struct DebugLogView: View {
|
||||||
} else {
|
} else {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
}
|
}
|
||||||
}.sheet(isPresented: $isSharing, content: sharingActivityView)
|
}
|
||||||
|
.sheet(isPresented: $isSharing, content: sharingActivityView)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
.edgesIgnoringSafeArea([.leading, .trailing])
|
.edgesIgnoringSafeArea([.leading, .trailing])
|
||||||
.onReceive(timer, perform: refreshLog)
|
.onReceive(timer, perform: refreshLog)
|
||||||
|
@ -104,9 +107,11 @@ private extension DebugLogView {
|
||||||
// TODO: layout, a slight padding would be nice, but it glitches on first touch
|
// TODO: layout, a slight padding would be nice, but it glitches on first touch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
func sharingActivityView() -> some View {
|
func sharingActivityView() -> some View {
|
||||||
ActivityView(activityItems: sharingItems)
|
ActivityView(activityItems: sharingItems)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var sharingItems: [Any] {
|
var sharingItems: [Any] {
|
||||||
let raw = logLines.joined(separator: "\n")
|
let raw = logLines.joined(separator: "\n")
|
||||||
|
@ -140,6 +145,7 @@ private extension DebugLogView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
func shareDebugLog() {
|
func shareDebugLog() {
|
||||||
guard !logLines.isEmpty else {
|
guard !logLines.isEmpty else {
|
||||||
assertionFailure("Log is empty, why could it share?")
|
assertionFailure("Log is empty, why could it share?")
|
||||||
|
@ -159,6 +165,7 @@ private extension DebugLogView {
|
||||||
|
|
||||||
Utils.copyToPasteboard(content)
|
Utils.copyToPasteboard(content)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
func scrollToLatestUpdate(_ proxy: ScrollViewProxy) {
|
func scrollToLatestUpdate(_ proxy: ScrollViewProxy) {
|
||||||
proxy.maybeScrollTo(logLines.count - 1, anchor: .bottomLeading)
|
proxy.maybeScrollTo(logLines.count - 1, anchor: .bottomLeading)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import TunnelKitOpenVPN
|
import TunnelKitOpenVPN
|
||||||
|
@ -200,3 +201,4 @@ private extension DiagnosticsView.OpenVPNView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -32,7 +32,9 @@ struct DiagnosticsView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
if !profile.isPlaceholder {
|
if !profile.isPlaceholder {
|
||||||
|
#if !os(tvOS)
|
||||||
vpnView
|
vpnView
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
genericView
|
genericView
|
||||||
}
|
}
|
||||||
|
@ -41,6 +43,8 @@ struct DiagnosticsView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension DiagnosticsView {
|
private extension DiagnosticsView {
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
var vpnView: some View {
|
var vpnView: some View {
|
||||||
Group {
|
Group {
|
||||||
switch profile.currentVPNProtocol {
|
switch profile.currentVPNProtocol {
|
||||||
|
@ -56,6 +60,7 @@ private extension DiagnosticsView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var genericView: some View {
|
var genericView: some View {
|
||||||
List {
|
List {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import TunnelKitCore
|
import TunnelKitCore
|
||||||
|
@ -111,3 +112,4 @@ private extension EndpointView.AddView {
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import TunnelKitOpenVPN
|
import TunnelKitOpenVPN
|
||||||
|
@ -394,3 +395,4 @@ private extension Profile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import TunnelKitWireGuard
|
import TunnelKitWireGuard
|
||||||
|
@ -155,3 +156,4 @@ private extension ObservableProfile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -48,3 +49,4 @@ struct EndpointView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct MainView: View {
|
struct MainView: View {
|
||||||
|
@ -33,3 +34,4 @@ struct MainView: View {
|
||||||
}.themeGlobal()
|
}.themeGlobal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -137,8 +137,10 @@ private extension OnDemandView {
|
||||||
guard isEligibleForSiri else {
|
guard isEligibleForSiri else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
IntentDispatcher.donateTrustCellularNetwork()
|
IntentDispatcher.donateTrustCellularNetwork()
|
||||||
IntentDispatcher.donateUntrustCellularNetwork()
|
IntentDispatcher.donateUntrustCellularNetwork()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// eligibility: donate intents if eligible for Siri
|
// eligibility: donate intents if eligible for Siri
|
||||||
|
@ -146,7 +148,9 @@ private extension OnDemandView {
|
||||||
guard isEligibleForSiri else {
|
guard isEligibleForSiri else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
IntentDispatcher.donateTrustCurrentNetwork()
|
IntentDispatcher.donateTrustCurrentNetwork()
|
||||||
IntentDispatcher.donateUntrustCurrentNetwork()
|
IntentDispatcher.donateUntrustCurrentNetwork()
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ extension OrganizerView {
|
||||||
VPNToggle(
|
VPNToggle(
|
||||||
profile: profile,
|
profile: profile,
|
||||||
interactiveProfile: interactiveProfile,
|
interactiveProfile: interactiveProfile,
|
||||||
|
title: L10n.Global.Strings.enabled,
|
||||||
rateLimit: Constants.RateLimit.vpnToggle
|
rateLimit: Constants.RateLimit.vpnToggle
|
||||||
).labelsHidden()
|
).labelsHidden()
|
||||||
}.padding([.top, .bottom], 10)
|
}.padding([.top, .bottom], 10)
|
||||||
|
@ -81,3 +83,4 @@ private extension OrganizerView.ProfileRow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -187,3 +188,4 @@ private extension OrganizerView.ProfilesList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -84,3 +85,4 @@ private extension OrganizerView.SceneView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
@ -89,12 +90,14 @@ struct OrganizerView: View {
|
||||||
presenting: alertType,
|
presenting: alertType,
|
||||||
actions: alertActions,
|
actions: alertActions,
|
||||||
message: alertMessage
|
message: alertMessage
|
||||||
).fileImporter(
|
)
|
||||||
|
.fileImporter(
|
||||||
isPresented: $isHostFileImporterPresented,
|
isPresented: $isHostFileImporterPresented,
|
||||||
allowedContentTypes: hostFileTypes,
|
allowedContentTypes: hostFileTypes,
|
||||||
allowsMultipleSelection: false,
|
allowsMultipleSelection: false,
|
||||||
onCompletion: onHostFileImporterResult
|
onCompletion: onHostFileImporterResult
|
||||||
).onOpenURL(perform: onOpenURL)
|
)
|
||||||
|
.onOpenURL(perform: onOpenURL)
|
||||||
.themePrimaryView()
|
.themePrimaryView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,3 +174,4 @@ private extension OrganizerView {
|
||||||
addProfileModalType = .addHost(url, false)
|
addProfileModalType = .addHost(url, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -44,6 +44,8 @@ extension PaywallView {
|
||||||
|
|
||||||
@State private var purchaseState: PurchaseState?
|
@State private var purchaseState: PurchaseState?
|
||||||
|
|
||||||
|
@State private var didPurchaseAppleTV = false
|
||||||
|
|
||||||
init(isPresented: Binding<Bool>, feature: LocalProduct? = nil) {
|
init(isPresented: Binding<Bool>, feature: LocalProduct? = nil) {
|
||||||
productManager = .shared
|
productManager = .shared
|
||||||
_isPresented = isPresented
|
_isPresented = isPresented
|
||||||
|
@ -52,12 +54,22 @@ extension PaywallView {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
featuresSection
|
skFullVersion.map {
|
||||||
|
fullFeaturesSection(withHeader: $0.localizedTitle)
|
||||||
|
}
|
||||||
purchaseSection
|
purchaseSection
|
||||||
.disabled(purchaseState != nil)
|
.disabled(purchaseState != nil)
|
||||||
restoreSection
|
restoreSection
|
||||||
.disabled(purchaseState != nil)
|
.disabled(purchaseState != nil)
|
||||||
}.navigationTitle(Unlocalized.appName)
|
}
|
||||||
|
.navigationTitle(Unlocalized.appName)
|
||||||
|
.alert(Unlocalized.Other.appleTV, isPresented: $didPurchaseAppleTV) {
|
||||||
|
Button(L10n.Global.Strings.ok) {
|
||||||
|
isPresented = false
|
||||||
|
}
|
||||||
|
} message: {
|
||||||
|
Text(L10n.Paywall.Alerts.Purchase.Appletv.Success.message)
|
||||||
|
}
|
||||||
|
|
||||||
// reloading
|
// reloading
|
||||||
.task {
|
.task {
|
||||||
|
@ -121,9 +133,9 @@ private struct PurchaseRow: View {
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
private extension PaywallView.PurchaseView {
|
private extension PaywallView.PurchaseView {
|
||||||
var featuresSection: some View {
|
func fullFeaturesSection(withHeader header: String) -> some View {
|
||||||
Section {
|
Section {
|
||||||
ForEach(features) { feature in
|
ForEach(fullFeatures) { feature in
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text(feature.title)
|
Text(feature.title)
|
||||||
.themeCellTitleStyle()
|
.themeCellTitleStyle()
|
||||||
|
@ -134,6 +146,8 @@ private extension PaywallView.PurchaseView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
Text(header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +197,9 @@ private extension PaywallView.PurchaseView {
|
||||||
|
|
||||||
// hide full version if already bought the other platform version
|
// hide full version if already bought the other platform version
|
||||||
var skFullVersion: InAppProduct? {
|
var skFullVersion: InAppProduct? {
|
||||||
|
guard !productManager.isFullVersion() else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
guard !productManager.hasPurchased(.fullVersion_iOS) else {
|
guard !productManager.hasPurchased(.fullVersion_iOS) else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -195,17 +212,25 @@ private extension PaywallView.PurchaseView {
|
||||||
return productManager.product(withIdentifier: .fullVersion)
|
return productManager.product(withIdentifier: .fullVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
var features: [FeatureModel] {
|
var skAppleTV: InAppProduct? {
|
||||||
|
guard feature == .appleTV else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return productManager.product(withIdentifier: .appleTV)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullFeatures: [FeatureModel] {
|
||||||
productManager.featureProducts(excluding: {
|
productManager.featureProducts(excluding: {
|
||||||
$0 == .fullVersion || $0.isPlatformVersion
|
$0 == .fullVersion || $0 == .appleTV || $0.isLegacyPlatformVersion
|
||||||
})
|
})
|
||||||
.map {
|
.map {
|
||||||
FeatureModel(product: $0)
|
FeatureModel(product: $0)
|
||||||
}
|
}
|
||||||
|
.sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
var productRowModels: [InAppProduct] {
|
var productRowModels: [InAppProduct] {
|
||||||
[skFullVersion]
|
[skFullVersion, skAppleTV]
|
||||||
.compactMap { $0 }
|
.compactMap { $0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,16 +274,25 @@ private extension PurchaseRow {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
|
// IMPORTANT: resync shared profiles after purchasing Apple TV feature (drop time limit)
|
||||||
|
|
||||||
private extension PaywallView.PurchaseView {
|
private extension PaywallView.PurchaseView {
|
||||||
func purchaseProduct(_ product: InAppProduct) {
|
func purchaseProduct(_ product: InAppProduct) {
|
||||||
purchaseState = .purchasing(product)
|
purchaseState = .purchasing(product)
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
|
let wasEligibleForAppleTV = productManager.isEligible(forFeature: .appleTV)
|
||||||
let result = try await productManager.purchase(product)
|
let result = try await productManager.purchase(product)
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .done:
|
case .done:
|
||||||
isPresented = false
|
if !wasEligibleForAppleTV && productManager.isEligible(forFeature: .appleTV) {
|
||||||
|
ProfileManager.shared.refreshSharedProfiles()
|
||||||
|
didPurchaseAppleTV = true
|
||||||
|
} else {
|
||||||
|
isPresented = false
|
||||||
|
}
|
||||||
|
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
break
|
break
|
||||||
|
@ -281,8 +315,16 @@ private extension PaywallView.PurchaseView {
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
|
let wasEligibleForAppleTV = productManager.isEligible(forFeature: .appleTV)
|
||||||
try await productManager.restorePurchases()
|
try await productManager.restorePurchases()
|
||||||
isPresented = false
|
|
||||||
|
if !wasEligibleForAppleTV && productManager.isEligible(forFeature: .appleTV) {
|
||||||
|
ProfileManager.shared.refreshSharedProfiles()
|
||||||
|
didPurchaseAppleTV = true
|
||||||
|
} else {
|
||||||
|
isPresented = false
|
||||||
|
}
|
||||||
|
|
||||||
purchaseState = nil
|
purchaseState = nil
|
||||||
} catch {
|
} catch {
|
||||||
pp_log.error("Unable to restore purchases: \(error)")
|
pp_log.error("Unable to restore purchases: \(error)")
|
||||||
|
|
|
@ -53,11 +53,13 @@ extension ProfileView {
|
||||||
Label(L10n.Global.Strings.protocol, systemImage: themeVPNProtocolImage)
|
Label(L10n.Global.Strings.protocol, systemImage: themeVPNProtocolImage)
|
||||||
.withTrailingText(currentProfile.value.currentVPNProtocol.description)
|
.withTrailingText(currentProfile.value.currentVPNProtocol.description)
|
||||||
}
|
}
|
||||||
|
#if !os(tvOS)
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
EndpointView(currentProfile: currentProfile)
|
EndpointView(currentProfile: currentProfile)
|
||||||
} label: {
|
} label: {
|
||||||
Label(L10n.Global.Strings.endpoint, systemImage: themeEndpointImage)
|
Label(L10n.Global.Strings.endpoint, systemImage: themeEndpointImage)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if currentProfile.value.requiresCredentials {
|
if currentProfile.value.requiresCredentials {
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
AccountView(
|
AccountView(
|
||||||
|
|
|
@ -96,6 +96,7 @@ extension ProfileView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
struct ShortcutsButton: View {
|
struct ShortcutsButton: View {
|
||||||
@ObservedObject private var productManager: ProductManager
|
@ObservedObject private var productManager: ProductManager
|
||||||
|
|
||||||
|
@ -114,6 +115,7 @@ extension ProfileView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct RenameButton: View {
|
struct RenameButton: View {
|
||||||
@Binding private var modalType: ModalType?
|
@Binding private var modalType: ModalType?
|
||||||
|
@ -164,9 +166,11 @@ private extension ProfileView.MainMenu {
|
||||||
var mainView: some View {
|
var mainView: some View {
|
||||||
Menu {
|
Menu {
|
||||||
ProfileView.ReconnectButton()
|
ProfileView.ReconnectButton()
|
||||||
|
#if !os(tvOS)
|
||||||
ProfileView.ShortcutsButton(
|
ProfileView.ShortcutsButton(
|
||||||
modalType: $modalType
|
modalType: $modalType
|
||||||
)
|
)
|
||||||
|
#endif
|
||||||
Divider()
|
Divider()
|
||||||
ProfileView.RenameButton(
|
ProfileView.RenameButton(
|
||||||
modalType: $modalType
|
modalType: $modalType
|
||||||
|
@ -238,11 +242,13 @@ private extension ProfileView.MainMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
private extension ProfileView.ShortcutsButton {
|
private extension ProfileView.ShortcutsButton {
|
||||||
var isEligibleForSiri: Bool {
|
var isEligibleForSiri: Bool {
|
||||||
productManager.isEligible(forFeature: .siriShortcuts)
|
productManager.isEligible(forFeature: .siriShortcuts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
||||||
|
@ -260,6 +266,7 @@ private extension ProfileView.MainMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
private extension ProfileView.ShortcutsButton {
|
private extension ProfileView.ShortcutsButton {
|
||||||
func presentShortcutsOrPaywall() {
|
func presentShortcutsOrPaywall() {
|
||||||
|
|
||||||
|
@ -271,6 +278,7 @@ private extension ProfileView.ShortcutsButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private extension ProfileView.DuplicateButton {
|
private extension ProfileView.DuplicateButton {
|
||||||
func duplicateProfile(withId id: UUID) {
|
func duplicateProfile(withId id: UUID) {
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
//
|
||||||
|
// ProfileView+TV.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/22/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
import PassepartoutLibrary
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension ProfileView {
|
||||||
|
struct TVSection: View {
|
||||||
|
@ObservedObject private var profileManager: ProfileManager
|
||||||
|
|
||||||
|
@ObservedObject private var productManager: ProductManager
|
||||||
|
|
||||||
|
@ObservedObject private var currentProfile: ObservableProfile
|
||||||
|
|
||||||
|
@Binding private var isProfileShared: Bool
|
||||||
|
|
||||||
|
@Binding private var modalType: ModalType?
|
||||||
|
|
||||||
|
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||||
|
let profileManager: ProfileManager = .shared
|
||||||
|
|
||||||
|
self.profileManager = profileManager
|
||||||
|
productManager = .shared
|
||||||
|
self.currentProfile = currentProfile
|
||||||
|
_isProfileShared = Binding {
|
||||||
|
profileManager.isSharing(profile: currentProfile.value)
|
||||||
|
} set: {
|
||||||
|
profileManager.setSharing($0, profile: currentProfile.value)
|
||||||
|
}
|
||||||
|
_modalType = modalType
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Section {
|
||||||
|
Toggle(isOn: $isProfileShared) {
|
||||||
|
Label(shareText, systemImage: themeAppleTVImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eligibility: present paywall for full support for Apple TV
|
||||||
|
if !isEligibleForAppleTV {
|
||||||
|
Button(L10n.Paywall.title) {
|
||||||
|
modalType = .paywallAppleTV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} footer: {
|
||||||
|
Text(footerText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ProfileView.TVSection {
|
||||||
|
var isEligibleForAppleTV: Bool {
|
||||||
|
productManager.isEligible(forFeature: .appleTV)
|
||||||
|
}
|
||||||
|
|
||||||
|
var shareText: String {
|
||||||
|
var sentences: [String] = [Unlocalized.Other.appleTV]
|
||||||
|
if !isEligibleForAppleTV {
|
||||||
|
sentences.append(L10n.Profile.Items.TvSharing.Caption.limited(Constants.InApp.tvLimitedMinutes))
|
||||||
|
}
|
||||||
|
return sentences.joined(separator: " — ")
|
||||||
|
}
|
||||||
|
|
||||||
|
var footerText: String {
|
||||||
|
var sentences: [String] = [L10n.Profile.Sections.Tv.Footer.encryption]
|
||||||
|
if !isEligibleForAppleTV {
|
||||||
|
sentences.append(L10n.Profile.Sections.Tv.Footer.Restricted.p1(Constants.InApp.tvLimitedMinutes))
|
||||||
|
sentences.append(L10n.Profile.Sections.Tv.Footer.Restricted.p2)
|
||||||
|
}
|
||||||
|
return sentences.joined(separator: " ")
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,6 +73,7 @@ private extension ProfileView.VPNSection {
|
||||||
VPNToggle(
|
VPNToggle(
|
||||||
profile: profile,
|
profile: profile,
|
||||||
interactiveProfile: interactiveProfile,
|
interactiveProfile: interactiveProfile,
|
||||||
|
title: L10n.Global.Strings.enabled,
|
||||||
rateLimit: Constants.RateLimit.vpnToggle
|
rateLimit: Constants.RateLimit.vpnToggle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@ struct ProfileView: View {
|
||||||
enum ModalType: Int, Identifiable {
|
enum ModalType: Int, Identifiable {
|
||||||
case interactiveAccount
|
case interactiveAccount
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
case shortcuts
|
case shortcuts
|
||||||
|
#endif
|
||||||
|
|
||||||
case rename
|
case rename
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ struct ProfileView: View {
|
||||||
|
|
||||||
case paywallTrustedNetworks
|
case paywallTrustedNetworks
|
||||||
|
|
||||||
|
case paywallAppleTV
|
||||||
|
|
||||||
var id: Int {
|
var id: Int {
|
||||||
rawValue
|
rawValue
|
||||||
}
|
}
|
||||||
|
@ -104,6 +108,10 @@ private extension ProfileView {
|
||||||
currentProfile: currentProfile,
|
currentProfile: currentProfile,
|
||||||
modalType: $modalType
|
modalType: $modalType
|
||||||
)
|
)
|
||||||
|
TVSection(
|
||||||
|
currentProfile: currentProfile,
|
||||||
|
modalType: $modalType
|
||||||
|
)
|
||||||
ExtraSection(currentProfile: currentProfile)
|
ExtraSection(currentProfile: currentProfile)
|
||||||
Section {
|
Section {
|
||||||
DiagnosticsRow(currentProfile: currentProfile)
|
DiagnosticsRow(currentProfile: currentProfile)
|
||||||
|
@ -122,10 +130,12 @@ private extension ProfileView {
|
||||||
InteractiveConnectionView(profile: currentProfile.value)
|
InteractiveConnectionView(profile: currentProfile.value)
|
||||||
}.themeGlobal()
|
}.themeGlobal()
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
case .shortcuts:
|
case .shortcuts:
|
||||||
NavigationView {
|
NavigationView {
|
||||||
ShortcutsView(target: currentProfile.value)
|
ShortcutsView(target: currentProfile.value)
|
||||||
}.themeGlobal()
|
}.themeGlobal()
|
||||||
|
#endif
|
||||||
|
|
||||||
case .rename:
|
case .rename:
|
||||||
NavigationView {
|
NavigationView {
|
||||||
|
@ -155,6 +165,14 @@ private extension ProfileView {
|
||||||
feature: .trustedNetworks
|
feature: .trustedNetworks
|
||||||
)
|
)
|
||||||
}.themeGlobal()
|
}.themeGlobal()
|
||||||
|
|
||||||
|
case .paywallAppleTV:
|
||||||
|
NavigationView {
|
||||||
|
PaywallView(
|
||||||
|
modalType: $modalType,
|
||||||
|
feature: .appleTV
|
||||||
|
)
|
||||||
|
}.themeGlobal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,9 +168,11 @@ private extension ProviderLocationView {
|
||||||
ForEach(filteredLocations(for: category)) { location in
|
ForEach(filteredLocations(for: category)) { location in
|
||||||
if isEditable {
|
if isEditable {
|
||||||
locationRow(location)
|
locationRow(location)
|
||||||
|
#if !os(tvOS)
|
||||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||||
favoriteActions(location)
|
favoriteActions(location)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
locationRow(location)
|
locationRow(location)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import MessageUI
|
import MessageUI
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -88,3 +89,4 @@ struct ReportIssueView: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Intents
|
import Intents
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -162,3 +163,4 @@ private extension ShortcutsView.AddView {
|
||||||
pendingShortcut = shortcut
|
pendingShortcut = shortcut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
import Intents
|
import Intents
|
||||||
import PassepartoutLibrary
|
import PassepartoutLibrary
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
@ -176,3 +177,4 @@ private extension ShortcutsView {
|
||||||
modalType = .add(shortcut: shortcut)
|
modalType = .add(shortcut: shortcut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
//
|
||||||
|
// ActiveProfileView+TV.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/18/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
import PassepartoutLibrary
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ActiveProfileView: View {
|
||||||
|
@ObservedObject private var profileManager: ProfileManager
|
||||||
|
|
||||||
|
@ObservedObject private var vpnState: ObservableVPNState
|
||||||
|
|
||||||
|
init(profileManager: ProfileManager) {
|
||||||
|
self.profileManager = profileManager
|
||||||
|
vpnState = .shared
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Section {
|
||||||
|
let activeProfile = profileManager.activeProfile
|
||||||
|
nameView(for: activeProfile)
|
||||||
|
if let activeProfile {
|
||||||
|
toggleView(for: activeProfile)
|
||||||
|
vpnProtocolView(for: activeProfile)
|
||||||
|
statusView(for: activeProfile)
|
||||||
|
if let expirationDate = activeProfile.connectionExpirationDate {
|
||||||
|
expirationView(at: expirationDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let activeProfile = profileManager.activeProfile,
|
||||||
|
let server = activeProfile.providerServer(.shared) {
|
||||||
|
providerSection(with: server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ActiveProfileView {
|
||||||
|
func nameView(for profile: Profile?) -> some View {
|
||||||
|
NavigationLink {
|
||||||
|
ProfilesListView(profileManager: profileManager)
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Placeholders.profileName)
|
||||||
|
.withTrailingText(profile?.header.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func vpnProtocolView(for profile: Profile) -> some View {
|
||||||
|
Text(L10n.Global.Strings.protocol)
|
||||||
|
.withTrailingText(profile.currentVPNProtocol.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleView(for profile: Profile) -> some View {
|
||||||
|
VPNToggle(
|
||||||
|
profile: profile,
|
||||||
|
interactiveProfile: .constant(nil),
|
||||||
|
title: L10n.Profile.Items.ConnectionStatus.caption,
|
||||||
|
rateLimit: Constants.RateLimit.vpnToggle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusView(for activeProfile: Profile) -> some View {
|
||||||
|
HStack {
|
||||||
|
Text(Unlocalized.VPN.vpn)
|
||||||
|
Spacer()
|
||||||
|
if vpnState.isEnabled && activeProfile.isExpired {
|
||||||
|
Text(L10n.Global.Errors.tunnelExpired)
|
||||||
|
.themeSecondaryTextStyle()
|
||||||
|
} else {
|
||||||
|
VPNStatusText(isActiveProfile: true)
|
||||||
|
.themeSecondaryTextStyle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expirationView(at expirationDate: Date) -> some View {
|
||||||
|
Text(L10n.Profile.Items.ExpiresAt.caption)
|
||||||
|
.withTrailingText(expirationDate.timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerSection(with server: ProviderServer) -> some View {
|
||||||
|
Section {
|
||||||
|
Text(L10n.Global.Strings.name)
|
||||||
|
.withTrailingText(server.providerMetadata.fullName)
|
||||||
|
HStack {
|
||||||
|
Text(L10n.Provider.Location.title)
|
||||||
|
Spacer()
|
||||||
|
Label(server.localizedDescription(style: .country), image: themeAssetsCountryImage(server.countryCode))
|
||||||
|
.themeSecondaryTextStyle()
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text(L10n.Global.Strings.provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// MainView+TV.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/17/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MainView: View {
|
||||||
|
@State private var path = NavigationPath()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack(path: $path) {
|
||||||
|
OrganizerView()
|
||||||
|
}
|
||||||
|
.themeGlobal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
MainView()
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,163 @@
|
||||||
|
//
|
||||||
|
// OrganizerView+TV.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/17/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
import PassepartoutLibrary
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct OrganizerView: View {
|
||||||
|
@ObservedObject private var profileManager: ProfileManager
|
||||||
|
|
||||||
|
#if targetEnvironment(simulator)
|
||||||
|
@State private var didLoadMockProfiles = false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
init(profileManager: ProfileManager = .shared) {
|
||||||
|
self.profileManager = profileManager
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
ActiveProfileView(profileManager: profileManager)
|
||||||
|
aboutSection
|
||||||
|
}
|
||||||
|
.navigationTitle(Unlocalized.appName)
|
||||||
|
.themeTV()
|
||||||
|
.themeAnimation(on: profileManager.activeProfileId)
|
||||||
|
#if targetEnvironment(simulator)
|
||||||
|
.task {
|
||||||
|
await loadMockProfiles()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension OrganizerView {
|
||||||
|
var aboutSection: some View {
|
||||||
|
Section {
|
||||||
|
Text(L10n.Version.title)
|
||||||
|
.withTrailingText(Constants.Global.appVersionString)
|
||||||
|
} header: {
|
||||||
|
Text(L10n.About.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Mock
|
||||||
|
|
||||||
|
#if targetEnvironment(simulator)
|
||||||
|
import TunnelKitOpenVPN
|
||||||
|
import TunnelKitWireGuard
|
||||||
|
|
||||||
|
// poor man's preview:
|
||||||
|
//
|
||||||
|
// https://developer.apple.com/forums/thread/719078
|
||||||
|
|
||||||
|
private let mockHosts: [(String, VPNProtocolType)] = [
|
||||||
|
("My Profile", .wireGuard),
|
||||||
|
("Friend's House", .openVPN),
|
||||||
|
("At School", .wireGuard)
|
||||||
|
]
|
||||||
|
|
||||||
|
private let mockProviders: [ProviderName] = [
|
||||||
|
.hideme,
|
||||||
|
.pia,
|
||||||
|
.protonvpn
|
||||||
|
]
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private let mockRepository: ProfileRepository = {
|
||||||
|
let hostProfiles = mockHosts.map { name, vpnType in
|
||||||
|
let header = Profile.Header(name: name)
|
||||||
|
switch vpnType {
|
||||||
|
case .openVPN:
|
||||||
|
let ovpn = OpenVPN.ConfigurationBuilder()
|
||||||
|
return Profile(header, configuration: ovpn.build())
|
||||||
|
|
||||||
|
case .wireGuard:
|
||||||
|
let wg = WireGuard.ConfigurationBuilder()
|
||||||
|
return Profile(header, configuration: wg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let providerProfiles = mockProviders.map { providerName in
|
||||||
|
let manager = ProviderManager.shared
|
||||||
|
let metadata = manager.provider(withName: providerName)!
|
||||||
|
let header = Profile.Header(name: metadata.fullName, providerName: providerName)
|
||||||
|
var provider = Profile.Provider(providerName)
|
||||||
|
let vpnType: VPNProtocolType = .openVPN // isOpenVPN ? .openVPN : .wireGuard
|
||||||
|
var settings = Profile.Provider.Settings()
|
||||||
|
let anyServer = manager.anyDefaultServer(providerName, vpnProtocol: vpnType)
|
||||||
|
settings.serverId = anyServer?.id
|
||||||
|
settings.presetId = anyServer?.presetIds.first
|
||||||
|
settings.account = .init("hello", "world")
|
||||||
|
provider.vpnSettings[vpnType] = settings
|
||||||
|
return Profile(header, provider: provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
var profiles: [Profile] = []
|
||||||
|
profiles.append(contentsOf: hostProfiles)
|
||||||
|
profiles.append(contentsOf: providerProfiles)
|
||||||
|
|
||||||
|
let repo = MockProfileRepository()
|
||||||
|
try? repo.saveProfiles(profiles.map {
|
||||||
|
var copy = $0
|
||||||
|
copy.connectionExpirationDate = Date().addingTimeInterval(10.0)
|
||||||
|
return copy
|
||||||
|
})
|
||||||
|
return repo
|
||||||
|
}()
|
||||||
|
|
||||||
|
private extension OrganizerView {
|
||||||
|
func loadMockProfiles() async {
|
||||||
|
guard !didLoadMockProfiles else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
let providerManager: ProviderManager = .shared
|
||||||
|
try await providerManager.fetchProvidersIndexPublisher(priority: .bundle).async()
|
||||||
|
|
||||||
|
for name in mockProviders {
|
||||||
|
try? await providerManager.fetchProviderPublisher(withName: name, vpnProtocol: .openVPN, priority: .bundle).async()
|
||||||
|
}
|
||||||
|
|
||||||
|
profileManager.swapProfileRepository(mockRepository)
|
||||||
|
profileManager.activateProfile(mockRepository.allProfiles().first!.value)
|
||||||
|
|
||||||
|
didLoadMockProfiles = true
|
||||||
|
} catch {
|
||||||
|
ErrorHandler.shared.handle(AppError(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
NavigationStack {
|
||||||
|
OrganizerView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,113 @@
|
||||||
|
//
|
||||||
|
// ProfilesList+TV.swift
|
||||||
|
// Passepartout
|
||||||
|
//
|
||||||
|
// Created by Davide De Rosa on 12/18/23.
|
||||||
|
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
|
||||||
|
//
|
||||||
|
// https://github.com/passepartoutvpn
|
||||||
|
//
|
||||||
|
// This file is part of Passepartout.
|
||||||
|
//
|
||||||
|
// Passepartout is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Passepartout is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if os(tvOS)
|
||||||
|
import PassepartoutLibrary
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ProfilesListView: View {
|
||||||
|
@ObservedObject private var profileManager: ProfileManager
|
||||||
|
|
||||||
|
@Environment(\.presentationMode) private var presentationMode
|
||||||
|
|
||||||
|
@State private var profileIdPendingSelection: UUID?
|
||||||
|
|
||||||
|
@FocusState private var focusedProfileId: UUID?
|
||||||
|
|
||||||
|
init(profileManager: ProfileManager) {
|
||||||
|
self.profileManager = profileManager
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
Section {
|
||||||
|
Text(listHeader)
|
||||||
|
.font(.footnote)
|
||||||
|
.themeSecondaryTextStyle()
|
||||||
|
ForEach(profiles, content: profileRow)
|
||||||
|
.themeAnimation(on: profiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
focusedProfileId = profileManager.activeProfileId
|
||||||
|
}
|
||||||
|
.disabled(profileIdPendingSelection != nil)
|
||||||
|
.navigationTitle(Text(L10n.Global.Strings.profiles))
|
||||||
|
.themeTV()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension ProfilesListView {
|
||||||
|
var profiles: [Profile] {
|
||||||
|
profileManager.profiles.sorted()
|
||||||
|
}
|
||||||
|
|
||||||
|
var listHeader: String {
|
||||||
|
[
|
||||||
|
L10n.Organizer.Sections.Tv.ProfilesList.Header.p1,
|
||||||
|
L10n.Profile.Sections.Tv.Footer.encryption
|
||||||
|
]
|
||||||
|
.joined(separator: " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func profileRow(for profile: Profile) -> some View {
|
||||||
|
Button {
|
||||||
|
activateProfile(profile)
|
||||||
|
} label: {
|
||||||
|
HStack {
|
||||||
|
Text(profile.header.name)
|
||||||
|
Spacer()
|
||||||
|
if profile.header.id == profileIdPendingSelection {
|
||||||
|
ProgressView()
|
||||||
|
} else if profileManager.isActiveProfile(profile.header.id) {
|
||||||
|
themeCheckmarkImage.asSystemImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focused($focusedProfileId, equals: profile.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func activateProfile(_ profile: Profile) {
|
||||||
|
guard profile.id != profileManager.activeProfileId else {
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Task {
|
||||||
|
profileIdPendingSelection = profile.id
|
||||||
|
do {
|
||||||
|
try await profileManager.makeProfileReady(profile)
|
||||||
|
await VPNManager.shared.disable()
|
||||||
|
profileManager.activateProfile(profile)
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
} catch {
|
||||||
|
ErrorHandler.shared.handle(
|
||||||
|
title: L10n.Global.Strings.profiles,
|
||||||
|
message: AppError(error).localizedDescription
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -39,22 +39,25 @@ struct VPNToggle: View {
|
||||||
|
|
||||||
@Binding private var interactiveProfile: Profile?
|
@Binding private var interactiveProfile: Profile?
|
||||||
|
|
||||||
|
private let title: String
|
||||||
|
|
||||||
private let rateLimit: Int
|
private let rateLimit: Int
|
||||||
|
|
||||||
@State private var canToggle = true
|
@State private var canToggle = true
|
||||||
|
|
||||||
init(profile: Profile, interactiveProfile: Binding<Profile?>, rateLimit: Int) {
|
init(profile: Profile, interactiveProfile: Binding<Profile?>, title: String, rateLimit: Int) {
|
||||||
profileManager = .shared
|
profileManager = .shared
|
||||||
vpnManager = .shared
|
vpnManager = .shared
|
||||||
currentVPNState = .shared
|
currentVPNState = .shared
|
||||||
productManager = .shared
|
productManager = .shared
|
||||||
self.profile = profile
|
self.profile = profile
|
||||||
_interactiveProfile = interactiveProfile
|
_interactiveProfile = interactiveProfile
|
||||||
|
self.title = title
|
||||||
self.rateLimit = rateLimit
|
self.rateLimit = rateLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Toggle(L10n.Global.Strings.enabled, isOn: isEnabled)
|
Toggle(title, isOn: isEnabled)
|
||||||
.disabled(!canToggle)
|
.disabled(!canToggle)
|
||||||
.themeAnimation(on: currentVPNState.isEnabled)
|
.themeAnimation(on: currentVPNState.isEnabled)
|
||||||
}
|
}
|
||||||
|
@ -129,11 +132,13 @@ private extension VPNToggle {
|
||||||
|
|
||||||
pp_log.debug("Donating connection intents...")
|
pp_log.debug("Donating connection intents...")
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
IntentDispatcher.donateEnableVPN()
|
IntentDispatcher.donateEnableVPN()
|
||||||
IntentDispatcher.donateDisableVPN()
|
IntentDispatcher.donateDisableVPN()
|
||||||
IntentDispatcher.donateConnection(
|
IntentDispatcher.donateConnection(
|
||||||
with: profile,
|
with: profile,
|
||||||
providerManager: ProviderManager.shared
|
providerManager: ProviderManager.shared
|
||||||
)
|
)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,11 @@ extension View {
|
||||||
.truncationMode(truncationMode)
|
.truncationMode(truncationMode)
|
||||||
if copyOnTap {
|
if copyOnTap {
|
||||||
trailing
|
trailing
|
||||||
|
#if !os(tvOS)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
text.map(Utils.copyToPasteboard)
|
text.map(Utils.copyToPasteboard)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
trailing
|
trailing
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"global.strings.authentication" = "Authentifizierung";
|
"global.strings.authentication" = "Authentifizierung";
|
||||||
"global.messages.unlock_app" = "Passepartout ist gesperrt";
|
"global.messages.unlock_app" = "Passepartout ist gesperrt";
|
||||||
"global.messages.email_not_configured" = "Es wurde kein Email-Account konfiguriert.";
|
"global.messages.email_not_configured" = "Es wurde kein Email-Account konfiguriert.";
|
||||||
"global.messages.share" = "Passepartout ist ein Benutzerfreundlicher, Open Source OpenVPN / WireGuard client für iOS und macOS";
|
"global.messages.share" = "Passepartout ist ein Benutzerfreundlicher, Open Source OpenVPN / WireGuard client für iOS und macOS"; // FIXME: l10n, Apple platforms
|
||||||
|
|
||||||
"global.alerts.buttons.remind" = "Später erinnern";
|
"global.alerts.buttons.remind" = "Später erinnern";
|
||||||
"global.alerts.buttons.never" = "Nicht erneut fragen";
|
"global.alerts.buttons.never" = "Nicht erneut fragen";
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
"global.errors.missing_account" = "Fehlender Account";
|
"global.errors.missing_account" = "Fehlender Account";
|
||||||
"global.errors.missing_provider_server" = "Fehlender Standort";
|
"global.errors.missing_provider_server" = "Fehlender Standort";
|
||||||
"global.errors.missing_provider_preset" = "Fehlende Voreinstellung";
|
"global.errors.missing_provider_preset" = "Fehlende Voreinstellung";
|
||||||
|
"global.errors.tunnel_expired" = "Verbindung abgelaufen";
|
||||||
|
|
||||||
/* MARK: Menus */
|
/* MARK: Menus */
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
|
|
||||||
"organizer.sections.active" = "In Benutzung";
|
"organizer.sections.active" = "In Benutzung";
|
||||||
|
"organizer.sections.tv.profiles_list.header.p1" = "Öffne Passepartout auf deinem iOS- oder macOS-Gerät und aktiviere den „Apple TV“-Schalter eines Profils, damit es hier angezeigt wird.";
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
"organizer.empty.no_profiles" = "Keine Profile";
|
"organizer.empty.no_profiles" = "Keine Profile";
|
||||||
|
|
||||||
|
@ -163,6 +165,9 @@
|
||||||
"profile.sections.vpn.footer" = "Die Verbindung wird immer aufgebaut wenn notwendig.";
|
"profile.sections.vpn.footer" = "Die Verbindung wird immer aufgebaut wenn notwendig.";
|
||||||
"profile.sections.status.header" = "Verbindung";
|
"profile.sections.status.header" = "Verbindung";
|
||||||
"profile.sections.provider_infrastructure.footer" = "Zuletzt aktualisiert am %@.";
|
"profile.sections.provider_infrastructure.footer" = "Zuletzt aktualisiert am %@.";
|
||||||
|
"profile.sections.tv.footer.encryption" = "Profile sind verschlüsselt und werden deinem Apple TV über iCloud zur Verfügung gestellt.";
|
||||||
|
"profile.sections.tv.footer.restricted.p1" = "Die Verbindung läuft jedoch nach %d Minuten ab.";
|
||||||
|
"profile.sections.tv.footer.restricted.p2" = "Bei einem Kauf entfällt diese Beschränkung.";
|
||||||
"profile.sections.vpn_survives_sleep.footer" = "Deaktivieren um die Batterielaufzeit zu verbessern, allerdings verzögert sich der Verbindungsaufbau beim Aufwachen.";
|
"profile.sections.vpn_survives_sleep.footer" = "Deaktivieren um die Batterielaufzeit zu verbessern, allerdings verzögert sich der Verbindungsaufbau beim Aufwachen.";
|
||||||
"profile.sections.vpn_resolves_hostname.footer" = "Bevorzugt in den meisten Netzwerken und benötigt in manchen IPv6 Netzwerken. Deaktivieren wo DNS geblockt ist oder um die Aushandlung zu beschleunigen bei langsam antwortenden DNS.";
|
"profile.sections.vpn_resolves_hostname.footer" = "Bevorzugt in den meisten Netzwerken und benötigt in manchen IPv6 Netzwerken. Deaktivieren wo DNS geblockt ist oder um die Aushandlung zu beschleunigen bei langsam antwortenden DNS.";
|
||||||
"profile.sections.feedback.header" = "Feedback";
|
"profile.sections.feedback.header" = "Feedback";
|
||||||
|
@ -178,6 +183,8 @@
|
||||||
"profile.items.only_shows_favorites.caption" = "Nur favorisierte Standorte anzeigen";
|
"profile.items.only_shows_favorites.caption" = "Nur favorisierte Standorte anzeigen";
|
||||||
"profile.items.vpn_survives_sleep.caption" = "Verbindung aktiv halten trotz Schlafmodus";
|
"profile.items.vpn_survives_sleep.caption" = "Verbindung aktiv halten trotz Schlafmodus";
|
||||||
"profile.items.vpn_resolves_hostname.caption" = "Server Hostname auflösen";
|
"profile.items.vpn_resolves_hostname.caption" = "Server Hostname auflösen";
|
||||||
|
"profile.items.tv_sharing.caption.limited" = "Begrenzt auf %d Minuten";
|
||||||
|
"profile.items.expires_at.caption" = "Endet";
|
||||||
|
|
||||||
"profile.alerts.rename.title" = "Profil umbenennen";
|
"profile.alerts.rename.title" = "Profil umbenennen";
|
||||||
"profile.alerts.reconnect_vpn.message" = "Möchtest du erneut zum VPN verbinden?";
|
"profile.alerts.reconnect_vpn.message" = "Möchtest du erneut zum VPN verbinden?";
|
||||||
|
@ -323,6 +330,7 @@
|
||||||
"paywall.items.full_version.extra_description" = "Alle Anbieter (inklusive Zukünftige)\n%@";
|
"paywall.items.full_version.extra_description" = "Alle Anbieter (inklusive Zukünftige)\n%@";
|
||||||
"paywall.items.restore.title" = "Einkäufe wiederherstellen";
|
"paywall.items.restore.title" = "Einkäufe wiederherstellen";
|
||||||
"paywall.items.restore.description" = "Wenn Sie diese App oder Funktion in der Vergangenheit gekauft haben, können Sie Ihre Einkäufe wiederherstellen und dieser Bildschirm wird nicht mehr angezeigt.";
|
"paywall.items.restore.description" = "Wenn Sie diese App oder Funktion in der Vergangenheit gekauft haben, können Sie Ihre Einkäufe wiederherstellen und dieser Bildschirm wird nicht mehr angezeigt.";
|
||||||
|
"paywall.alerts.purchase.appletv.success.message" = "Vielen Dank! Das Zeitlimit entfällt, sobald iCloud auf dem neuesten Stand ist. Warte einen Moment und starte die Verbindung in der TV-App dann neu.";
|
||||||
|
|
||||||
/* MARK: DonateView */
|
/* MARK: DonateView */
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"global.strings.authentication" = "Αυθεντικοποίηση";
|
"global.strings.authentication" = "Αυθεντικοποίηση";
|
||||||
"global.messages.unlock_app" = "Το πασπαρτού είναι κλειδωμένο";
|
"global.messages.unlock_app" = "Το πασπαρτού είναι κλειδωμένο";
|
||||||
"global.messages.email_not_configured" = "Δεν έχει ρυθμιστεί λογαριασμός ηλεκτρονικού ταχυδρομείου.";
|
"global.messages.email_not_configured" = "Δεν έχει ρυθμιστεί λογαριασμός ηλεκτρονικού ταχυδρομείου.";
|
||||||
"global.messages.share" = "Το Passepartout είναι φιλικό προς το χρήστη, ανοιχτού κώδικα OpenVPN / WireGuard πρόγραμμα για iOS και macOS";
|
"global.messages.share" = "Το Passepartout είναι φιλικό προς το χρήστη, ανοιχτού κώδικα OpenVPN / WireGuard πρόγραμμα για iOS και macOS"; // FIXME: l10n, Apple platforms
|
||||||
|
|
||||||
"global.alerts.buttons.remind" = "Υπενθύμιση Αργότερα";
|
"global.alerts.buttons.remind" = "Υπενθύμιση Αργότερα";
|
||||||
"global.alerts.buttons.never" = "Μη με ρωτήσεις ξανά";
|
"global.alerts.buttons.never" = "Μη με ρωτήσεις ξανά";
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
"global.errors.missing_account" = "Λείπει λογαριασμός";
|
"global.errors.missing_account" = "Λείπει λογαριασμός";
|
||||||
"global.errors.missing_provider_server" = "Λείπει η τοποθεσία";
|
"global.errors.missing_provider_server" = "Λείπει η τοποθεσία";
|
||||||
"global.errors.missing_provider_preset" = "Λείπει προεπιλογή";
|
"global.errors.missing_provider_preset" = "Λείπει προεπιλογή";
|
||||||
|
"global.errors.tunnel_expired" = "H σύνδεση έληξε";
|
||||||
|
|
||||||
/* MARK: Menus */
|
/* MARK: Menus */
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
|
|
||||||
"organizer.sections.active" = "Σε χρήση";
|
"organizer.sections.active" = "Σε χρήση";
|
||||||
|
"organizer.sections.tv.profiles_list.header.p1" = "Ανοίξτε το Passepartout στη συσκευή σας iOS ή macOS και ενεργοποιήστε την εναλλαγή \"Apple TV\" ενός προφίλ για να εμφανιστεί εδώ.";
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
"organizer.empty.no_profiles" = "Δεν υπάρχουν προφίλ";
|
"organizer.empty.no_profiles" = "Δεν υπάρχουν προφίλ";
|
||||||
|
|
||||||
|
@ -163,6 +165,9 @@
|
||||||
"profile.sections.vpn.footer" = "Η σύνδεση θα πραγματοποιηθεί όποτε είναι απαραίτητο.";
|
"profile.sections.vpn.footer" = "Η σύνδεση θα πραγματοποιηθεί όποτε είναι απαραίτητο.";
|
||||||
"profile.sections.status.header" = "Σύνδεση";
|
"profile.sections.status.header" = "Σύνδεση";
|
||||||
"profile.sections.provider_infrastructure.footer" = "Τελευταία ενημέρωση στις %@.";
|
"profile.sections.provider_infrastructure.footer" = "Τελευταία ενημέρωση στις %@.";
|
||||||
|
"profile.sections.tv.footer.encryption" = "Τα προφίλ κρυπτογραφούνται και διατίθενται στο Apple TV σας μέσω iCloud.";
|
||||||
|
"profile.sections.tv.footer.restricted.p1" = "Ωστόσο, η σύνδεση θα λήξει μετά από %d λεπτά.";
|
||||||
|
"profile.sections.tv.footer.restricted.p2" = "Αγορά για την κατάργηση του περιορισμού.";
|
||||||
"profile.sections.vpn_survives_sleep.footer" = "Απενεργοποιήστε για να βελτιώσετε τη χρήση της μπαταρίας, εις βάρος των περιστασιακών επιβραδύνσεων που οφείλονται σε επανασύνδεση αφύπνισης.";
|
"profile.sections.vpn_survives_sleep.footer" = "Απενεργοποιήστε για να βελτιώσετε τη χρήση της μπαταρίας, εις βάρος των περιστασιακών επιβραδύνσεων που οφείλονται σε επανασύνδεση αφύπνισης.";
|
||||||
"profile.sections.vpn_resolves_hostname.footer" = "Προτιμάται στα περισσότερα δίκτυα και απαιτείται σε ορισμένα δίκτυα IPv6. Απενεργοποιήστε το εκεί που μπλοκάρεται το DNS ή για να επιταχύνετε τη επικοινωνία όταν το DNS είναι αργό για να ανταποκριθεί.";
|
"profile.sections.vpn_resolves_hostname.footer" = "Προτιμάται στα περισσότερα δίκτυα και απαιτείται σε ορισμένα δίκτυα IPv6. Απενεργοποιήστε το εκεί που μπλοκάρεται το DNS ή για να επιταχύνετε τη επικοινωνία όταν το DNS είναι αργό για να ανταποκριθεί.";
|
||||||
"profile.sections.feedback.header" = "Ανατροφοδότηση";
|
"profile.sections.feedback.header" = "Ανατροφοδότηση";
|
||||||
|
@ -178,6 +183,8 @@
|
||||||
"profile.items.only_shows_favorites.caption" = "Προβολή αγαπημένων τοποθεσιών μόνο";
|
"profile.items.only_shows_favorites.caption" = "Προβολή αγαπημένων τοποθεσιών μόνο";
|
||||||
"profile.items.vpn_survives_sleep.caption" = "Κρατήστε ζωντανό στον ύπνο";
|
"profile.items.vpn_survives_sleep.caption" = "Κρατήστε ζωντανό στον ύπνο";
|
||||||
"profile.items.vpn_resolves_hostname.caption" = "Επίλυση του ονόματος σέρβερ διακομιστή";
|
"profile.items.vpn_resolves_hostname.caption" = "Επίλυση του ονόματος σέρβερ διακομιστή";
|
||||||
|
"profile.items.tv_sharing.caption.limited" = "Περιορίστηκε σε %d λεπτά";
|
||||||
|
"profile.items.expires_at.caption" = "Λήξη";
|
||||||
|
|
||||||
"profile.alerts.rename.title" = "Μετονομασία προφίλ";
|
"profile.alerts.rename.title" = "Μετονομασία προφίλ";
|
||||||
"profile.alerts.reconnect_vpn.message" = "Θέλετε να συνδεθείτε ξανά με το VPN;";
|
"profile.alerts.reconnect_vpn.message" = "Θέλετε να συνδεθείτε ξανά με το VPN;";
|
||||||
|
@ -323,6 +330,7 @@
|
||||||
"paywall.items.full_version.extra_description" = "Όλοι οι πάροχοι (περιλαμβάνονται και οι μελλοντικοί)\n%@";
|
"paywall.items.full_version.extra_description" = "Όλοι οι πάροχοι (περιλαμβάνονται και οι μελλοντικοί)\n%@";
|
||||||
"paywall.items.restore.title" = "Επαναφορά Αγορών";
|
"paywall.items.restore.title" = "Επαναφορά Αγορών";
|
||||||
"paywall.items.restore.description" = "Εαν αγοράσατε την εφαρμογή στο παρελθόν, μπορείτε να κάνετε επαναφορά αγορών και αυτή η οθόνη δε θα εμφανιστεί ξανά.";
|
"paywall.items.restore.description" = "Εαν αγοράσατε την εφαρμογή στο παρελθόν, μπορείτε να κάνετε επαναφορά αγορών και αυτή η οθόνη δε θα εμφανιστεί ξανά.";
|
||||||
|
"paywall.alerts.purchase.appletv.success.message" = "Σας ευχαριστούμε! Το χρονικό όριο θα αφαιρεθεί μόλις ενημερωθεί το iCloud. Περιμένετε μερικά λεπτά και μετά επανεκκινήστε τη σύνδεση στην εφαρμογή TV.";
|
||||||
|
|
||||||
/* MARK: DonateView */
|
/* MARK: DonateView */
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"global.strings.authentication" = "Authentication";
|
"global.strings.authentication" = "Authentication";
|
||||||
"global.messages.unlock_app" = "Passepartout is locked";
|
"global.messages.unlock_app" = "Passepartout is locked";
|
||||||
"global.messages.email_not_configured" = "No e-mail account is configured.";
|
"global.messages.email_not_configured" = "No e-mail account is configured.";
|
||||||
"global.messages.share" = "Passepartout is a user-friendly, open source OpenVPN / WireGuard client for iOS and macOS";
|
"global.messages.share" = "Passepartout is a user-friendly, open source OpenVPN / WireGuard client for iOS and macOS"; // FIXME: l10n, Apple platforms
|
||||||
|
|
||||||
"global.alerts.buttons.remind" = "Remind me later";
|
"global.alerts.buttons.remind" = "Remind me later";
|
||||||
"global.alerts.buttons.never" = "Don't ask again";
|
"global.alerts.buttons.never" = "Don't ask again";
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
"global.errors.missing_account" = "Missing account";
|
"global.errors.missing_account" = "Missing account";
|
||||||
"global.errors.missing_provider_server" = "Missing location";
|
"global.errors.missing_provider_server" = "Missing location";
|
||||||
"global.errors.missing_provider_preset" = "Missing preset";
|
"global.errors.missing_provider_preset" = "Missing preset";
|
||||||
|
"global.errors.tunnel_expired" = "Connection expired";
|
||||||
|
|
||||||
/* MARK: Menus */
|
/* MARK: Menus */
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
|
|
||||||
"organizer.sections.active" = "In use";
|
"organizer.sections.active" = "In use";
|
||||||
|
"organizer.sections.tv.profiles_list.header.p1" = "Open Passepartout on your iOS or macOS device and enable the \"Apple TV\" toggle of a profile to make it appear here.";
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
"organizer.empty.no_profiles" = "No profiles";
|
"organizer.empty.no_profiles" = "No profiles";
|
||||||
|
|
||||||
|
@ -163,6 +165,9 @@
|
||||||
"profile.sections.vpn.footer" = "The connection will be established whenever necessary.";
|
"profile.sections.vpn.footer" = "The connection will be established whenever necessary.";
|
||||||
"profile.sections.status.header" = "Connection";
|
"profile.sections.status.header" = "Connection";
|
||||||
"profile.sections.provider_infrastructure.footer" = "Last updated on %@.";
|
"profile.sections.provider_infrastructure.footer" = "Last updated on %@.";
|
||||||
|
"profile.sections.tv.footer.encryption" = "Profiles are encrypted and made available to your Apple TV via iCloud.";
|
||||||
|
"profile.sections.tv.footer.restricted.p1" = "However, the connection will expire after %d minutes.";
|
||||||
|
"profile.sections.tv.footer.restricted.p2" = "Purchase to drop the restriction.";
|
||||||
"profile.sections.vpn_survives_sleep.footer" = "Disable to improve battery usage, at the expense of occasional slowdowns due to wake-up reconnections.";
|
"profile.sections.vpn_survives_sleep.footer" = "Disable to improve battery usage, at the expense of occasional slowdowns due to wake-up reconnections.";
|
||||||
"profile.sections.vpn_resolves_hostname.footer" = "Preferred in most networks and required in some IPv6 networks. Disable where DNS is blocked, or to speed up negotiation when DNS is slow to respond.";
|
"profile.sections.vpn_resolves_hostname.footer" = "Preferred in most networks and required in some IPv6 networks. Disable where DNS is blocked, or to speed up negotiation when DNS is slow to respond.";
|
||||||
"profile.sections.feedback.header" = "Feedback";
|
"profile.sections.feedback.header" = "Feedback";
|
||||||
|
@ -178,6 +183,8 @@
|
||||||
"profile.items.only_shows_favorites.caption" = "Only show favorite locations";
|
"profile.items.only_shows_favorites.caption" = "Only show favorite locations";
|
||||||
"profile.items.vpn_survives_sleep.caption" = "Keep alive on sleep";
|
"profile.items.vpn_survives_sleep.caption" = "Keep alive on sleep";
|
||||||
"profile.items.vpn_resolves_hostname.caption" = "Resolve provider hostname";
|
"profile.items.vpn_resolves_hostname.caption" = "Resolve provider hostname";
|
||||||
|
"profile.items.tv_sharing.caption.limited" = "Limited to %d minutes";
|
||||||
|
"profile.items.expires_at.caption" = "Expiration";
|
||||||
|
|
||||||
"profile.alerts.rename.title" = "Rename profile";
|
"profile.alerts.rename.title" = "Rename profile";
|
||||||
"profile.alerts.reconnect_vpn.message" = "Do you want to reconnect to the VPN?";
|
"profile.alerts.reconnect_vpn.message" = "Do you want to reconnect to the VPN?";
|
||||||
|
@ -323,6 +330,7 @@
|
||||||
"paywall.items.full_version.extra_description" = "All providers (including future ones)\n%@";
|
"paywall.items.full_version.extra_description" = "All providers (including future ones)\n%@";
|
||||||
"paywall.items.restore.title" = "Restore purchases";
|
"paywall.items.restore.title" = "Restore purchases";
|
||||||
"paywall.items.restore.description" = "If you bought this app or feature in the past, you can restore your purchases and this screen won't show again.";
|
"paywall.items.restore.description" = "If you bought this app or feature in the past, you can restore your purchases and this screen won't show again.";
|
||||||
|
"paywall.alerts.purchase.appletv.success.message" = "Thank you! The time limit will be dropped as soon as iCloud catches up. Wait a few moments, then restart the connection on the TV app.";
|
||||||
|
|
||||||
/* MARK: DonateView */
|
/* MARK: DonateView */
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
"global.strings.authentication" = "Autenticación";
|
"global.strings.authentication" = "Autenticación";
|
||||||
"global.messages.unlock_app" = "Passepartout está bloqueada";
|
"global.messages.unlock_app" = "Passepartout está bloqueada";
|
||||||
"global.messages.email_not_configured" = "Ningún e-mail configurado.";
|
"global.messages.email_not_configured" = "Ningún e-mail configurado.";
|
||||||
"global.messages.share" = "Passepartout es un cliente OpenVPN / WireGuard intuitivo, de código abierto para iOS y macOS";
|
"global.messages.share" = "Passepartout es un cliente OpenVPN / WireGuard intuitivo, de código abierto para iOS y macOS"; // FIXME: l10n, Apple platforms
|
||||||
|
|
||||||
"global.alerts.buttons.remind" = "Recordar más tarde";
|
"global.alerts.buttons.remind" = "Recordar más tarde";
|
||||||
"global.alerts.buttons.never" = "No preguntar más";
|
"global.alerts.buttons.never" = "No preguntar más";
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
"global.errors.missing_account" = "Sin cuenta";
|
"global.errors.missing_account" = "Sin cuenta";
|
||||||
"global.errors.missing_provider_server" = "Sin ubicación";
|
"global.errors.missing_provider_server" = "Sin ubicación";
|
||||||
"global.errors.missing_provider_preset" = "Sin ajuste";
|
"global.errors.missing_provider_preset" = "Sin ajuste";
|
||||||
|
"global.errors.tunnel_expired" = "Conexión caducada";
|
||||||
|
|
||||||
/* MARK: Menus */
|
/* MARK: Menus */
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
|
|
||||||
"organizer.sections.active" = "En uso";
|
"organizer.sections.active" = "En uso";
|
||||||
|
"organizer.sections.tv.profiles_list.header.p1" = "Abre Passepartout desde tu dispositivo iOS o macOS y habilita el switch \"Apple TV\" de un perfil para que aparezca aquí abajo.";
|
||||||
/* MARK: OrganizerView */
|
/* MARK: OrganizerView */
|
||||||
"organizer.empty.no_profiles" = "Ningún perfil";
|
"organizer.empty.no_profiles" = "Ningún perfil";
|
||||||
|
|
||||||
|
@ -163,6 +165,9 @@
|
||||||
"profile.sections.vpn.footer" = "La conexión se establecerá siempre y cuando sea necesario.";
|
"profile.sections.vpn.footer" = "La conexión se establecerá siempre y cuando sea necesario.";
|
||||||
"profile.sections.status.header" = "Conexión";
|
"profile.sections.status.header" = "Conexión";
|
||||||
"profile.sections.provider_infrastructure.footer" = "Última actualización: %@.";
|
"profile.sections.provider_infrastructure.footer" = "Última actualización: %@.";
|
||||||
|
"profile.sections.tv.footer.encryption" = "Los perfiles están encriptados y puestos a disposición para tu Apple TV a través de iCloud.";
|
||||||
|
"profile.sections.tv.footer.restricted.p1" = "Sin embargo, la conexión caducará en %d minutos.";
|
||||||
|
"profile.sections.tv.footer.restricted.p2" = "Comprar para eliminar la restricción.";
|
||||||
"profile.sections.vpn_survives_sleep.footer" = "Deshabilitar para mejorar el uso de la batería, a costa de ralentizaciones ocasionales por las reconexiones al despertar el dispositivo.";
|
"profile.sections.vpn_survives_sleep.footer" = "Deshabilitar para mejorar el uso de la batería, a costa de ralentizaciones ocasionales por las reconexiones al despertar el dispositivo.";
|
||||||
"profile.sections.vpn_resolves_hostname.footer" = "Preferido en la mayoría de las redes y necesario en algunas redes IPv6. Deshabilitar donde el DNS esté bloqueado, o para acelerar la negociación cuando el DNS sea lento en responder.";
|
"profile.sections.vpn_resolves_hostname.footer" = "Preferido en la mayoría de las redes y necesario en algunas redes IPv6. Deshabilitar donde el DNS esté bloqueado, o para acelerar la negociación cuando el DNS sea lento en responder.";
|
||||||
"profile.sections.feedback.header" = "Feedback";
|
"profile.sections.feedback.header" = "Feedback";
|
||||||
|
@ -178,6 +183,8 @@
|
||||||
"profile.items.only_shows_favorites.caption" = "Mostrar solo ubicaciones favoritas";
|
"profile.items.only_shows_favorites.caption" = "Mostrar solo ubicaciones favoritas";
|
||||||
"profile.items.vpn_survives_sleep.caption" = "Mantener en modo inactivo";
|
"profile.items.vpn_survives_sleep.caption" = "Mantener en modo inactivo";
|
||||||
"profile.items.vpn_resolves_hostname.caption" = "Resolver hostname del servidor";
|
"profile.items.vpn_resolves_hostname.caption" = "Resolver hostname del servidor";
|
||||||
|
"profile.items.tv_sharing.caption.limited" = "Limitado a %d minutos";
|
||||||
|
"profile.items.expires_at.caption" = "Caducidad";
|
||||||
|
|
||||||
"profile.alerts.rename.title" = "Renombrar perfil";
|
"profile.alerts.rename.title" = "Renombrar perfil";
|
||||||
"profile.alerts.reconnect_vpn.message" = "Quieres reconectarte al VPN?";
|
"profile.alerts.reconnect_vpn.message" = "Quieres reconectarte al VPN?";
|
||||||
|
@ -323,6 +330,7 @@
|
||||||
"paywall.items.full_version.extra_description" = "Todos los proveedores (incluye los futuros)\n%@";
|
"paywall.items.full_version.extra_description" = "Todos los proveedores (incluye los futuros)\n%@";
|
||||||
"paywall.items.restore.title" = "Restaurar compras";
|
"paywall.items.restore.title" = "Restaurar compras";
|
||||||
"paywall.items.restore.description" = "Si compraste esta aplicación o funcionalidad anteriormente, puedes restaurar tus compras y esta pantalla no volverá a aparecer.";
|
"paywall.items.restore.description" = "Si compraste esta aplicación o funcionalidad anteriormente, puedes restaurar tus compras y esta pantalla no volverá a aparecer.";
|
||||||
|
"paywall.alerts.purchase.appletv.success.message" = "Gracias! El limite de tiempo será eliminado en cuanto iCloud se sincronice. Espera unos momentos, y reinicia la conexión en la app de la TV.";
|
||||||
|
|
||||||
/* MARK: DonateView */
|
/* MARK: DonateView */
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
|
Passepartout is a bare VPN client and, as such, does not store nor forward any personal data. Therefore, you should get in touch with your VPN service provider to learn about its data retention policy.
|
||||||
|
|
||||||
|
Passepartout may access GitHub repositories on request. Please refer to GitHub privacy statement for any information about data retention when accessing their website.
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
### Fixed
|
### Added
|
||||||
|
|
||||||
- Persisted profile is overwritten with its former value.
|
- WireGuard: Show data count.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade OpenSSL to 3.2.0.
|
||||||
|
- Encrypt profiles stored to iCloud.
|
||||||
|
|
||||||
|
|