diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 000000000..cf980c02f --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,49 @@ +name: pia_vpn_ios +on: + pull_request: + workflow_dispatch: +concurrency: + group: "${{ github.ref }}" + cancel-in-progress: true +jobs: + build: + runs-on: macos-13 + env: + TEST_RUNNER_PIA_TEST_USER: ${{ secrets.PIA_ACCOUNT_USERNAME}} + TEST_RUNNER_PIA_TEST_PASSWORD: ${{ secrets.PIA_ACCOUNT_PASSWORD }} + + steps: + - name: Setup Git credentials + run: | + git config --global url."https://${{ secrets.ORG_GITHUB_USERNAME }}:${{ secrets.ORG_GITHUB_TOKEN }}@github.com/".insteadOf "git@github.com:" + + - uses: actions/checkout@v3 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + + - name: Install Fastlane + run: gem install fastlane + + - name: Set credentials in fastlane env + run: echo "TEST_RUNNER_PIA_TEST_USER=${{ secrets.PIA_ACCOUNT_USERNAME}}"\n"TEST_RUNNER_PIA_TEST_PASSWORD=${{ secrets.PIA_ACCOUNT_PASSWORD }}" > fastlane/.env + + - name: Check fastlane env + run: cat fastlane/.env + + - name: Select XCode version + run: sudo xcode-select -s /Applications/Xcode_15.0.app + + - name: Install dependencies + run: swift package resolve + + - name: Run e2e tests with fastlane + run: bundle exec fastlane e2e_tests + continue-on-error: true + + - name: Run tests + run: bundle exec fastlane tests + + \ No newline at end of file diff --git a/.github/workflows/testflight_deploy.yml b/.github/workflows/testflight_deploy.yml new file mode 100644 index 000000000..f95a5d290 --- /dev/null +++ b/.github/workflows/testflight_deploy.yml @@ -0,0 +1,48 @@ +name: testflight_deploy +on: + push: + branches: + - master + + workflow_dispatch: +concurrency: + group: "${{ github.ref }}" + cancel-in-progress: true +jobs: + build: + runs-on: macos-latest + env: + CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} + KEYCHAIN_NAME: ${{ secrets.KEYCHAIN_NAME }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }} + + steps: + - name: Setup Git credentials + run: | + git config --global url."https://${{ secrets.ORG_GITHUB_USERNAME }}:${{ secrets.ORG_GITHUB_TOKEN }}@github.com/".insteadOf "git@github.com:" + + - uses: actions/checkout@v3 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + + - name: Install Fastlane + run: gem install fastlane + + - name: Decode Certificates + run: echo "${{ secrets.IOS_CERTIFICATE }}" | base64 --decode > ./fastlane/Certificate.p12 + + - name: Run tests + run: bundle exec fastlane tests + + - name: Set up certificates and profiles + run: bundle exec fastlane get_profiles > /dev/null 2>&1 + + - name: Upload version to TestFlight + run: bundle exec fastlane testflight_build + \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..7a118b49b --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/PIA VPN.xcodeproj/project.pbxproj b/PIA VPN.xcodeproj/project.pbxproj index 622eb63a9..33551baed 100644 --- a/PIA VPN.xcodeproj/project.pbxproj +++ b/PIA VPN.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -145,15 +145,42 @@ 3545E98226AADB2B00B812CC /* ServerSelectingTileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3545E98126AADB2B00B812CC /* ServerSelectingTileCell.swift */; }; 3545E98326AADC7C00B812CC /* ServerSelectingTileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3545E98126AADB2B00B812CC /* ServerSelectingTileCell.swift */; }; 3545E98426AADC7E00B812CC /* ServerSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3545E97F26AAD60C00B812CC /* ServerSelectionDelegate.swift */; }; - 69446CB32AA7502E0080F446 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69446CB22AA7502E0080F446 /* PIALibrary */; }; - 69446CB52AA7503A0080F446 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69446CB42AA7503A0080F446 /* PIALibrary */; }; - 69446CB72AA750440080F446 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69446CB62AA750440080F446 /* PIALibrary */; }; - 69446CB92AA7504B0080F446 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69446CB82AA7504B0080F446 /* PIALibrary */; }; - 7EB8D11F27CE2B020030B060 /* PIAUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EB8D11E27CE2B020030B060 /* PIAUITests.swift */; }; - 7EB8D12127CE2B5D0030B060 /* PIALaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EB8D12027CE2B5D0030B060 /* PIALaunchTests.swift */; }; - 7EB8D12327CE7D4C0030B060 /* PIALoginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EB8D12227CE7D4C0030B060 /* PIALoginTests.swift */; }; - 7EC2972F27D8B8580061C56A /* CredentialsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EC2972D27D8B8580061C56A /* CredentialsUtil.swift */; }; - 7EC2973027D8B8580061C56A /* Credentials.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7EC2972E27D8B8580061C56A /* Credentials.plist */; }; + 35950B312ADD2996006F3CD9 /* Quick in Frameworks */ = {isa = PBXBuildFile; productRef = 35950B302ADD2996006F3CD9 /* Quick */; }; + 35950B342ADD2EE5006F3CD9 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = 35950B332ADD2EE5006F3CD9 /* Nimble */; }; + 35EDD6282ADE5D31007B9ACB /* BaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6272ADE5D31007B9ACB /* BaseTest.swift */; }; + 35EDD62A2ADE5F08007B9ACB /* SignInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */; }; + 35EDD6332ADE7281007B9ACB /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */; }; + 35EDD6352ADE7424007B9ACB /* VPNPermissionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6342ADE7424007B9ACB /* VPNPermissionScreen.swift */; }; + 35EDD6372ADE761A007B9ACB /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6362ADE761A007B9ACB /* HomeScreen.swift */; }; + 35EDD63B2AE62D15007B9ACB /* ElementHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD63A2AE62D15007B9ACB /* ElementHelper.swift */; }; + 35EDD63E2AE76A3B007B9ACB /* WaitHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD63D2AE76A3B007B9ACB /* WaitHelper.swift */; }; + 35EDD6422AE7A83D007B9ACB /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6412AE7A83D007B9ACB /* WelcomeScreen.swift */; }; + 35EDD6442AE7B480007B9ACB /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6432AE7B480007B9ACB /* Common.swift */; }; + 69196F4F2AF901B6008FDD43 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69196F4E2AF901B6008FDD43 /* PIALibrary */; }; + 69196F512AF901DE008FDD43 /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 69196F502AF901DE008FDD43 /* PIALibrary */; }; + 6924831A2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */; }; + 6924831B2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */; }; + 6924831C2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */; }; + 6924831E2AB04FFD002A0407 /* PIAWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6924831D2AB04FFD002A0407 /* PIAWidgetBundle.swift */; }; + 692483202AB05F18002A0407 /* PIAConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6924831F2AB05F18002A0407 /* PIAConnectionView.swift */; }; + 692483222AB05F37002A0407 /* PIACircleIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483212AB05F37002A0407 /* PIACircleIcon.swift */; }; + 692483262AB05F85002A0407 /* PIAConnectionActivityWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483252AB05F85002A0407 /* PIAConnectionActivityWidget.swift */; }; + 695A17412AF8FC7A005542AC /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 695A17402AF8FC7A005542AC /* PIALibrary */; }; + 695A17432AF8FCAA005542AC /* PIALibrary in Frameworks */ = {isa = PBXBuildFile; productRef = 695A17422AF8FCAA005542AC /* PIALibrary */; }; + 695BF81D2AC30EFB00D1139C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E7EC043209326E30029811E /* Localizable.strings */; }; + 695BF81F2AC410E000D1139C /* SwiftGen+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2215C820084CD700F5FB4D /* SwiftGen+Strings.swift */; }; + 698F4F2B2AB8A2080010B2B0 /* PIAWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 8269A6D5251CB5E0000B4DBF /* PIAWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 698F4F2D2AB978BF0010B2B0 /* PIACircleImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698F4F2C2AB978BF0010B2B0 /* PIACircleImageView.swift */; }; + 698F4F2E2AB97BAD0010B2B0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 291C6397183EBC210039EC03 /* Images.xcassets */; }; + 698F4F302ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698F4F2F2ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift */; }; + 698F4F312ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698F4F2F2ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift */; }; + 698F4F322ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698F4F2F2ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift */; }; + 69B70AB52ACBF51C0072A09D /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B70AB42ACBF51C0072A09D /* LoginScreen.swift */; }; + 69B70ABC2ACBF8300072A09D /* CredentialsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EC2972D27D8B8580061C56A /* CredentialsUtil.swift */; }; + 69B70ABE2ACC2CFE0072A09D /* AccessibilityId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B70ABD2ACC2CFE0072A09D /* AccessibilityId.swift */; }; + 69B70ABF2ACC2CFE0072A09D /* AccessibilityId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B70ABD2ACC2CFE0072A09D /* AccessibilityId.swift */; }; + 69B70AC02ACC2CFE0072A09D /* AccessibilityId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69B70ABD2ACC2CFE0072A09D /* AccessibilityId.swift */; }; + 69C587FD2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C587FC2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift */; }; 7ECBB8DD27B6C4F500C0C774 /* UserSurveyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ECBB8DC27B6C4F500C0C774 /* UserSurveyManager.swift */; }; 7ECBB8DE27BA5FCE00C0C774 /* UserSurveyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ECBB8DC27B6C4F500C0C774 /* UserSurveyManager.swift */; }; 821674F12678A1BE0028E4FD /* SettingsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821674F02678A1BE0028E4FD /* SettingsDelegate.swift */; }; @@ -254,7 +281,6 @@ 82CAB87B255AEA3500BB08EF /* MessagesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB879255AEA3500BB08EF /* MessagesManager.swift */; }; 82CAB8B0255B050000BB08EF /* MessagesCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8AF255B050000BB08EF /* MessagesCommands.swift */; }; 82CAB8B1255B050000BB08EF /* MessagesCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8AF255B050000BB08EF /* MessagesCommands.swift */; }; - 82CAB8DA255BEC7000BB08EF /* PIACommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8D9255BEC7000BB08EF /* PIACommandTests.swift */; }; 82CAB8E8255C0CB000BB08EF /* MessagesTile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8E7255C0CB000BB08EF /* MessagesTile.swift */; }; 82CAB8E9255C0CB000BB08EF /* MessagesTile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8E7255C0CB000BB08EF /* MessagesTile.swift */; }; 82CAB8F2255C0CD100BB08EF /* MessagesTileCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAB8F0255C0CD100BB08EF /* MessagesTileCollectionViewCell.swift */; }; @@ -464,7 +490,7 @@ remoteGlobalIDString = 0EFB606F203D7A2C0095398C; remoteInfo = "PIA VPN AdBlocker"; }; - 7EC2973127D8BCB60061C56A /* PBXContainerItemProxy */ = { + 69B70AB62ACBF51C0072A09D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 291C6374183EBC210039EC03 /* Project object */; proxyType = 1; @@ -532,6 +558,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 698F4F2B2AB8A2080010B2B0 /* PIAWidgetExtension.appex in Embed App Extensions */, DD1AB0E923F2993600396E74 /* PIA VPN WG Tunnel.appex in Embed App Extensions */, 0EFB6079203D7A2C0095398C /* PIA VPN AdBlocker.appex in Embed App Extensions */, 0EE220741F4EF307002805AE /* PIA VPN Tunnel.appex in Embed App Extensions */, @@ -550,9 +577,9 @@ 0E257AC41DA45D2F0000D3C3 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 0E325DA62093277F0020BEDB /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/Main.storyboard; sourceTree = ""; }; 0E392DA51FE3283C0002160D /* TransientState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransientState.swift; sourceTree = ""; }; - 0E3A35271FD9A960000B0F99 /* DashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewController.swift; sourceTree = ""; }; + 0E3A35271FD9A960000B0F99 /* DashboardViewController.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = DashboardViewController.swift; sourceTree = ""; tabWidth = 4; }; 0E3A352B1FD9CDC5000B0F99 /* Theme+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+App.swift"; sourceTree = ""; }; - 0E3A35341FD9EBDA000B0F99 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0E3A35341FD9EBDA000B0F99 /* AppDelegate.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; tabWidth = 4; }; 0E3C9A5D20EC004D00B199F9 /* custom.servers */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = custom.servers; sourceTree = ""; }; 0E441E252055AEDF007528D5 /* ThemeStrategy+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThemeStrategy+App.swift"; sourceTree = ""; }; 0E492C661FE60907007F23DF /* Flags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flags.swift; sourceTree = ""; }; @@ -610,7 +637,7 @@ 0E9452AA1FDB5EF600891948 /* UINavigationItem+Shortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationItem+Shortcuts.swift"; sourceTree = ""; }; 0E9452AD1FDB5F7A00891948 /* PIAPageControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAPageControl.swift; sourceTree = ""; }; 0E9785851DA82FF000711A24 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; - 0E98BB6D1FD5BC6200B41D6B /* Bootstrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bootstrapper.swift; sourceTree = ""; }; + 0E98BB6D1FD5BC6200B41D6B /* Bootstrapper.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = Bootstrapper.swift; sourceTree = ""; tabWidth = 4; }; 0E9AEA6120683FDF00B6E59A /* AboutComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutComponent.swift; sourceTree = ""; }; 0EA660071FEC7A9500CB2B0D /* PIATunnelProvider+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PIATunnelProvider+UI.swift"; sourceTree = ""; }; 0EB0A849204F0CE2008BCF1D /* DataCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataCounter.h; sourceTree = ""; }; @@ -663,12 +690,29 @@ 3524670D26B432ED00E3F0AC /* DashboardViewController+ServerSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DashboardViewController+ServerSelection.swift"; sourceTree = ""; }; 3545E97F26AAD60C00B812CC /* ServerSelectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionDelegate.swift; sourceTree = ""; }; 3545E98126AADB2B00B812CC /* ServerSelectingTileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectingTileCell.swift; sourceTree = ""; }; - 7EB8D11327CCF4C20030B060 /* PIA VPN UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PIA VPN UITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 7EB8D11E27CE2B020030B060 /* PIAUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAUITests.swift; sourceTree = ""; }; - 7EB8D12027CE2B5D0030B060 /* PIALaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIALaunchTests.swift; sourceTree = ""; }; - 7EB8D12227CE7D4C0030B060 /* PIALoginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIALoginTests.swift; sourceTree = ""; }; - 7EC2972D27D8B8580061C56A /* CredentialsUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsUtil.swift; sourceTree = ""; }; - 7EC2972E27D8B8580061C56A /* Credentials.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Credentials.plist; sourceTree = ""; }; + 35EDD6272ADE5D31007B9ACB /* BaseTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTest.swift; sourceTree = ""; }; + 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInTests.swift; sourceTree = ""; }; + 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; + 35EDD6342ADE7424007B9ACB /* VPNPermissionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNPermissionScreen.swift; sourceTree = ""; }; + 35EDD6362ADE761A007B9ACB /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = ""; }; + 35EDD63A2AE62D15007B9ACB /* ElementHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementHelper.swift; sourceTree = ""; }; + 35EDD63D2AE76A3B007B9ACB /* WaitHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitHelper.swift; sourceTree = ""; }; + 35EDD6412AE7A83D007B9ACB /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = ""; }; + 35EDD6432AE7B480007B9ACB /* Common.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = ""; }; + 69196F522AF9048A008FDD43 /* PIA-VPN-e2e-simulator.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = "PIA-VPN-e2e-simulator.xctestplan"; path = "PIA-VPN_E2E_Tests/PIA-VPN-e2e-simulator.xctestplan"; sourceTree = ""; }; + 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAWidgetAttributes.swift; sourceTree = ""; tabWidth = 4; }; + 6924831D2AB04FFD002A0407 /* PIAWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIAWidgetBundle.swift; sourceTree = ""; }; + 6924831F2AB05F18002A0407 /* PIAConnectionView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAConnectionView.swift; sourceTree = ""; tabWidth = 4; }; + 692483212AB05F37002A0407 /* PIACircleIcon.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIACircleIcon.swift; sourceTree = ""; tabWidth = 4; }; + 692483252AB05F85002A0407 /* PIAConnectionActivityWidget.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAConnectionActivityWidget.swift; sourceTree = ""; tabWidth = 4; }; + 6947AADB2ACDC8AE001BCC66 /* PIA-VPN-e2e-simulator.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "PIA-VPN-e2e-simulator.xctestplan"; sourceTree = ""; }; + 698F4F2C2AB978BF0010B2B0 /* PIACircleImageView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIACircleImageView.swift; sourceTree = ""; tabWidth = 4; }; + 698F4F2F2ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAConnectionLiveActivityManager.swift; sourceTree = ""; tabWidth = 4; }; + 69B70AB02ACBF51C0072A09D /* PIA-VPN_E2E_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PIA-VPN_E2E_Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 69B70AB42ACBF51C0072A09D /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = ""; }; + 69B70ABD2ACC2CFE0072A09D /* AccessibilityId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityId.swift; sourceTree = ""; }; + 69C587FC2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = PIAExampleWithAuthenticatedAppTest.swift; sourceTree = ""; tabWidth = 2; }; + 7EC2972D27D8B8580061C56A /* CredentialsUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = CredentialsUtil.swift; sourceTree = ""; tabWidth = 4; }; 7ECBB8DC27B6C4F500C0C774 /* UserSurveyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSurveyManager.swift; sourceTree = ""; }; 821674F02678A1BE0028E4FD /* SettingsDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDelegate.swift; sourceTree = ""; }; 82183D7A2500FD460033023F /* String+Substrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Substrings.swift"; sourceTree = ""; }; @@ -818,7 +862,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 69446CB72AA750440080F446 /* PIALibrary in Frameworks */, + 69196F4F2AF901B6008FDD43 /* PIALibrary in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -838,7 +882,7 @@ 0EE2205C1F4EF307002805AE /* CoreGraphics.framework in Frameworks */, AABF826F28AD187800CDAC64 /* Popover in Frameworks */, 0EE2205F1F4EF307002805AE /* StoreKit.framework in Frameworks */, - 69446CB52AA7503A0080F446 /* PIALibrary in Frameworks */, + 695A17432AF8FCAA005542AC /* PIALibrary in Frameworks */, 0EE2205D1F4EF307002805AE /* UIKit.framework in Frameworks */, 0EE2205E1F4EF307002805AE /* Foundation.framework in Frameworks */, AABF826D28AD185E00CDAC64 /* TweetNacl in Frameworks */, @@ -876,7 +920,7 @@ 2985E5671856BD1200D70E28 /* QuartzCore.framework in Frameworks */, 291C6382183EBC210039EC03 /* CoreGraphics.framework in Frameworks */, 291C6384183EBC210039EC03 /* UIKit.framework in Frameworks */, - 69446CB32AA7502E0080F446 /* PIALibrary in Frameworks */, + 695A17412AF8FC7A005542AC /* PIALibrary in Frameworks */, DD606ABA21C7A17900E0781D /* NetworkExtension.framework in Frameworks */, AA36CDC928A6733500180A33 /* DZNEmptyDataSet in Frameworks */, 291C6380183EBC210039EC03 /* Foundation.framework in Frameworks */, @@ -884,10 +928,12 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7EB8D11027CCF4C20030B060 /* Frameworks */ = { + 69B70AAD2ACBF51C0072A09D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 35950B312ADD2996006F3CD9 /* Quick in Frameworks */, + 35950B342ADD2EE5006F3CD9 /* Nimble in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -904,7 +950,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 69446CB92AA7504B0080F446 /* PIALibrary in Frameworks */, + 69196F512AF901DE008FDD43 /* PIALibrary in Frameworks */, AA36CDDB28A6860F00180A33 /* TweetNacl in Frameworks */, DDC8F5F923EC10E4005D19C6 /* NetworkExtension.framework in Frameworks */, ); @@ -1114,6 +1160,7 @@ 291C6373183EBC210039EC03 = { isa = PBXGroup; children = ( + 69196F522AF9048A008FDD43 /* PIA-VPN-e2e-simulator.xctestplan */, 8269A6ED251CB5ED000B4DBF /* PIAWidgetExtension.entitlements */, 291C6385183EBC210039EC03 /* PIA VPN */, 0EFB6071203D7A2C0095398C /* PIA VPN AdBlocker */, @@ -1122,7 +1169,7 @@ 0EEE1C191E4F719E00397DE2 /* Resources */, DDC8F5ED23EC1070005D19C6 /* PIA VPN WG Tunnel */, 8269A6D8251CB5E0000B4DBF /* PIAWidget */, - 7EB8D11427CCF4C20030B060 /* PIA VPN UITests */, + 69B70AB12ACBF51C0072A09D /* PIA-VPN_E2E_Tests */, 291C637E183EBC210039EC03 /* Frameworks */, 291C637D183EBC210039EC03 /* Products */, ); @@ -1138,7 +1185,7 @@ 0EFB6070203D7A2C0095398C /* PIA VPN AdBlocker.appex */, DDC8F5EC23EC106F005D19C6 /* PIA VPN WG Tunnel.appex */, 8269A6D5251CB5E0000B4DBF /* PIAWidgetExtension.appex */, - 7EB8D11327CCF4C20030B060 /* PIA VPN UITests.xctest */, + 69B70AB02ACBF51C0072A09D /* PIA-VPN_E2E_Tests.xctest */, ); name = Products; sourceTree = ""; @@ -1218,6 +1265,7 @@ 0E2215C820084CD700F5FB4D /* SwiftGen+Strings.swift */, DD58F4BE21B12CFE00D043F7 /* PIAConnectionButton.swift */, DD125DD021E7A694004ECCB6 /* ServerButton.swift */, + 69B70ABD2ACC2CFE0072A09D /* AccessibilityId.swift */, ); name = Shared; sourceTree = ""; @@ -1234,16 +1282,64 @@ name = UI; sourceTree = ""; }; - 7EB8D11427CCF4C20030B060 /* PIA VPN UITests */ = { + 35EDD6262ADE5D1E007B9ACB /* Tests */ = { + isa = PBXGroup; + children = ( + 69C587FC2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift */, + 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */, + 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */, + ); + path = Tests; + sourceTree = ""; + }; + 35EDD62B2ADE62FE007B9ACB /* Screens */ = { + isa = PBXGroup; + children = ( + 69B70AB42ACBF51C0072A09D /* LoginScreen.swift */, + 35EDD6342ADE7424007B9ACB /* VPNPermissionScreen.swift */, + 35EDD6362ADE761A007B9ACB /* HomeScreen.swift */, + 35EDD6412AE7A83D007B9ACB /* WelcomeScreen.swift */, + 35EDD6432AE7B480007B9ACB /* Common.swift */, + ); + path = Screens; + sourceTree = ""; + }; + 35EDD6382AE62CF0007B9ACB /* Helpers */ = { + isa = PBXGroup; + children = ( + 35EDD63A2AE62D15007B9ACB /* ElementHelper.swift */, + 35EDD63D2AE76A3B007B9ACB /* WaitHelper.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 35EDD63C2AE7679B007B9ACB /* Core */ = { + isa = PBXGroup; + children = ( + 35EDD6272ADE5D31007B9ACB /* BaseTest.swift */, + ); + path = Core; + sourceTree = ""; + }; + 69B70AB12ACBF51C0072A09D /* PIA-VPN_E2E_Tests */ = { + isa = PBXGroup; + children = ( + 35EDD63C2AE7679B007B9ACB /* Core */, + 35EDD6382AE62CF0007B9ACB /* Helpers */, + 35EDD62B2ADE62FE007B9ACB /* Screens */, + 35EDD6262ADE5D1E007B9ACB /* Tests */, + 6947AADB2ACDC8AE001BCC66 /* PIA-VPN-e2e-simulator.xctestplan */, + 69D12D152ACC75140053A81B /* Util */, + ); + path = "PIA-VPN_E2E_Tests"; + sourceTree = ""; + }; + 69D12D152ACC75140053A81B /* Util */ = { isa = PBXGroup; children = ( - 7EC2972E27D8B8580061C56A /* Credentials.plist */, 7EC2972D27D8B8580061C56A /* CredentialsUtil.swift */, - 7EB8D12227CE7D4C0030B060 /* PIALoginTests.swift */, - 7EB8D11E27CE2B020030B060 /* PIAUITests.swift */, - 7EB8D12027CE2B5D0030B060 /* PIALaunchTests.swift */, ); - path = "PIA VPN UITests"; + path = Util; sourceTree = ""; }; 82183D8425014F940033023F /* Menu */ = { @@ -1370,6 +1466,9 @@ AAE878A628E473A400557F26 /* PIAWidgetVpnDetailsView.swift */, AAE878A828E4765F00557F26 /* PIAIconView.swift */, AA52C59E28E5ECD400D025AF /* PIAWidgetVpnDetaislRow.swift */, + 6924831F2AB05F18002A0407 /* PIAConnectionView.swift */, + 692483212AB05F37002A0407 /* PIACircleIcon.swift */, + 698F4F2C2AB978BF0010B2B0 /* PIACircleImageView.swift */, ); path = UI; sourceTree = ""; @@ -1380,6 +1479,10 @@ 8269A6D9251CB5E0000B4DBF /* PIAWidget.swift */, AAE8789E28E4696300557F26 /* PIAWidgetProvider.swift */, AAE878A028E46C1600557F26 /* PIAWidgetPreview.swift */, + 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */, + 6924831D2AB04FFD002A0407 /* PIAWidgetBundle.swift */, + 692483252AB05F85002A0407 /* PIAConnectionActivityWidget.swift */, + 698F4F2F2ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift */, ); path = Widget; sourceTree = ""; @@ -1555,7 +1658,7 @@ ); name = "PIA VPN Tunnel"; packageProductDependencies = ( - 69446CB62AA750440080F446 /* PIALibrary */, + 69196F4E2AF901B6008FDD43 /* PIALibrary */, ); productName = "PIA OpenVPN"; productReference = 0E67FC221E3F802D00EF9929 /* PIA VPN Tunnel.appex */; @@ -1589,7 +1692,7 @@ AABF827228AE2FF500CDAC64 /* GradientProgressBar */, AABF827428AE2FFE00CDAC64 /* SideMenu */, AABF827728AE333200CDAC64 /* DZNEmptyDataSet */, - 69446CB42AA7503A0080F446 /* PIALibrary */, + 695A17422AF8FCAA005542AC /* PIALibrary */, ); productName = "PIA VPN"; productReference = 0EE2207A1F4EF307002805AE /* PIA VPN dev.app */; @@ -1657,28 +1760,32 @@ AA36CDCB28A673C900180A33 /* GradientProgressBar */, AA36CDCE28A6746500180A33 /* SideMenu */, AA36CDDD28A6878000180A33 /* AlamofireImage */, - 69446CB22AA7502E0080F446 /* PIALibrary */, + 695A17402AF8FC7A005542AC /* PIALibrary */, ); productName = "PIA VPN"; productReference = 291C637C183EBC210039EC03 /* PIA VPN.app */; productType = "com.apple.product-type.application"; }; - 7EB8D11227CCF4C20030B060 /* PIA VPN UITests */ = { + 69B70AAF2ACBF51C0072A09D /* PIA-VPN_E2E_Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = 7EB8D11D27CCF4C20030B060 /* Build configuration list for PBXNativeTarget "PIA VPN UITests" */; + buildConfigurationList = 69B70ABA2ACBF51C0072A09D /* Build configuration list for PBXNativeTarget "PIA-VPN_E2E_Tests" */; buildPhases = ( - 7EB8D10F27CCF4C20030B060 /* Sources */, - 7EB8D11027CCF4C20030B060 /* Frameworks */, - 7EB8D11127CCF4C20030B060 /* Resources */, + 69B70AAC2ACBF51C0072A09D /* Sources */, + 69B70AAD2ACBF51C0072A09D /* Frameworks */, + 69B70AAE2ACBF51C0072A09D /* Resources */, ); buildRules = ( ); dependencies = ( - 7EC2973227D8BCB60061C56A /* PBXTargetDependency */, + 69B70AB72ACBF51C0072A09D /* PBXTargetDependency */, ); - name = "PIA VPN UITests"; - productName = "PIA VPN UITests"; - productReference = 7EB8D11327CCF4C20030B060 /* PIA VPN UITests.xctest */; + name = "PIA-VPN_E2E_Tests"; + packageProductDependencies = ( + 35950B302ADD2996006F3CD9 /* Quick */, + 35950B332ADD2EE5006F3CD9 /* Nimble */, + ); + productName = "PIA-VPN_E2E_Tests"; + productReference = 69B70AB02ACBF51C0072A09D /* PIA-VPN_E2E_Tests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; 8269A6D4251CB5E0000B4DBF /* PIAWidgetExtension */ = { @@ -1713,7 +1820,7 @@ name = "PIA VPN WG Tunnel"; packageProductDependencies = ( AA36CDDA28A6860F00180A33 /* TweetNacl */, - 69446CB82AA7504B0080F446 /* PIALibrary */, + 69196F502AF901DE008FDD43 /* PIALibrary */, ); productName = "PIA VPN WG Tunnel"; productReference = DDC8F5EC23EC106F005D19C6 /* PIA VPN WG Tunnel.appex */; @@ -1726,7 +1833,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = PIA; - LastSwiftUpdateCheck = 1300; + LastSwiftUpdateCheck = 1430; LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Private Internet Access Inc."; TargetAttributes = { @@ -1754,9 +1861,7 @@ }; 0EEE1BE61E4F6EF400397DE2 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = 5357M5NW9W; LastSwiftMigration = 1010; - ProvisioningStyle = Automatic; TestTargetID = 291C637B183EBC210039EC03; }; 0EFB606F203D7A2C0095398C = { @@ -1798,10 +1903,8 @@ }; }; }; - 7EB8D11227CCF4C20030B060 = { - CreatedOnToolsVersion = 13.0; - DevelopmentTeam = 5357M5NW9W; - ProvisioningStyle = Automatic; + 69B70AAF2ACBF51C0072A09D = { + CreatedOnToolsVersion = 14.3.1; TestTargetID = 0EE2200B1F4EF307002805AE; }; 8269A6D4251CB5E0000B4DBF = { @@ -1849,7 +1952,9 @@ AA36CDCA28A673C900180A33 /* XCRemoteSwiftPackageReference "GradientProgressBar" */, AA36CDCD28A6746500180A33 /* XCRemoteSwiftPackageReference "SideMenu" */, AA36CDDC28A6878000180A33 /* XCRemoteSwiftPackageReference "AlamofireImage" */, - 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */, + 35950B2F2ADD2877006F3CD9 /* XCRemoteSwiftPackageReference "Quick" */, + 35950B322ADD2EE5006F3CD9 /* XCRemoteSwiftPackageReference "Nimble" */, + 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */, ); productRefGroup = 291C637D183EBC210039EC03 /* Products */; projectDirPath = ""; @@ -1862,7 +1967,7 @@ DDC8F5EB23EC106F005D19C6 /* PIA VPN WG Tunnel */, 8269A6D4251CB5E0000B4DBF /* PIAWidgetExtension */, 0EEE1BE61E4F6EF400397DE2 /* PIA VPNTests */, - 7EB8D11227CCF4C20030B060 /* PIA VPN UITests */, + 69B70AAF2ACBF51C0072A09D /* PIA-VPN_E2E_Tests */, ); }; /* End PBXProject section */ @@ -1987,11 +2092,10 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7EB8D11127CCF4C20030B060 /* Resources */ = { + 69B70AAE2ACBF51C0072A09D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7EC2973027D8B8580061C56A /* Credentials.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2000,6 +2104,8 @@ buildActionMask = 2147483647; files = ( 8269A6DD251CB5E3000B4DBF /* Assets.xcassets in Resources */, + 695BF81D2AC30EFB00D1139C /* Localizable.strings in Resources */, + 698F4F2E2AB97BAD0010B2B0 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2039,7 +2145,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftgen >/dev/null; then\n set -e\n swiftgen\nelse\n echo \"warning: SwiftGen not installed, download it from https://github.com/SwiftGen/SwiftGen\"\nfi\n"; + shellScript = "if which swiftgen >/dev/null; then\n set -e\n #swiftgen\nelse\n echo \"warning: SwiftGen not installed, download it from https://github.com/SwiftGen/SwiftGen\"\nfi\n"; }; 2931563B18513F6500E769A7 /* Download Latest Regions List */ = { isa = PBXShellScriptBuildPhase; @@ -2080,6 +2186,7 @@ DD76292321ECCD5C0092DF50 /* UsageTile.swift in Sources */, DDD65314247E66AD00F0A897 /* CoordinatesFinder.swift in Sources */, DDD271DF21D616AA00B6D20F /* Server+Favorite.swift in Sources */, + 698F4F312ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */, DD125DC621E77046004ECCB6 /* QuickConnectTile.swift in Sources */, 82A1AD2724B86AF60003DD02 /* PIACardsViewController.swift in Sources */, 829EB508253598BD003E74DD /* DedicatedIpViewController.swift in Sources */, @@ -2159,6 +2266,7 @@ 0E2215CD2008C01D00F5FB4D /* SwiftGen+Assets.swift in Sources */, 8272C62E2657B46100D846A8 /* NetworkSettingsViewController.swift in Sources */, DDFCFA9021E892070081F235 /* RegionTileCollectionViewCell.swift in Sources */, + 6924831B2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */, DD9706A5224262BF00630220 /* QuickSettingsTile.swift in Sources */, 82CAB8E9255C0CB000BB08EF /* MessagesTile.swift in Sources */, DD3B504424B7576F0002F4B5 /* Card.swift in Sources */, @@ -2179,6 +2287,7 @@ 0EFDC1E11FE4A450007C0B9B /* AppPreferences.swift in Sources */, 0E441E272055AEDF007528D5 /* ThemeStrategy+App.swift in Sources */, DDC8125021761B0B00CB290C /* SwiftGen+ScenesStoryboards.swift in Sources */, + 69B70ABF2ACC2CFE0072A09D /* AccessibilityId.swift in Sources */, 7ECBB8DE27BA5FCE00C0C774 /* UserSurveyManager.swift in Sources */, 0E492C681FE60907007F23DF /* Flags.swift in Sources */, DD172A972254C35000071CFB /* FavoriteServersTile.swift in Sources */, @@ -2208,7 +2317,6 @@ DD606AC821C9344100E0781D /* AppTests.swift in Sources */, 82A1AD2324B7C0020003DD02 /* PIACardTests.swift in Sources */, 8221922B24CECFE700C24F1C /* NMTTests.swift in Sources */, - 82CAB8DA255BEC7000BB08EF /* PIACommandTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2256,6 +2364,7 @@ 0ECF5C082017EBAD0047596C /* ThemeCode.swift in Sources */, 3545E98026AAD60C00B812CC /* ServerSelectionDelegate.swift in Sources */, 0E392DA61FE3283C0002160D /* TransientState.swift in Sources */, + 6924831A2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */, 82F41376264E8AC20098FF4B /* SettingOptions.swift in Sources */, 824C531524C04796003DB740 /* ConnectionTileCollectionViewCell.swift in Sources */, 0E3A35351FD9EBDA000B0F99 /* AppDelegate.swift in Sources */, @@ -2287,6 +2396,7 @@ 827570D124DAA128008F9800 /* PIAHeaderCollectionViewCell.swift in Sources */, DD125DD121E7A694004ECCB6 /* ServerButton.swift in Sources */, DD9329A2237AFD0A0025B6BC /* ShowQuickSettingsViewController.swift in Sources */, + 69B70ABE2ACC2CFE0072A09D /* AccessibilityId.swift in Sources */, 0E2215C920084CD700F5FB4D /* SwiftGen+Strings.swift in Sources */, 827570D824DAB6E4008F9800 /* NetworkFooterCollectionViewCell.swift in Sources */, E5F52A1F2A8A614900828883 /* NetworkMonitor.swift in Sources */, @@ -2340,6 +2450,7 @@ 8272C62726540B2100D846A8 /* ProtocolSettingsViewController.swift in Sources */, 82CAB8B0255B050000BB08EF /* MessagesCommands.swift in Sources */, DDE432DF2498EADB0095B197 /* Array+Group.swift in Sources */, + 698F4F302ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */, DDB6B95321C95CD400DE8C5F /* EnumsBuilder.swift in Sources */, 3545E98226AADB2B00B812CC /* ServerSelectingTileCell.swift in Sources */, 829EB5322535AD27003E74DD /* DedicatedIpEmptyHeaderViewCell.swift in Sources */, @@ -2355,14 +2466,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 7EB8D10F27CCF4C20030B060 /* Sources */ = { + 69B70AAC2ACBF51C0072A09D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7EC2972F27D8B8580061C56A /* CredentialsUtil.swift in Sources */, - 7EB8D12327CE7D4C0030B060 /* PIALoginTests.swift in Sources */, - 7EB8D11F27CE2B020030B060 /* PIAUITests.swift in Sources */, - 7EB8D12127CE2B5D0030B060 /* PIALaunchTests.swift in Sources */, + 35EDD6442AE7B480007B9ACB /* Common.swift in Sources */, + 35EDD63E2AE76A3B007B9ACB /* WaitHelper.swift in Sources */, + 35EDD6282ADE5D31007B9ACB /* BaseTest.swift in Sources */, + 35EDD6352ADE7424007B9ACB /* VPNPermissionScreen.swift in Sources */, + 69B70ABC2ACBF8300072A09D /* CredentialsUtil.swift in Sources */, + 35EDD6372ADE761A007B9ACB /* HomeScreen.swift in Sources */, + 35EDD63B2AE62D15007B9ACB /* ElementHelper.swift in Sources */, + 69C587FD2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift in Sources */, + 35EDD6422AE7A83D007B9ACB /* WelcomeScreen.swift in Sources */, + 35EDD62A2ADE5F08007B9ACB /* SignInTests.swift in Sources */, + 69B70AB52ACBF51C0072A09D /* LoginScreen.swift in Sources */, + 35EDD6332ADE7281007B9ACB /* OnboardingTests.swift in Sources */, + 69B70AC02ACC2CFE0072A09D /* AccessibilityId.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2371,15 +2491,23 @@ buildActionMask = 2147483647; files = ( 8269A6FE251CBB36000B4DBF /* WidgetInformation.swift in Sources */, + 695BF81F2AC410E000D1139C /* SwiftGen+Strings.swift in Sources */, + 698F4F2D2AB978BF0010B2B0 /* PIACircleImageView.swift in Sources */, 822F97B4251DD53100644EF2 /* WidgetUserDefaultsDatasource.swift in Sources */, 8269A6DA251CB5E0000B4DBF /* PIAWidget.swift in Sources */, + 692483222AB05F37002A0407 /* PIACircleIcon.swift in Sources */, AAE878A928E4765F00557F26 /* PIAIconView.swift in Sources */, + 6924831E2AB04FFD002A0407 /* PIAWidgetBundle.swift in Sources */, AAE8789F28E4696300557F26 /* PIAWidgetProvider.swift in Sources */, AAE878A128E46C1600557F26 /* PIAWidgetPreview.swift in Sources */, + 692483262AB05F85002A0407 /* PIAConnectionActivityWidget.swift in Sources */, AAE878A528E4723B00557F26 /* PIACircleVpnButton.swift in Sources */, 82BAACFB25B09C9200B3C733 /* PIAWidget.intentdefinition in Sources */, AAE8789C28E4679500557F26 /* WidgetPersistenceDatasource.swift in Sources */, AAE878A328E46D2B00557F26 /* PIAWidgetView.swift in Sources */, + 6924831C2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */, + 698F4F322ABA1DA10010B2B0 /* PIAConnectionLiveActivityManager.swift in Sources */, + 692483202AB05F18002A0407 /* PIAConnectionView.swift in Sources */, AAE878A728E473A400557F26 /* PIAWidgetVpnDetailsView.swift in Sources */, AA52C59F28E5ECD400D025AF /* PIAWidgetVpnDetaislRow.swift in Sources */, ); @@ -2426,10 +2554,10 @@ target = 0EFB606F203D7A2C0095398C /* PIA VPN AdBlocker */; targetProxy = 0EFB607E203D893E0095398C /* PBXContainerItemProxy */; }; - 7EC2973227D8BCB60061C56A /* PBXTargetDependency */ = { + 69B70AB72ACBF51C0072A09D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0EE2200B1F4EF307002805AE /* PIA VPN dev */; - targetProxy = 7EC2973127D8BCB60061C56A /* PBXContainerItemProxy */; + targetProxy = 69B70AB62ACBF51C0072A09D /* PBXContainerItemProxy */; }; 8269A6E2251CB5E3000B4DBF /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -2532,7 +2660,7 @@ CODE_SIGN_ENTITLEMENTS = "PIA VPN Tunnel/PIA VPN Tunnel.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5357M5NW9W; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -2543,7 +2671,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.Tunnel"; PRODUCT_NAME = "PIA VPN Tunnel"; @@ -2566,9 +2694,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 5357M5NW9W; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5357M5NW9W; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = "PIA VPN Tunnel/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.1; @@ -2577,12 +2706,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.Tunnel"; PRODUCT_NAME = "PIA VPN Tunnel"; PROVISIONING_PROFILE = "b5b9e54d-7aba-4fc6-9320-adbce64c544a"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.privateinternetaccess.ios.PIA-VPN.Tunnel"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.privateinternetaccess.ios.PIA-VPN.Tunnel"; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -2598,7 +2728,7 @@ CODE_SIGN_ENTITLEMENTS = "PIA VPN/PIA VPN.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5357M5NW9W; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2618,7 +2748,7 @@ "$(inherited)", "$(SRCROOT)", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.4; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN"; PRODUCT_MODULE_NAME = PIA_VPN_dev; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2642,7 +2772,7 @@ CODE_SIGN_ENTITLEMENTS = "PIA VPN/PIA VPN.entitlements"; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5357M5NW9W; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -2662,7 +2792,7 @@ "$(inherited)", "$(SRCROOT)", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.4; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN"; PRODUCT_MODULE_NAME = PIA_VPN_dev; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2718,7 +2848,6 @@ CLANG_ENABLE_MODULES = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -2737,7 +2866,6 @@ "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = ""; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)-Swift.h"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PIA VPN.app/PIA VPN"; @@ -2754,7 +2882,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2766,7 +2894,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.AdBlocker"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2791,9 +2919,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 5357M5NW9W; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = "PIA VPN AdBlocker/Info.plist"; @@ -2803,12 +2932,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.AdBlocker"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "5aba703f-4bee-46e6-a5e4-42b785d1db55"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.privateinternetaccess.ios.PIA-VPN.AdBlocker"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.privateinternetaccess.ios.PIA-VPN.AdBlocker"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -2934,7 +3064,7 @@ CODE_SIGN_ENTITLEMENTS = "PIA VPN/PIA VPN.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5357M5NW9W; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -2952,7 +3082,7 @@ "$(inherited)", "$(SRCROOT)", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.4; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match Development com.privateinternetaccess.ios.PIA-VPN"; @@ -2971,10 +3101,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "PIA VPN/PIA VPN.entitlements"; - CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_IDENTITY = "Apple Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 5357M5NW9W; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5357M5NW9W; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2991,22 +3123,23 @@ "$(inherited)", "$(SRCROOT)", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.4; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.privateinternetaccess.ios.PIA-VPN"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.privateinternetaccess.ios.PIA-VPN"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.privateinternetaccess.ios.PIA-VPN"; SWIFT_OBJC_BRIDGING_HEADER = ""; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Release; }; - 7EB8D11B27CCF4C20030B060 /* Debug */ = { + 69B70AB82ACBF51C0072A09D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; @@ -3018,18 +3151,13 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.cyberghostsrl.PIA-VPN-UITests"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = ""; + PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.e2e-Tests.PIA-VPN-E2E-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "420cc0bf-ef09-4d4c-b1b3-9d7cffd4d201"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -3039,12 +3167,12 @@ }; name = Debug; }; - 7EB8D11C27CCF4C20030B060 /* Release */ = { + 69B70AB92ACBF51C0072A09D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; @@ -3057,18 +3185,13 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.1; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.cyberghostsrl.PIA-VPN-UITests"; - "PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]" = ""; + PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.e2e-Tests.PIA-VPN-E2E-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "420cc0bf-ef09-4d4c-b1b3-9d7cffd4d201"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -3091,7 +3214,7 @@ CODE_SIGN_ENTITLEMENTS = PIAWidgetExtension.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -3103,7 +3226,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.PIAWidget"; @@ -3133,9 +3256,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 5357M5NW9W; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = PIAWidget/Info.plist; @@ -3145,12 +3269,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.PIAWidget"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.privateinternetaccess.ios.PIA-VPN.PIAWidget"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.privateinternetaccess.ios.PIA-VPN.PIAWidget"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -3169,7 +3294,7 @@ CODE_SIGN_ENTITLEMENTS = "PIA VPN WG Tunnel/PIA_VPN_WG_Tunnel.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -3181,7 +3306,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.WG-Tunnel"; @@ -3208,9 +3333,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 20034; + CURRENT_PROJECT_VERSION = 20042; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 5357M5NW9W; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5357M5NW9W; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = "PIA VPN WG Tunnel/Info.plist"; @@ -3220,12 +3346,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.23.0; + MARKETING_VERSION = 3.23.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.privateinternetaccess.ios.PIA-VPN.WG-Tunnel"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.privateinternetaccess.ios.PIA-VPN.WG-Tunnel"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.privateinternetaccess.ios.PIA-VPN.WG-Tunnel"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -3289,11 +3416,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 7EB8D11D27CCF4C20030B060 /* Build configuration list for PBXNativeTarget "PIA VPN UITests" */ = { + 69B70ABA2ACBF51C0072A09D /* Build configuration list for PBXNativeTarget "PIA-VPN_E2E_Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 7EB8D11B27CCF4C20030B060 /* Debug */, - 7EB8D11C27CCF4C20030B060 /* Release */, + 69B70AB82ACBF51C0072A09D /* Debug */, + 69B70AB92ACBF51C0072A09D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -3319,9 +3446,25 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */ = { + 35950B2F2ADD2877006F3CD9 /* XCRemoteSwiftPackageReference "Quick" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Quick/Quick"; + requirement = { + kind = exactVersion; + version = 7.3.0; + }; + }; + 35950B322ADD2EE5006F3CD9 /* XCRemoteSwiftPackageReference "Nimble" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Quick/Nimble"; + requirement = { + kind = exactVersion; + version = 13.0.0; + }; + }; + 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "git@github.com:pia-foss/client-library-apple.git"; + repositoryURL = "git@github.com:pia-foss/mobile-ios-library.git"; requirement = { branch = master; kind = branch; @@ -3378,24 +3521,34 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 69446CB22AA7502E0080F446 /* PIALibrary */ = { + 35950B302ADD2996006F3CD9 /* Quick */ = { + isa = XCSwiftPackageProductDependency; + package = 35950B2F2ADD2877006F3CD9 /* XCRemoteSwiftPackageReference "Quick" */; + productName = Quick; + }; + 35950B332ADD2EE5006F3CD9 /* Nimble */ = { + isa = XCSwiftPackageProductDependency; + package = 35950B322ADD2EE5006F3CD9 /* XCRemoteSwiftPackageReference "Nimble" */; + productName = Nimble; + }; + 69196F4E2AF901B6008FDD43 /* PIALibrary */ = { isa = XCSwiftPackageProductDependency; - package = 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */; + package = 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */; productName = PIALibrary; }; - 69446CB42AA7503A0080F446 /* PIALibrary */ = { + 69196F502AF901DE008FDD43 /* PIALibrary */ = { isa = XCSwiftPackageProductDependency; - package = 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */; + package = 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */; productName = PIALibrary; }; - 69446CB62AA750440080F446 /* PIALibrary */ = { + 695A17402AF8FC7A005542AC /* PIALibrary */ = { isa = XCSwiftPackageProductDependency; - package = 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */; + package = 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */; productName = PIALibrary; }; - 69446CB82AA7504B0080F446 /* PIALibrary */ = { + 695A17422AF8FCAA005542AC /* PIALibrary */ = { isa = XCSwiftPackageProductDependency; - package = 69446CB12AA74F880080F446 /* XCRemoteSwiftPackageReference "client-library-apple" */; + package = 695A173F2AF8FC7A005542AC /* XCRemoteSwiftPackageReference "mobile-ios-library" */; productName = PIALibrary; }; AA36CDBA28A6622A00180A33 /* TweetNacl */ = { diff --git a/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN dev.xcscheme b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN dev.xcscheme index a41ce8df3..8a19b76d3 100644 --- a/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN dev.xcscheme +++ b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN dev.xcscheme @@ -1,7 +1,7 @@ + version = "1.7"> @@ -54,7 +54,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "NO"> + + + + + + + + + + @@ -76,12 +94,13 @@ + skipped = "NO" + parallelizable = "YES"> diff --git a/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN.xcscheme b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN.xcscheme index c8602f4fa..9860758c1 100644 --- a/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN.xcscheme +++ b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN.xcscheme @@ -48,6 +48,20 @@ ReferencedContainer = "container:PIA VPN.xcodeproj"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PIA VPN/AccessibilityId.swift b/PIA VPN/AccessibilityId.swift new file mode 100644 index 000000000..a83f3db2c --- /dev/null +++ b/PIA VPN/AccessibilityId.swift @@ -0,0 +1,48 @@ + +import Foundation + +public struct AccessibilityId { + public struct VPNPermission { + public static let screen = "id.vpnPermission.screen" + public static let submit = "id.vpnPermission.ok.button" + } + + public struct Dashboard { + public static let connectionButton = "id.dashboard.connection.button" + } + +} + + +/// This is the same struct `Accessibility` from `PIALibrary` +/// It has been copied over to the VPN ios client app to +/// facilitate e2e testing. +/// In the future, we will move the Welcome and Login ViewControllers and storyboards from `PIALibrary` into vpn ios +/// And this duplication will not be necessary +public struct PIALibraryAccessibility { + public struct Id { + public struct Welcome { + public static let environment = "id.welcome.environment" + } + public struct Login { + public static let submit = "id.login.submit" + public static let submitNew = "id.login.submit.new" + public static let username = "id.login.username" + public static let password = "id.login.submit" + public struct Error { + public static let banner = "id.login.error.banner" + } + } + + public struct Dashboard { + public static let menu = "id.dashboard.menu" + } + public struct Menu { + public static let logout = "id.menu.logout" + } + public struct Dialog { + public static let destructive = "id.dialog.destructive.button" + } + } +} + diff --git a/PIA VPN/AppDelegate.swift b/PIA VPN/AppDelegate.swift index 350977a1a..c921da89c 100644 --- a/PIA VPN/AppDelegate.swift +++ b/PIA VPN/AppDelegate.swift @@ -42,6 +42,7 @@ class AppDelegate: NSObject, UIApplicationDelegate { var window: UIWindow? private var hotspotHelper: PIAHotspotHelper! + private (set) var liveActivityManager: PIAConnectionLiveActivityManagerType? deinit { NotificationCenter.default.removeObserver(self) @@ -55,12 +56,27 @@ class AppDelegate: NSObject, UIApplicationDelegate { application.shortcutItems = [] hotspotHelper = PIAHotspotHelper() _ = hotspotHelper.configureHotspotHelper() - + + instantiateLiveActivityManagerIfNeeded() return true } + + private func instantiateLiveActivityManagerIfNeeded() { + if #available(iOS 16.2, *) { + // Only instantiates the LiveActivities if the Feature Flag for it is enabled + guard AppPreferences.shared.showDynamicIslandLiveActivity else { + liveActivityManager = nil + return + } + + liveActivityManager = PIAConnectionLiveActivityManager.shared + } + } func applicationWillTerminate(_ application: UIApplication) { Bootstrapper.shared.dispose() + + liveActivityManager?.endLiveActivities() } // MARK: Orientations @@ -200,6 +216,9 @@ class AppDelegate: NSObject, UIApplicationDelegate { application.applicationIconBadgeNumber = 0 // Remove the Non compliant Wifi local notification as the app is in foreground now Macros.removeLocalNotification(NotificationCategory.nonCompliantWifi) + + instantiateLiveActivityManagerIfNeeded() + } private func refreshShortcutItems(in application: UIApplication) { diff --git a/PIA VPN/AppPreferences.swift b/PIA VPN/AppPreferences.swift index faa821d9d..003c49a30 100644 --- a/PIA VPN/AppPreferences.swift +++ b/PIA VPN/AppPreferences.swift @@ -104,6 +104,7 @@ class AppPreferences { static let showNewInitialScreen = "showNewInitialScreen" static let showLeakProtection = "showLeakProtection" static let showLeakProtectionNotifications = "showLeakProtectionNotifications" + static let showDynamicIslandLiveActivity = "showDynamicIslandLiveActivity" // Survey static let userInteractedWithSurvey = "userInteractedWithSurvey" @@ -537,6 +538,15 @@ class AppPreferences { defaults.set(newValue, forKey: Entries.showLeakProtectionNotifications) } } + + var showDynamicIslandLiveActivity: Bool { + get { + return defaults.bool(forKey: Entries.showDynamicIslandLiveActivity) + } + set { + defaults.set(newValue, forKey: Entries.showDynamicIslandLiveActivity) + } + } var checksDipExpirationRequest: Bool { get { diff --git a/PIA VPN/Bootstrapper.swift b/PIA VPN/Bootstrapper.swift index 0f5f4581a..0ef950e81 100644 --- a/PIA VPN/Bootstrapper.swift +++ b/PIA VPN/Bootstrapper.swift @@ -35,7 +35,7 @@ class Bootstrapper { } private var isSimulator: Bool { - #if arch(i386) || arch(x86_64) + #if targetEnvironment(simulator) return true #else return false @@ -59,6 +59,10 @@ class Bootstrapper { // Leak Protection feature flags AppPreferences.shared.showLeakProtection = Client.configuration.featureFlags.contains(Client.FeatureFlags.showLeakProtection) AppPreferences.shared.showLeakProtectionNotifications = Client.configuration.featureFlags.contains(Client.FeatureFlags.showLeakProtectionNotifications) + + // DynamicIsland LiveActivity + AppPreferences.shared.showDynamicIslandLiveActivity = Client.configuration.featureFlags.contains(Client.FeatureFlags.showDynamicIslandLiveActivity) + } func bootstrap() { diff --git a/PIA VPN/DashboardViewController.swift b/PIA VPN/DashboardViewController.swift index dfa6fe800..8bad1a3e3 100644 --- a/PIA VPN/DashboardViewController.swift +++ b/PIA VPN/DashboardViewController.swift @@ -26,6 +26,7 @@ import SideMenu import SwiftyBeaver import WidgetKit import NetworkExtension +import ActivityKit private let log = SwiftyBeaver.self @@ -69,7 +70,13 @@ class DashboardViewController: AutolayoutViewController { private var isDisconnecting = false private var isUnauthorized = false - private var currentStatus: VPNStatus = .disconnected + private var currentStatus: VPNStatus = .disconnected { + didSet { + if #available(iOS 16.2, *) { + startConnectionLiveActivityIfNeeded() + } + } + } private var connectingStatus: DashboardVPNConnectingStatus = .none private var tileModeStatus: TileStatus = .normal { @@ -130,7 +137,7 @@ class DashboardViewController: AutolayoutViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + setupNavigationBarButtons() AppPreferences.shared.wasLaunched = true @@ -390,7 +397,6 @@ class DashboardViewController: AutolayoutViewController { } @IBAction func vpnButtonClicked(_ sender: Any?) { - if canConnectVPN() { manuallyConnect() } else { @@ -656,50 +662,141 @@ class DashboardViewController: AutolayoutViewController { guard Client.preferences.currentRFC1918VulnerableWifi != nil || WifiNetworkMonitor().checkForRFC1918Vulnerability() else { return } - guard Client.preferences.allowLocalDeviceAccess - && Client.preferences.leakProtection else { return } - guard AppPreferences.shared.showLeakProtectionNotifications else { return } let currentRFC1918VulnerableWifiName = Client.preferences.currentRFC1918VulnerableWifi ?? "" + let selectedProtocol = Client.preferences.vpnType.vpnProtocol + let isWireguardSelected = selectedProtocol == PIAWGTunnelProfile.vpnType.vpnProtocol + let isOpenVPNSelected = selectedProtocol == PIATunnelProfile.vpnType.vpnProtocol + + guard !isWireguardSelected, + !isOpenVPNSelected else { + DispatchQueue.main.async { + self.presentNonCompliantWireguardWifiAlert() + self.showNonCompliantWifiLocalNotification(currentRFC1918VulnerableWifiName: currentRFC1918VulnerableWifiName) + } + + return + } + + guard Client.preferences.allowLocalDeviceAccess + && Client.preferences.leakProtection else { return } + DispatchQueue.main.async { self.presentNonCompliantWifiAlert() self.showNonCompliantWifiLocalNotification(currentRFC1918VulnerableWifiName: currentRFC1918VulnerableWifiName) } } - private func presentNonCompliantWifiAlert() { - guard let window = UIApplication.shared.delegate?.window, + //MARK: Non compliant Wifi alert + + private struct WifiAlertAction { + let title: String + let style: UIAlertAction.Style + let action: ((UIAlertAction) -> Void)? + } + + private func showNonCompliantWifiAlert(title: String, message: String, actions: [WifiAlertAction]) { + guard + let window = UIApplication.shared.delegate?.window, let presentedViewController = window?.rootViewController?.presentedViewController ?? window?.rootViewController else { return } - let title = L10n.Dashboard.Vpn.Leakprotection.Alert.title + if let alertController = presentedViewController as? UIAlertController, alertController.title == title { return } - if let alertController = presentedViewController as? UIAlertController, - alertController.title == title { return } + let sheet = Macros.alertController(title, message) - let sheet = Macros.alertController(title, L10n.Dashboard.Vpn.Leakprotection.Alert.message) - sheet.addAction(UIAlertAction(title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta1, style: .default, handler: { _ in - Client.preferences.allowLocalDeviceAccess = false - Client.providers.vpnProvider.disconnect { _ in - self.shouldReconnect = true - } - })) + for action in actions { + let alertAction = UIAlertAction(title: action.title, + style: action.style, + handler: action.action) + sheet.addAction(alertAction) + } - // Learn More action - sheet.addAction(UIAlertAction(title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta2, style: .default, handler: { _ in - let application = UIApplication.shared - let learnMoreURL = AppConstants.Web.leakProtectionURL - - if application.canOpenURL(learnMoreURL) { - application.open(learnMoreURL) - } - })) + presentedViewController.present(sheet, animated: true, completion: nil) + } + + private func presentNonCompliantWifiAlert() { + let title = L10n.Dashboard.Vpn.Leakprotection.Alert.title + let message = L10n.Dashboard.Vpn.Leakprotection.Alert.message + + var alertActions = [WifiAlertAction]() + let reconnectAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta1, + style: .default, + action: handleDisconnectAndReconnectAction) + alertActions.append(reconnectAction) - sheet.addAction(UIAlertAction(title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta3, style: .default, handler: nil)) + let learnMoreAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta2, + style: .default, + action: handleLearnMoreAction) + alertActions.append(learnMoreAction) + + let cancelAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta3, + style: .cancel, + action: nil) + alertActions.append(cancelAction) + + showNonCompliantWifiAlert(title: title, message: message, actions: alertActions) + } - presentedViewController.present(sheet, animated: true, completion: nil) + private func presentNonCompliantWireguardWifiAlert() { + let title = L10n.Dashboard.Vpn.Leakprotection.Alert.title + let message = L10n.Dashboard.Vpn.Leakprotection.Alert.IKEV2.message + + var alertActions = [WifiAlertAction]() + let reconnectAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.IKEV2.cta1, + style: .default, + action: handleSwitchProtocolAction) + alertActions.append(reconnectAction) + + let learnMoreAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta2, + style: .default, + action: handleLearnMoreAction) + alertActions.append(learnMoreAction) + + let cancelAction = WifiAlertAction( + title: L10n.Dashboard.Vpn.Leakprotection.Alert.cta3, + style: .cancel, + action: nil) + alertActions.append(cancelAction) + + showNonCompliantWifiAlert(title: title, message: message, actions: alertActions) + } + + private func handleDisconnectAndReconnectAction(_ action: UIAlertAction) { + Client.preferences.allowLocalDeviceAccess = false + Client.providers.vpnProvider.disconnect { _ in + self.shouldReconnect = true + } + } + + private func handleLearnMoreAction(_ action: UIAlertAction) { + let application = UIApplication.shared + let learnMoreURL = AppConstants.Web.leakProtectionURL + + if application.canOpenURL(learnMoreURL) { + application.open(learnMoreURL) + } + } + + private func handleSwitchProtocolAction(_ action: UIAlertAction) { + let editable = Client.preferences.editable() + editable.vpnType = IKEv2Profile.vpnType + let action = editable.requiredVPNAction() + editable.commit() + + Client.preferences.leakProtection = true + Client.preferences.allowLocalDeviceAccess = false + + action?.execute { _ in + self.shouldReconnect = true + } } func showNonCompliantWifiLocalNotification(currentRFC1918VulnerableWifiName: String) { @@ -771,6 +868,10 @@ class DashboardViewController: AutolayoutViewController { guard Client.providers.accountProvider.isLoggedIn else { return } + + if #available(iOS 16.2, *) { + startConnectionLiveActivityIfNeeded() + } currentStatus = Client.providers.vpnProvider.vpnStatus @@ -1126,3 +1227,28 @@ extension DashboardViewController: UICollectionViewDelegate, UICollectionViewDat } } } + + +// MARK: Live Activities + +extension DashboardViewController { + @available(iOS 16.2, *) + private func makeLiveActivityStateForCurrentConnection() -> PIAConnectionAttributes.ContentState { + let vpnProvider = Client.providers.vpnProvider + let currentServer = Client.preferences.displayedServer + + let vpnProtocol = vpnProvider.currentVPNType.vpnProtocol + + let state = PIAConnectionAttributes.ContentState(connected: vpnProvider.isVPNConnected, regionName: currentServer.name, regionFlag: "flag-\(currentServer.country.lowercased())", vpnProtocol: vpnProtocol) + return state + } + + + @available(iOS 16.2, *) + private func startConnectionLiveActivityIfNeeded() { + guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, + let liveActivityManager = appDelegate.liveActivityManager else { return } + let connState = makeLiveActivityStateForCurrentConnection() + liveActivityManager.startLiveActivity(with: connState) + } +} diff --git a/PIA VPN/Info.plist b/PIA VPN/Info.plist index 53cb1dce7..cbeba7e2c 100644 --- a/PIA VPN/Info.plist +++ b/PIA VPN/Info.plist @@ -51,6 +51,8 @@ We need camera access to scan a code from an gift card NSFaceIDUsageDescription Authenticate to reveal + NSSupportsLiveActivities + NSUserActivityTypes PIAConfigurationIntent diff --git a/PIA VPN/MessagesManager.swift b/PIA VPN/MessagesManager.swift index 6b7b4634b..6905be26b 100644 --- a/PIA VPN/MessagesManager.swift +++ b/PIA VPN/MessagesManager.swift @@ -21,7 +21,7 @@ import Foundation import PIALibrary -import PIAAccount +import account import UIKit public class MessagesManager: NSObject { diff --git a/PIA VPN/PIAConnectionButton.swift b/PIA VPN/PIAConnectionButton.swift index 8030960e9..c525268ad 100644 --- a/PIA VPN/PIAConnectionButton.swift +++ b/PIA VPN/PIAConnectionButton.swift @@ -68,6 +68,7 @@ class PIAConnectionButton: UIButton, Restylable { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.setupView() + self.accessibilityIdentifier = AccessibilityId.Dashboard.connectionButton } deinit { diff --git a/PIA VPN/ServerProvider+UI.swift b/PIA VPN/ServerProvider+UI.swift index 77b6ca710..228b24891 100644 --- a/PIA VPN/ServerProvider+UI.swift +++ b/PIA VPN/ServerProvider+UI.swift @@ -31,6 +31,10 @@ extension Client.Preferences { return preferredServer ?? .automatic } set { + guard newValue != displayedServer else { + connectToSelectedServerIfNeeded() + return + } let ed = editable() if newValue.isAutomatic { ed.preferredServer = nil @@ -41,13 +45,21 @@ extension Client.Preferences { let action = ed.requiredVPNAction() ed.commit() - action?.execute { (error) in - let vpn = Client.providers.vpnProvider - if (vpn.vpnStatus != .disconnected) { - vpn.reconnect(after: nil, forceDisconnect: true, nil) - } else { - vpn.connect(nil) - } + action?.execute { [weak self] (error) in + self?.connectToSelectedServerIfNeeded(shouldReconnect: true) + } + } + } + + private func connectToSelectedServerIfNeeded(shouldReconnect: Bool = false) { + let vpn = Client.providers.vpnProvider + + switch vpn.vpnStatus { + case .disconnected: + vpn.connect(nil) + default: + if shouldReconnect { + vpn.reconnect(after: nil, forceDisconnect: true, nil) } } } diff --git a/PIA VPN/SettingOptions.swift b/PIA VPN/SettingOptions.swift index d72c74427..a287a6800 100644 --- a/PIA VPN/SettingOptions.swift +++ b/PIA VPN/SettingOptions.swift @@ -297,6 +297,7 @@ public enum DevelopmentSections: Int, SettingSection, EnumsBuilder { case crash case leakProtectionFlag case leakProtectionNotificationsFlag + case dynamicIslandLiveActivityFlag public func localizedTitleMessage() -> String { switch self { @@ -311,6 +312,7 @@ public enum DevelopmentSections: Int, SettingSection, EnumsBuilder { case .crash: return "Crash the app" case .leakProtectionFlag: return "FF - Leak Protection" case .leakProtectionNotificationsFlag: return "FF - Leak Protection Notifications" + case .dynamicIslandLiveActivityFlag: return "FF - Dynamic Island Live Activity" } } @@ -327,11 +329,12 @@ public enum DevelopmentSections: Int, SettingSection, EnumsBuilder { case .crash: return "" case .leakProtectionFlag: return "" case .leakProtectionNotificationsFlag: return "" + case .dynamicIslandLiveActivityFlag: return "" } } public static func all() -> [Self] { - return [.stagingVersion, .customServers, .publicUsername, .username, .password, .environment, .resolveGoogleAdsDomain, .deleteKeychain, .crash, .leakProtectionFlag, .leakProtectionNotificationsFlag] + return [.stagingVersion, .customServers, .publicUsername, .username, .password, .environment, .resolveGoogleAdsDomain, .deleteKeychain, .crash, .leakProtectionFlag, .leakProtectionNotificationsFlag, .dynamicIslandLiveActivityFlag] } } diff --git a/PIA VPN/Settings/DevelopmentSettingsViewController.swift b/PIA VPN/Settings/DevelopmentSettingsViewController.swift index 3d0793ac5..91f746153 100644 --- a/PIA VPN/Settings/DevelopmentSettingsViewController.swift +++ b/PIA VPN/Settings/DevelopmentSettingsViewController.swift @@ -34,6 +34,7 @@ class DevelopmentSettingsViewController: PIABaseSettingsViewController { private lazy var switchEnvironment = UISwitch() private lazy var switchLeakProtectionFlag = UISwitch() private lazy var switchLeakProtectionNotificationsFlag = UISwitch() + private lazy var switchDynamicIslandLiveActivityFlag = UISwitch() private var controller: OptionsViewController? override func viewDidLoad() { @@ -150,18 +151,26 @@ extension DevelopmentSettingsViewController: UITableViewDelegate, UITableViewDat cell.textLabel?.text = "Crash" cell.detailTextLabel?.text = nil case .leakProtectionFlag: - cell.textLabel?.text = "FF - Leak Protection" - cell.detailTextLabel?.text = nil - cell.accessoryView = switchLeakProtectionFlag - cell.selectionStyle = .none + cell.textLabel?.text = "FF - Leak Protection" + cell.detailTextLabel?.text = nil + cell.accessoryView = switchLeakProtectionFlag + cell.selectionStyle = .none switchLeakProtectionFlag.isOn = AppPreferences.shared.showLeakProtection case .leakProtectionNotificationsFlag: - cell.textLabel?.text = "FF - Leak Protection Notifications" - cell.detailTextLabel?.text = nil - cell.accessoryView = switchLeakProtectionNotificationsFlag - cell.selectionStyle = .none + cell.textLabel?.text = "FF - Leak Protection Notifications" + cell.detailTextLabel?.text = nil + cell.accessoryView = switchLeakProtectionNotificationsFlag + cell.selectionStyle = .none switchLeakProtectionNotificationsFlag.isOn = AppPreferences.shared.showLeakProtectionNotifications + case .dynamicIslandLiveActivityFlag: + cell.textLabel?.text = "FF - Dynamic Island Live Activity" + cell.detailTextLabel?.text = nil + cell.accessoryView = switchDynamicIslandLiveActivityFlag + cell.selectionStyle = .none + switchDynamicIslandLiveActivityFlag.isOn = AppPreferences.shared.showDynamicIslandLiveActivity + } + } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -375,9 +384,14 @@ extension DevelopmentSettingsViewController { AppPreferences.shared.showLeakProtectionNotifications = sender.isOn } + @objc private func toggleDynamicIslandLiveActivityFlag(_ sender: UISwitch) { + AppPreferences.shared.showDynamicIslandLiveActivity = sender.isOn + } + private func addFeatureFlagsTogglesActions() { switchLeakProtectionFlag.addTarget(self, action: #selector(toggleLeakProtectionFlag(_:)), for: .valueChanged) switchLeakProtectionNotificationsFlag.addTarget(self, action: #selector(toggleLeakProtectionNotificationsFlag(_:)), for: .valueChanged) + switchDynamicIslandLiveActivityFlag.addTarget(self, action: #selector(toggleDynamicIslandLiveActivityFlag(_:)), for: .valueChanged) // Additional Feature Flags toggles actions here } diff --git a/PIA VPN/Settings/PrivacyFeaturesSettingsViewController.swift b/PIA VPN/Settings/PrivacyFeaturesSettingsViewController.swift index f6fe859bb..2639af4f9 100644 --- a/PIA VPN/Settings/PrivacyFeaturesSettingsViewController.swift +++ b/PIA VPN/Settings/PrivacyFeaturesSettingsViewController.swift @@ -45,7 +45,11 @@ class PrivacyFeaturesSettingsViewController: PIABaseSettingsViewController { preferences = AppPreferences.shared vpnProvider = Client.providers.vpnProvider - if let preferences = preferences, preferences.showLeakProtection { + // Show Leak protection settings when: + // - The feature flag is ON (`showLeakProtection`) + // - Wireguard or OpenVPN is NOT selected + if let preferences = preferences, preferences.showLeakProtection, + !isCurrentProtocolWireguardOrOpenVPN() { sections = PrivacyFeaturesSections.all() } else { sections = PrivacyFeaturesSections.all().filter { $0 != .leakProtection && $0 != .allowAccessOnLocalNetwork } @@ -321,3 +325,21 @@ extension PrivacyFeaturesSettingsViewController: UITableViewDelegate, UITableVie } } + + +extension PrivacyFeaturesSettingsViewController { + func isCurrentProtocolWireguardOrOpenVPN() -> Bool { + + // Selected protocol is OpenVPN + if pendingPreferences.vpnType == PIATunnelProfile.vpnType { + return true + } + + // Selected protocol is Wireguard + if pendingPreferences.vpnType == PIAWGTunnelProfile.vpnType { + return true + } + + return false + } +} diff --git a/PIA VPN/SwiftGen+Strings.swift b/PIA VPN/SwiftGen+Strings.swift index aa1043fa6..c22d791db 100644 --- a/PIA VPN/SwiftGen+Strings.swift +++ b/PIA VPN/SwiftGen+Strings.swift @@ -220,6 +220,12 @@ internal enum L10n { internal static let message = L10n.tr("Localizable", "dashboard.vpn.leakprotection.alert.message", fallback: "To prevent data leaks, tap Disable Now to turn off “Allow access to devices on local network\" and automatically reconnect.") /// Unsecured Wi-Fi detected internal static let title = L10n.tr("Localizable", "dashboard.vpn.leakprotection.alert.title", fallback: "Unsecured Wi-Fi detected") + internal enum IKEV2 { + /// Switch now + internal static let cta1 = L10n.tr("Localizable", "dashboard.vpn.leakprotection.ikev2.alert.cta1", fallback: "Switch Now") + /// To prevent data leaks, tap Switch Now to change to the IKEv2 VPN protocol and automatically reconnect. + internal static let message = L10n.tr("Localizable", "dashboard.vpn.leakprotection.ikev2.alert.message", fallback: "To prevent data leaks, tap Switch Now to change to the IKEv2 VPN protocol and automatically reconnect.") + } } } } @@ -1310,6 +1316,20 @@ internal enum L10n { } } } + + internal enum Widget { + internal enum LiveActivity { + internal enum SelectedProtocol { + /// Protocol + internal static let title = L10n.tr("Localizable", "widget.liveActivity.protocol.title", fallback: "Protocol") + } + internal enum Region { + /// Region + internal static let title = L10n.tr("Localizable", "widget.liveActivity.region.title", fallback: "Region") + } + } + } + } // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces diff --git a/PIA VPN/VPNPermissionViewController.swift b/PIA VPN/VPNPermissionViewController.swift index 922be68f7..a34176fa1 100644 --- a/PIA VPN/VPNPermissionViewController.swift +++ b/PIA VPN/VPNPermissionViewController.swift @@ -46,6 +46,7 @@ class VPNPermissionViewController: AutolayoutViewController { title = L10n.VpnPermission.title navigationItem.hidesBackButton = true + self.view.accessibilityIdentifier = AccessibilityId.VPNPermission.screen imvPicture.image = Asset.imageVpnAllow.image labelTitle.text = L10n.VpnPermission.Body.title @@ -112,7 +113,7 @@ class VPNPermissionViewController: AutolayoutViewController { buttonSubmit.style(style: TextStyle.Buttons.piaGreenButton) buttonSubmit.setTitle(L10n.Global.ok.uppercased(), for: []) - buttonSubmit.accessibilityIdentifier = Accessibility.Id.Permissions.submit + buttonSubmit.accessibilityIdentifier = AccessibilityId.VPNPermission.submit } } diff --git a/PIA VPN/ar.lproj/Localizable.strings b/PIA VPN/ar.lproj/Localizable.strings index 969fb18dc..f5d0448f2 100644 --- a/PIA VPN/ar.lproj/Localizable.strings +++ b/PIA VPN/ar.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "تجديد"; "expiration.message" = "سينتهي اشتراكك قريبًا. قم بتجديده لتبقى محميًا."; +"local_notification.non_compliant_wifi.title" = "واي فاي غير آمنة: %@"; +"local_notification.non_compliant_wifi.text" = "اضغط هنا لحماية جهازك"; + // SHORTCUTS "shortcuts.connect" = "اتصال"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "النسق النشط"; "settings.application_settings.kill_switch.title" = "مفتاح إيقاف VPN"; "settings.application_settings.kill_switch.footer" = "يؤدي استخدام مفتاح إيقاف VPN إلى تعطيل اتصالك بالإنترنت إذا كان الـ VPN في وضع إعادة الاتصال. لا ينطبق ذلك ذلك على الاتصال اليدوي."; +"settings.application_settings.leak_protection.title" = "حماية من تسريب المعلومات"; +"settings.application_settings.leak_protection.footer" = "يتضمن نظام iOS ميزات مصممة للعمل خارج شبكة VPN افتراضيًا مثل AirDrop و CarPlay و AirPlay ونقاط الاتصال الشخصية. يؤدي تمكين الحماية المخصصة من تسريب المعلومات إلى توجيه حركة البيانات عبر VPN ولكنه قد يؤثر على كيفية عمل هذه الميزات. المزيد من المعلومات"; +"settings.application_settings.leak_protection.more_info" = "المزيد من المعلومات"; +"settings.application_settings.allow_local_network.title" = "السماح بالوصول إلى الأجهزة الموجودة على الشبكة المحلية"; +"settings.application_settings.allow_local_network.footer" = "كن متصلًا بالأجهزة المحلية مثل الطابعات أو خوادم الملفات أثناء الاتصال بشبكة VPN. (اسمح بذلك فقط إذا كنت تثق في الأشخاص المتصلين بشبكتك والأجهزة التي عليها.)"; "settings.application_settings.mace.title" = "™PIA MACE"; "settings.application_settings.mace.footer" = "يحجب ™PIA MACE الإعلانات والمتعقبين والبرمجيات الضارة عندما تكون متصلًا بخدمة VPN."; +"settings.application_settings.leak_protection.alert.title" = "سيتم تفعيل التعديلات على إعدادات الـ VPN عند معاودة الاتصال"; "settings.content_blocker.title" = "حالة حظر المحتوى في Safari"; "settings.content_blocker.state.title" = "الحالة الحالية"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "زر اتصال VPN. خدمة VPN متصلة حاليًا"; "dashboard.accessibility.vpn.button.isOff" = "زر اتصال VPN. خدمة VPN غير متصلة حاليًا"; +"dashboard.vpn.leakprotection.alert.title" = "تم العثور على شبكة واي فاي غير آمنة"; +"dashboard.vpn.leakprotection.alert.message" = "لمنع تسريب البيانات، اضغط على تعطيل الآن لإغلاق \"السماح بالوصول إلى الأجهزة الموجودة على الشبكة المحلية\" وإعادة الاتصال تلقائيًا."; +"dashboard.vpn.leakprotection.alert.cta1" = "تعطيل الآن"; +"dashboard.vpn.leakprotection.alert.cta2" = "اعرف أكثر"; +"dashboard.vpn.leakprotection.alert.cta3" = "تجاهل"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "لمنع تسرب البيانات، اضغط على التبديل الآن للتغير إلى بروتوكول IKEv2 VPN وإعادة الاتصال تلقائيًا."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "التبديل الآن"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "إظهار رسائل اتصال الخدمة"; "inapp.messages.settings.updated" = "تم تحديث الإعدادات"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "المنطقة"; +"widget.liveActivity.protocol.title" = "البروتوكول"; diff --git a/PIA VPN/da.lproj/Localizable.strings b/PIA VPN/da.lproj/Localizable.strings index 1e53c5174..da4073046 100644 --- a/PIA VPN/da.lproj/Localizable.strings +++ b/PIA VPN/da.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Fornyelse"; "expiration.message" = "Dit abonnement udløber snart. Forny for at forblive beskyttet."; +"local_notification.non_compliant_wifi.title" = "Usikret wi-fi: %@"; +"local_notification.non_compliant_wifi.text" = "Tryk her for at sikre din enhed"; + // SHORTCUTS "shortcuts.connect" = "Forbind"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Aktivt tema"; "settings.application_settings.kill_switch.title" = "VPN-afbryderknap"; "settings.application_settings.kill_switch.footer" = "VPN-kill switchen forebygger kontakt til internettet, hvis VPN-forbindelsen genoprettes. Dette udelukker manuel frakobling."; +"settings.application_settings.leak_protection.title" = "Lækagebeskyttelse"; +"settings.application_settings.leak_protection.footer" = "iOS inkluderer funktioner designet til at fungere uden for VPN'et som standard, såsom AirDrop, CarPlay, AirPlay og personlige hotspots. Aktivering af tilpasset lækagebeskyttelse dirigerer denne trafik gennem VPN'et, men kan påvirke, hvordan disse funktioner fungerer. Mere info"; +"settings.application_settings.leak_protection.more_info" = "Mere info"; +"settings.application_settings.allow_local_network.title" = "Tillad adgang til enheder på det lokale netværk"; +"settings.application_settings.allow_local_network.footer" = "Hold forbindelsen til lokale enheder såsom printere eller filservere, mens du er tilsluttet til VPN'et. (Tillad kun dette, hvis du har tillid til personerne og enhederne på dit netværk.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blokerer annoncer, trackers og malware, mens du har forbindelse til VPN."; +"settings.application_settings.leak_protection.alert.title" = "Ændringer af VPN-indstillingerne træder i kraft ved næste forbindelse"; "settings.content_blocker.title" = "Safari Indholdsblokeringstilstand"; "settings.content_blocker.state.title" = "Aktuel status"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN-forbindelse-knap. VPN er i øjeblikket forbundet"; "dashboard.accessibility.vpn.button.isOff" = "VPN-forbindelse-knap. VPN er i øjeblikket afbrudt"; +"dashboard.vpn.leakprotection.alert.title" = "Usikret wi-fi registreret"; +"dashboard.vpn.leakprotection.alert.message" = "For at forhindre datalækage skal du trykke på Deaktiver nu for at deaktivere \"Tillad adgang til enheder på det lokale netværk\" og automatisk oprette forbindelse igen."; +"dashboard.vpn.leakprotection.alert.cta1" = "Deaktiver nu"; +"dashboard.vpn.leakprotection.alert.cta2" = "Få flere oplysninger"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorer"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "For at forhindre datalækage skal du trykke på Skift nu for at skifte til IKEv2 VPN-protokollen og automatisk oprette forbindelse igen."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Skift nu"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Vis servicekommunikationsmeddelelser"; "inapp.messages.settings.updated" = "Indstillinger er blevet opdateret"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Region"; +"widget.liveActivity.protocol.title" = "Protokol"; diff --git a/PIA VPN/de.lproj/Localizable.strings b/PIA VPN/de.lproj/Localizable.strings index 3ad30822c..e5ec3a0d7 100644 --- a/PIA VPN/de.lproj/Localizable.strings +++ b/PIA VPN/de.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Verlängerung"; "expiration.message" = "Dein Abonnement endet bald. Verlängere deinen Schutz."; +"local_notification.non_compliant_wifi.title" = "Ungesichertes WLAN: %@"; +"local_notification.non_compliant_wifi.text" = "Tippe hier, um dein Gerät zu schützen"; + // SHORTCUTS "shortcuts.connect" = "Verbinden"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Aktives Theme"; "settings.application_settings.kill_switch.title" = "VPN-Killswitch"; "settings.application_settings.kill_switch.footer" = "Der VPN-Notausschalter unterbricht den Internetzugang, wenn die VPN-Verbindung neu aufgebaut wird. Dies schließt manuelles Trennen aus."; +"settings.application_settings.leak_protection.title" = "Schutz vor Datenlecks"; +"settings.application_settings.leak_protection.footer" = "iOS enthält Funktionen, die standardmäßig außerhalb des VPNs funktionieren, wie AirDrop, CarPlay, AirPlay und „Persönliche Hotspots“. Die Aktivierung des benutzerdefinierten Schutzes vor Datenlecks leitet diesen Datenverkehr durch das VPN, kann aber die Funktionsweise dieser Funktionen beeinträchtigen. Weitere Informationen"; +"settings.application_settings.leak_protection.more_info" = "Weitere Informationen"; +"settings.application_settings.allow_local_network.title" = "Zugriff auf Geräte im lokalen Netzwerk erlauben"; +"settings.application_settings.allow_local_network.footer" = "Die Verbindung zu lokalen Geräten wie Druckern oder Dateiservern während einer Verbindung zum VPN halten. (Erlaube dies nur, wenn du den Personen und Geräten in deinem Netzwerk vertraust.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blockiert Werbung, Tracker und Malware bei aktiver VPN-Verbindung."; +"settings.application_settings.leak_protection.alert.title" = "Änderungen an den VPN-Einstellungen werden bei der nächsten Verbindung aktiv"; "settings.content_blocker.title" = "Status Inhalts-Blocker für Safari"; "settings.content_blocker.state.title" = "Aktueller Status"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN-Verbindungs-Schaltfläche. VPN derzeit verbunden"; "dashboard.accessibility.vpn.button.isOff" = "VPN-Verbindungs-Schaltfläche. VPN derzeit nicht verbunden"; +"dashboard.vpn.leakprotection.alert.title" = "Ungesichertes WLAN erkannt"; +"dashboard.vpn.leakprotection.alert.message" = "Um Datenlecks zu verhindern, tippe auf „Jetzt deaktivieren“, um „Zugriff auf Geräte im lokalen Netzwerk erlauben“ zu deaktivieren und automatisch erneut eine Verbindung herzustellen."; +"dashboard.vpn.leakprotection.alert.cta1" = "Jetzt deaktivieren"; +"dashboard.vpn.leakprotection.alert.cta2" = "Mehr erfahren"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorieren"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Um Datenlecks zu verhindern, tippe auf „Jetzt wechseln“, um zum IKEv2 VPN-Protokoll zu wechseln und automatisch erneut eine Verbindung herzustellen."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Jetzt wechseln"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Meldungen der Servicekommunikation anzeigen"; "inapp.messages.settings.updated" = "Die Einstellungen wurden aktualisiert"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Region"; +"widget.liveActivity.protocol.title" = "Protokoll"; diff --git a/PIA VPN/en.lproj/Localizable.strings b/PIA VPN/en.lproj/Localizable.strings index 8d0c2ac64..489233b1a 100644 --- a/PIA VPN/en.lproj/Localizable.strings +++ b/PIA VPN/en.lproj/Localizable.strings @@ -230,6 +230,9 @@ "dashboard.vpn.leakprotection.alert.cta2" = "Learn more"; "dashboard.vpn.leakprotection.alert.cta3" = "Ignore"; +"dashboard.vpn.leakprotection.ikev2.alert.message" = "To prevent data leaks, tap Switch Now to change to the IKEv2 VPN protocol and automatically reconnect."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Switch Now"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -431,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Show Service Communication Messages"; "inapp.messages.settings.updated" = "Settings have been updated"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Region"; +"widget.liveActivity.protocol.title" = "Protocol"; diff --git a/PIA VPN/es-MX.lproj/Localizable.strings b/PIA VPN/es-MX.lproj/Localizable.strings index f55860ac2..3e646e38d 100644 --- a/PIA VPN/es-MX.lproj/Localizable.strings +++ b/PIA VPN/es-MX.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Renovación"; "expiration.message" = "Tu suscripción expira pronto. Renueva para estar protegido."; +"local_notification.non_compliant_wifi.title" = "Wifi no protegida: %@"; +"local_notification.non_compliant_wifi.text" = "Toca aquí para proteger el dispositivo"; + // SHORTCUTS "shortcuts.connect" = "Conectar"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Activar tema"; "settings.application_settings.kill_switch.title" = "Interruptor de corte de VPN"; "settings.application_settings.kill_switch.footer" = "El botón de pánico de VPN evita el acceso a Internet si la conexión VPN se está volviendo a conectar. Esto excluye la desconexión manual."; +"settings.application_settings.leak_protection.title" = "Protección contra filtraciones"; +"settings.application_settings.leak_protection.footer" = "iOS incluye funciones diseñadas para operar fuera de la VPN por omisión, como AirDrop, CarPlay, AirPlay y los puntos de acceso personales. Habilitar la protección personalizada contra las filtraciones dirige este tráfico a través de la VPN, pero puede afectar a su funcionamiento. Más información"; +"settings.application_settings.leak_protection.more_info" = "Más información"; +"settings.application_settings.allow_local_network.title" = "Permitir acceso a dispositivos de la red local"; +"settings.application_settings.allow_local_network.footer" = "Mantente conectado a dispositivos locales como impresoras o servidores de archivos mientras estés conectado a la VPN. (Solo debes permitirlo si confías en las personas y los dispositivos de tu red.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ bloquea publicidad, rastreadores y malware mientras estás conectado a la VPN."; +"settings.application_settings.leak_protection.alert.title" = "Los cambios en la configuración de la VPN tendrán efecto en la próxima conexión"; "settings.content_blocker.title" = "Estado del bloqueador de contenido de Safari"; "settings.content_blocker.state.title" = "Estado actual"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Botón de conexión de VPN. La VPN está conectada en este momento."; "dashboard.accessibility.vpn.button.isOff" = "Botón de conexión de VPN. La VPN está desconectada en este momento."; +"dashboard.vpn.leakprotection.alert.title" = "Detectada red wifi no protegida"; +"dashboard.vpn.leakprotection.alert.message" = "Para evitar filtraciones de datos, toca en \"Desactivar ahora\" para desactivar la opción \"Permitir acceso a dispositivos de la red local\" y restablecer la conexión automáticamente."; +"dashboard.vpn.leakprotection.alert.cta1" = "Desactivar ahora"; +"dashboard.vpn.leakprotection.alert.cta2" = "Más información"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorar"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Para evitar las filtraciones de datos, toca en \"Cambiar ahora\" para cambiar al protocolo VPN IKEv2 y restablecer la conexión automáticamente."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Cambiar ahora"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Mostrar mensajes de comunicación de servicio"; "inapp.messages.settings.updated" = "Se actualizaron los ajustes"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Región"; +"widget.liveActivity.protocol.title" = "Protocolo"; diff --git a/PIA VPN/fr.lproj/Localizable.strings b/PIA VPN/fr.lproj/Localizable.strings index ad9c5c439..b2d8e6082 100644 --- a/PIA VPN/fr.lproj/Localizable.strings +++ b/PIA VPN/fr.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Renouvellement"; "expiration.message" = "Votre adhésion expire bientôt. Renouvelez pour rester protégé."; +"local_notification.non_compliant_wifi.title" = "Wi-Fi non sécurisé : %@"; +"local_notification.non_compliant_wifi.text" = "Appuyez ici pour sécuriser votre appareil"; + // SHORTCUTS "shortcuts.connect" = "Se connecter"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Thème actif"; "settings.application_settings.kill_switch.title" = "Killswitch du VPN"; "settings.application_settings.kill_switch.footer" = "Le killswitch du VPN empêche l'accès à Internet si la connexion VPN est en cours de reconnexion. Cela exclut la déconnexion manuelle."; +"settings.application_settings.leak_protection.title" = "Protection contre les fuites de données"; +"settings.application_settings.leak_protection.footer" = "iOS comprend des fonctionnalités conçues pour opérer par défaut en dehors du VPN, comme AirDrop, CarPlay, AirPlay et le partage de connexion. L’activation de la protection personnalisée contre les fuites de données achemine ce trafic à travers le VPN, mais risque de perturber ces fonctionnalités. En savoir plus"; +"settings.application_settings.leak_protection.more_info" = "En savoir plus"; +"settings.application_settings.allow_local_network.title" = "Autoriser l’accès aux appareils sur le réseau local"; +"settings.application_settings.allow_local_network.footer" = "Restez connecté aux appareils locaux tels que les imprimantes ou les serveurs de fichiers tout en étant connecté au VPN. (N’accordez cette autorisation que si vous faites confiance aux personnes et aux appareils de votre réseau.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ bloque les publicités, les traqueurs et les logiciels malveillants quand vous êtes connecté au VPN."; +"settings.application_settings.leak_protection.alert.title" = "Les modifications apportées aux réglages VPN prendront effet à la prochaine connexion"; "settings.content_blocker.title" = "État du bloqueur de contenu Safari"; "settings.content_blocker.state.title" = "État actuel"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Bouton de connexion VPN. Le VPN est actuellement connecté"; "dashboard.accessibility.vpn.button.isOff" = "Bouton de connexion VPN. Le VPN est actuellement déconnecté"; +"dashboard.vpn.leakprotection.alert.title" = "Wi-Fi non sécurisé détecté"; +"dashboard.vpn.leakprotection.alert.message" = "Pour éviter les fuites de données, appuyez sur « Désactiver » afin de désactiver l’option « Autoriser l’accès aux appareils sur le réseau local » et permettre la reconnexion automatique."; +"dashboard.vpn.leakprotection.alert.cta1" = "Désactiver"; +"dashboard.vpn.leakprotection.alert.cta2" = "En savoir plus"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorer"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Pour éviter les fuites de données, appuyez sur « Changer » afin de passer au protocole VPN IKEv2 et de permettre la reconnexion automatique."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Changer"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Afficher les messages de communication de service"; "inapp.messages.settings.updated" = "Les paramètres ont été mis à jour"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Région"; +"widget.liveActivity.protocol.title" = "Protocole"; diff --git a/PIA VPN/it.lproj/Localizable.strings b/PIA VPN/it.lproj/Localizable.strings index fa8d23a0c..5fef616f0 100644 --- a/PIA VPN/it.lproj/Localizable.strings +++ b/PIA VPN/it.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Rinnovo"; "expiration.message" = "Il tuo abbonamento scade presto. Rinnovalo per mantenere la protezione."; +"local_notification.non_compliant_wifi.title" = "Wi-Fi non protetto: %@"; +"local_notification.non_compliant_wifi.text" = "Tocca qui per proteggere il tuo dispositivo"; + // SHORTCUTS "shortcuts.connect" = "Connetti"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Tema attivo"; "settings.application_settings.kill_switch.title" = "Killswitch VPN"; "settings.application_settings.kill_switch.footer" = "Il killswitch VPN impedisce l'accesso a Internet quando la connessione VPN si sta riconnettendo. Questo esclude la disconnessione manuale."; +"settings.application_settings.leak_protection.title" = "Protezione perdita dati"; +"settings.application_settings.leak_protection.footer" = "iOS include funzioni per operare di default al di fuori della VPN, come AirDrop, CarPlay, AirPlay e hotspot personali. L’attivazione di una protezione personalizzata contro la perdita dei dati instrada questo traffico attraverso la VPN, ma può influire su queste funzioni. Ulteriori informazioni"; +"settings.application_settings.leak_protection.more_info" = "Ulteriori informazioni"; +"settings.application_settings.allow_local_network.title" = "Consenti l’accesso ai dispositivi sulla rete locale"; +"settings.application_settings.allow_local_network.footer" = "Rimani connesso ai dispositivi locali come stampanti o file server durante la connessione alla VPN. (Consenti solo se ti fidi delle persone e dei dispositivi sulla rete.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blocca pubblicità, tracker e malware mentre sei connesso alla VPN."; +"settings.application_settings.leak_protection.alert.title" = "Le modifiche alle impostazioni della VPN avranno effetto alla prossima connessione"; "settings.content_blocker.title" = "Stato di blocco contenuti Safari"; "settings.content_blocker.state.title" = "Stato corrente"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Pulsante di connessione VPN. VPN attualmente connesso"; "dashboard.accessibility.vpn.button.isOff" = "Pulsante di connessione VPN. VPN attualmente disconnesso"; +"dashboard.vpn.leakprotection.alert.title" = "Rilevato Wi-Fi non sicuro"; +"dashboard.vpn.leakprotection.alert.message" = "Per prevenire perdite di dati, tocca Disabilita ora per disattivare “Consenti l’accesso ai dispositivi sulla rete locale“ e riconnettersi automaticamente."; +"dashboard.vpn.leakprotection.alert.cta1" = "Disabilita ora"; +"dashboard.vpn.leakprotection.alert.cta2" = "Ulteriori informazioni"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignora"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Per prevenire le perdite di dati, tocca Cambia ora per passare al protocollo VPN IKEv2 e riconnettersi automaticamente."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Cambia ora"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Mostra i messaggi di comunicazione sul servizio"; "inapp.messages.settings.updated" = "Impostazioni aggiornate"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Area"; +"widget.liveActivity.protocol.title" = "Protocollo"; diff --git a/PIA VPN/ja.lproj/Localizable.strings b/PIA VPN/ja.lproj/Localizable.strings index 468ed7676..fea22e5db 100644 --- a/PIA VPN/ja.lproj/Localizable.strings +++ b/PIA VPN/ja.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "更新"; "expiration.message" = "ご利用のサブスクリプションがもうすぐ期限切れとなります。更新して保護された状態を保ちましょう。"; +"local_notification.non_compliant_wifi.title" = "保護されていないWiFi:%@"; +"local_notification.non_compliant_wifi.text" = "お使いのデバイスを保護するには、ここをタップしてください"; + // SHORTCUTS "shortcuts.connect" = "接続"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "アクティブなテーマ"; "settings.application_settings.kill_switch.title" = "VPNキルスイッチ"; "settings.application_settings.kill_switch.footer" = "VPNキルスイッチは、VPNの再接続時にインターネット接続を無効にします。これには手動での切断が含まれません。"; +"settings.application_settings.leak_protection.title" = "漏えい防止"; +"settings.application_settings.leak_protection.footer" = "iOSには、デフォルトでAirDrop、CarPlay、AirPlay、パーソナルホットスポットなど、VPNの外部で動作するように設計された機能が含まれています。カスタムリーク保護機能を有効にすると、このトラフィックはVPN経由でルーティングされますが、これらの機能の動作に影響する可能性があります。詳細"; +"settings.application_settings.leak_protection.more_info" = "詳細"; +"settings.application_settings.allow_local_network.title" = "ローカルネットワーク内のデバイスへのアクセスを許可"; +"settings.application_settings.allow_local_network.footer" = "VPNに接続している間、プリンタやファイルサーバーなどのローカルデバイスへの接続を維持できます(ネットワーク内のユーザーとデバイスを信頼できる場合にのみ許可してください。)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™はVPNに接続されている間、広告、閲覧行動の追跡、そしてマルウェアをブロックします。"; +"settings.application_settings.leak_protection.alert.title" = "VPN設定への変更は次回の接続時に反映されます"; "settings.content_blocker.title" = "Safariコンテンツブロッカーの状態"; "settings.content_blocker.state.title" = "現在の状況"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN接続ボタン。VPNに現在接続されています"; "dashboard.accessibility.vpn.button.isOff" = "VPN接続ボタン。VPNは現在切断されています"; +"dashboard.vpn.leakprotection.alert.title" = "保護されていないWiFiが検出されました"; +"dashboard.vpn.leakprotection.alert.message" = "データ漏洩を防ぐには、[今すぐ無効にする]をタップして[ローカルネットワーク内のデバイスへのアクセスを許可]をオフにし、自動的に再接続してください。"; +"dashboard.vpn.leakprotection.alert.cta1" = "今すぐ無効にする"; +"dashboard.vpn.leakprotection.alert.cta2" = "詳細"; +"dashboard.vpn.leakprotection.alert.cta3" = "無視"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "データ漏洩を防ぐには、[今すぐ切り替える]をタップしてIKEv2 VPNプロトコルに変更し、自動的に再接続してください。"; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "今すぐ切り替える"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "サービス通信メッセージを表示"; "inapp.messages.settings.updated" = "設定が更新されました"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "地域"; +"widget.liveActivity.protocol.title" = "プロトコル"; diff --git a/PIA VPN/ko.lproj/Localizable.strings b/PIA VPN/ko.lproj/Localizable.strings index c156af612..029680fff 100644 --- a/PIA VPN/ko.lproj/Localizable.strings +++ b/PIA VPN/ko.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "갱신"; "expiration.message" = "구독이 곧 만료됩니다. 갱신하여 계속 보호를 받으세요."; +"local_notification.non_compliant_wifi.title" = "비보안 Wi-Fi: %@"; +"local_notification.non_compliant_wifi.text" = "장치를 보호하려면 여기를 누르세요."; + // SHORTCUTS "shortcuts.connect" = "연결"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "활성화된 테마"; "settings.application_settings.kill_switch.title" = "VPN 킬 스위치"; "settings.application_settings.kill_switch.footer" = "VPN 킬 스위치는 VPN 연결이 다시 연결 중이면 인터넷에 대한 액세스를 방지합니다. 수동으로 연결을 해제하는 경우는 제외입니다."; +"settings.application_settings.leak_protection.title" = "보호 누출"; +"settings.application_settings.leak_protection.footer" = "iOS에는 기본적으로 AirDrop, CarPlay, AirPlay, 개인 핫스팟과 같이 VPN 외부에서 작동하도록 설계된 기능이 포함됩니다. 사용자 지정 누출 보호를 활성화하면 이 트래픽이 VPN을 통해 라우팅되지만 이러한 기능의 작동 방식에 영향을 줄 수 있습니다. 자세히 알아보기"; +"settings.application_settings.leak_protection.more_info" = "자세히 알아보기"; +"settings.application_settings.allow_local_network.title" = "로컬 네트워크의 장치 액세스 허용"; +"settings.application_settings.allow_local_network.footer" = "VPN에 연결된 상태에서 프린터 또는 파일 서버와 같은 로컬 장치 연결을 유지하세요. (네트워크의 사용자 및 장치를 신뢰하는 경우에만 이 옵션 허용)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™는 VPN에 연결되어 있을 때 광고, 트래커 및 악성코드를 차단합니다."; +"settings.application_settings.leak_protection.alert.title" = "VPN 설정을 변경하면 다음에 연결할 때 적용됩니다."; "settings.content_blocker.title" = "Safari 콘텐츠 차단기 상태"; "settings.content_blocker.state.title" = "현재 상태"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN 연결 버튼. VPN이 현재 연결되었습니다"; "dashboard.accessibility.vpn.button.isOff" = "VPN 연결 버튼. VPN이 현재 연결 해제되었습니다"; +"dashboard.vpn.leakprotection.alert.title" = "안전하지 않은 Wi-Fi 감지됨"; +"dashboard.vpn.leakprotection.alert.message" = "데이터 누출을 방지하려면 지금 비활성화를 눌러서 \"로컬 네트워크의 장치 액세스 허용\"을 해제하고 자동으로 다시 연결하세요."; +"dashboard.vpn.leakprotection.alert.cta1" = "지금 비활성화"; +"dashboard.vpn.leakprotection.alert.cta2" = "자세히 알아보기"; +"dashboard.vpn.leakprotection.alert.cta3" = "무시"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "데이터 누출을 방지하려면 지금 전환을 눌러서 IKEv2 VPN 프로토콜로 변경하고 자동으로 다시 연결하세요."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "지금 전환"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "서비스 통신 메시지 표시"; "inapp.messages.settings.updated" = "설정이 업데이트되었습니다"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "지역"; +"widget.liveActivity.protocol.title" = "프로토콜"; diff --git a/PIA VPN/nb.lproj/Localizable.strings b/PIA VPN/nb.lproj/Localizable.strings index 22237a276..bed2092a0 100644 --- a/PIA VPN/nb.lproj/Localizable.strings +++ b/PIA VPN/nb.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Forny"; "expiration.message" = "Abonnementet ditt utløper snart. Forny det for å forbli beskyttet."; +"local_notification.non_compliant_wifi.title" = "Usikret WiFi:%@"; +"local_notification.non_compliant_wifi.text" = "Trykk her for å sikre enheten din"; + // SHORTCUTS "shortcuts.connect" = "Koble til"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Aktivt tema"; "settings.application_settings.kill_switch.title" = "Kill switch for VPN"; "settings.application_settings.kill_switch.footer" = "Kill switch for VPN hindrer tilgang til Internett hvis VPN-tilkoblingen mister forbindelsen og prøver å koble til igjen. Dette ekskluderer manuell frakobling."; +"settings.application_settings.leak_protection.title" = "Lekkasjebeskyttelse"; +"settings.application_settings.leak_protection.footer" = "iOS har funksjoner som er utviklet for å fungere utenfor VPN-et, for eksempel AirDrop, CarPlay, AirPlay og delt Internett. Ved å aktivere tilpasset lekkasjebeskyttelse kan du rute denne trafikken gjennom VPN-et, men det kan påvirke hvordan disse funksjonene fungerer. Mer informasjon"; +"settings.application_settings.leak_protection.more_info" = "Mer informasjon"; +"settings.application_settings.allow_local_network.title" = "Tillat tilgang til enheter på lokalnettverk"; +"settings.application_settings.allow_local_network.footer" = "Behold tilgang til lokale enheter som skrivere eller filservere mens du er koblet til VPN-et. (Tillat dette bare hvis du stoler på personene og enhetene på nettverket ditt.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blokkerer reklamer, sporere og skadelig programvare når du er koblet til VPN-en."; +"settings.application_settings.leak_protection.alert.title" = "Endringer i VPN-innstillingene vil tre i kraft ved neste tilkobling"; "settings.content_blocker.title" = "Safari Innholdsblokkerer – status"; "settings.content_blocker.state.title" = "Gjeldene status"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN-tilkoblingsknapp. VPN-klienten er for øyeblikket tilkoblet"; "dashboard.accessibility.vpn.button.isOff" = "VPN-tilkoblingsknapp. VPN-klienten er for øyeblikket frakoblet"; +"dashboard.vpn.leakprotection.alert.title" = "Usikret WiFi oppdaget"; +"dashboard.vpn.leakprotection.alert.message" = "For å hindre datalekkasjer trykker du på Deaktiver nå for å slå av \"Tillat tillat tilgang til enheter på lokalnettverk\" og automatisk koble til på nytt."; +"dashboard.vpn.leakprotection.alert.cta1" = "Deaktiver nå"; +"dashboard.vpn.leakprotection.alert.cta2" = "Les mer"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorer"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "For å hindre datalekkasjer trykker du på Bytt nå for å bytte til VPN-protokollen IKEv2 og automatisk koble til på nytt."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Bytt nå"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Vis tjenestekommunikasjonsmeldinger"; "inapp.messages.settings.updated" = "Innstillingene ble oppdatert"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Region"; +"widget.liveActivity.protocol.title" = "Protokoll"; diff --git a/PIA VPN/nl.lproj/Localizable.strings b/PIA VPN/nl.lproj/Localizable.strings index f1f62738f..c6153cfd9 100644 --- a/PIA VPN/nl.lproj/Localizable.strings +++ b/PIA VPN/nl.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Vernieuwing"; "expiration.message" = "Uw abonnement verloopt binnenkort. Vernieuw uw abonnement om beschermd te blijven."; +"local_notification.non_compliant_wifi.title" = "Onbeveiligde wifi: %@"; +"local_notification.non_compliant_wifi.text" = "Tik hier om je apparaat te beschermen"; + // SHORTCUTS "shortcuts.connect" = "Verbinden"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Actief thema"; "settings.application_settings.kill_switch.title" = "VPN-killswitch"; "settings.application_settings.kill_switch.footer" = "De VPN kill switch voorkomt toegang tot internet als de VPN-verbinding opnieuw tot stand wordt gebracht. Dit geldt niet wanneer de verbinding handmatig wordt verbroken."; +"settings.application_settings.leak_protection.title" = "Lekbescherming"; +"settings.application_settings.leak_protection.footer" = "iOS bevat functies die ontworpen zijn om standaard te werken buiten het VPN, zoals AirDrop, CarPlay, AirPlay en persoonlijke hotspots. Het inschakelen van aangepaste lekbescherming leidt dit verkeer om via het VPN, maar kan de werking van deze functies beïnvloeden. Meer info"; +"settings.application_settings.leak_protection.more_info" = "Meer info"; +"settings.application_settings.allow_local_network.title" = "Sta toegang toe tot apparaten op een lokaal netwerk"; +"settings.application_settings.allow_local_network.footer" = "Blijf verbonden met lokale apparaten, zoals printers of bestandsservers die verbonden zijn met het VPN. (Sta dit alleen toe als je de personen en apparaten op je netwerk vertrouwt.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blokkeert advertenties, trackers en malware als u met de VPN bent verbonden."; +"settings.application_settings.leak_protection.alert.title" = "Wijzigingen aan de VPN-instellingen worden van kracht bij de volgende verbinding"; "settings.content_blocker.title" = "Status Safari Content Blocker"; "settings.content_blocker.state.title" = "Huidige status"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN-verbindingsknop. De VPN is verbonden"; "dashboard.accessibility.vpn.button.isOff" = "VPN-verbindingsknop. De VPN is niet verbonden"; +"dashboard.vpn.leakprotection.alert.title" = "Onbeveiligde wifi gedetecteerd"; +"dashboard.vpn.leakprotection.alert.message" = "Om gegevenslekken te voorkomen, tik je op \"Schakel nu uit\" om \"Sta toegang toe tot apparaten op een lokaal netwerk\" uit te schakelen en automatisch opnieuw verbinding te maken."; +"dashboard.vpn.leakprotection.alert.cta1" = "Schakel nu uit"; +"dashboard.vpn.leakprotection.alert.cta2" = "Meer informatie"; +"dashboard.vpn.leakprotection.alert.cta3" = "Negeer"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Om gegevenslekken te voorkomen, tik je op \"Schakel nu\" om te wijzigen naar het IKEv2 VPN-protocol en automatisch opnieuw verbinding te maken."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Schakel nu"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Service-communicatieberichten weergeven"; "inapp.messages.settings.updated" = "De instellingen zijn bijgewerkt"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Regio"; +"widget.liveActivity.protocol.title" = "Protocol"; diff --git a/PIA VPN/pl.lproj/Localizable.strings b/PIA VPN/pl.lproj/Localizable.strings index fe3905363..2e2f5fd85 100644 --- a/PIA VPN/pl.lproj/Localizable.strings +++ b/PIA VPN/pl.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Odnowienie"; "expiration.message" = "Twoja subskrypcja wkrótce wygasa. Odnów ją, aby utrzymać ochronę."; +"local_notification.non_compliant_wifi.title" = "Niezabezpieczona sieć Wi-Fi: %@"; +"local_notification.non_compliant_wifi.text" = "Dotknij tutaj, aby zabezpieczyć urządzenie"; + // SHORTCUTS "shortcuts.connect" = "Połącz"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Aktywny motyw"; "settings.application_settings.kill_switch.title" = "Wyłącznik awaryjny VPN"; "settings.application_settings.kill_switch.footer" = "Wyłącznik awaryjny VPN zapobiega dostępowi do internetu, jeśli połączenie VPN jest nawiązywane ponownie. Nie obejmuje to ręcznego rozłączenia."; +"settings.application_settings.leak_protection.title" = "Ochrona przed wyciekami"; +"settings.application_settings.leak_protection.footer" = "iOS zawiera funkcje zaprojektowane domyślnie do działania poza VPN, takie jak AirDrop, CarPlay, AirPlay i osobiste hotspoty. Włączenie niestandardowej ochrony przed wyciekiem kieruje ten ruch przez VPN, ale może wpłynąć na działanie tych funkcji. Więcej informacji"; +"settings.application_settings.leak_protection.more_info" = "Więcej informacji"; +"settings.application_settings.allow_local_network.title" = "Zezwól na dostęp do urządzeń w sieci lokalnej"; +"settings.application_settings.allow_local_network.footer" = "Pozostań w kontakcie z lokalnymi urządzeniami, takimi jak drukarki lub serwery plików, podczas połączenia z VPN. (Zezwalaj na to tylko wtedy, gdy ufasz osobom i urządzeniom w Twojej sieci)."; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ blokuje reklamy, programy śledzące i złośliwe oprogramowanie w czasie połączenia przez VPN."; +"settings.application_settings.leak_protection.alert.title" = "Zmiany w Ustawieniach VPN zostaną zastosowane przy kolejnym nawiązaniu połączenia"; "settings.content_blocker.title" = "Stan blokady zawartości Safari"; "settings.content_blocker.state.title" = "Bieżący stan"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Przycisk połączenia z VPN. VPN jest teraz podłączona."; "dashboard.accessibility.vpn.button.isOff" = "Przycisk połączenia z VPN. VPN jest teraz odłączona."; +"dashboard.vpn.leakprotection.alert.title" = "Wykryto niezabezpieczoną sieć Wi-Fi"; +"dashboard.vpn.leakprotection.alert.message" = "Aby zapobiec wyciekom danych, dotknij Wyłącz teraz, aby wyłączyć opcję „Zezwól na dostęp do urządzeń w sieci lokalnej” i automatycznie połączyć się ponownie."; +"dashboard.vpn.leakprotection.alert.cta1" = "Wyłącz teraz"; +"dashboard.vpn.leakprotection.alert.cta2" = "Dowiedz się więcej"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignoruj"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Aby zapobiec wyciekom danych, dotknij opcji Przełącz teraz, aby zmienić protokół na IKEv2 VPN i automatycznie połączyć się ponownie."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Przełącz teraz"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Pokaż komunikaty dotyczące komunikacji usługi"; "inapp.messages.settings.updated" = "Zaktualizowano ustawienia"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Region"; +"widget.liveActivity.protocol.title" = "Protokół"; diff --git a/PIA VPN/pt-BR.lproj/Localizable.strings b/PIA VPN/pt-BR.lproj/Localizable.strings index 470b23c15..c4fa37acd 100644 --- a/PIA VPN/pt-BR.lproj/Localizable.strings +++ b/PIA VPN/pt-BR.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Renovação"; "expiration.message" = "Sua assinatura expirará em breve. Renove para continuar protegido."; +"local_notification.non_compliant_wifi.title" = "Wi-Fi não seguro: %@"; +"local_notification.non_compliant_wifi.text" = "Toque aqui para proteger seu dispositivo"; + // SHORTCUTS "shortcuts.connect" = "Conectar"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Tema ativo"; "settings.application_settings.kill_switch.title" = "Kill switch de VPN"; "settings.application_settings.kill_switch.footer" = "O kill switch do VPN impede o acesso à internet se a conexão de VPN estiver se reconectando. Isto exclui a desconexão manual."; +"settings.application_settings.leak_protection.title" = "Proteção contra vazamentos"; +"settings.application_settings.leak_protection.footer" = "O iOS inclui recursos projetados para operar fora da VPN por padrão, como AirDrop, CarPlay, AirPlay e Acesso Pessoal. A ativação da proteção personalizada contra vazamentos roteia esse tráfego por meio da VPN, mas pode afetar o funcionamento desses recursos. Mais informações"; +"settings.application_settings.leak_protection.more_info" = "Mais informações"; +"settings.application_settings.allow_local_network.title" = "Permitir acesso a dispositivos na rede local"; +"settings.application_settings.allow_local_network.footer" = "Permaneça conectado a dispositivos locais, como impressoras ou servidores de arquivos, enquanto estiver conectado à VPN. (Permita essa opção apenas se você confiar nas pessoas e nos dispositivos da sua rede.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "O PIA MACE™ bloqueia anúncios, rastreadores e malware enquanto você está conectado à VPN."; +"settings.application_settings.leak_protection.alert.title" = "As alterações nas configurações da VPN entrarão em vigor na próxima conexão"; "settings.content_blocker.title" = "Status do bloqueador de conteúdo do Safari"; "settings.content_blocker.state.title" = "Situação atual"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Botão de conexão da VPN. A VPN está conectada no momento."; "dashboard.accessibility.vpn.button.isOff" = "Botão de conexão da VPN. A VPN está desconectada no momento."; +"dashboard.vpn.leakprotection.alert.title" = "Wi-Fi não seguro detectado"; +"dashboard.vpn.leakprotection.alert.message" = "Para evitar vazamentos de dados, toque em “Desabilitar agora” para desativar a opção “Permitir acesso a dispositivos na rede local” e reconectar automaticamente."; +"dashboard.vpn.leakprotection.alert.cta1" = "Desabilitar agora"; +"dashboard.vpn.leakprotection.alert.cta2" = "Saiba mais"; +"dashboard.vpn.leakprotection.alert.cta3" = "Ignorar"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Para evitar vazamentos de dados, toque em “Alternar agora” para mudar para o protocolo VPN IKEv2 e reconectar automaticamente."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Alternar agora"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Mostrar mensagens de comunicação de serviço"; "inapp.messages.settings.updated" = "As configurações foram atualizadas"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Região"; +"widget.liveActivity.protocol.title" = "Protocolo"; diff --git a/PIA VPN/ru.lproj/Localizable.strings b/PIA VPN/ru.lproj/Localizable.strings index f81c82060..b5e47cc79 100644 --- a/PIA VPN/ru.lproj/Localizable.strings +++ b/PIA VPN/ru.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "Продление"; "expiration.message" = "Срок действия подписки истекает в ближайшее время. Продлите подписку, чтобы не потерять защиту."; +"local_notification.non_compliant_wifi.title" = "Незащищенная сеть Wi-Fi: %@"; +"local_notification.non_compliant_wifi.text" = "Нажмите здесь, чтобы защитить ваше устройство"; + // SHORTCUTS "shortcuts.connect" = "Подключиться"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "Активная тема"; "settings.application_settings.kill_switch.title" = "Авторазрыв соединения"; "settings.application_settings.kill_switch.footer" = "Функция авторазрыва соединения рвет Интернет-соединение при отключении VPN. Она не срабатывает при ручном отключении VPN."; +"settings.application_settings.leak_protection.title" = "Защита от утечек"; +"settings.application_settings.leak_protection.footer" = "iOS включает функции, по умолчанию предназначенные для работы вне VPN, такие как AirDrop, CarPlay, AirPlay и Персональная точка доступа. Включение защиты от утечек перенаправляет этот трафик через VPN, но может отразиться на работе этих функций. Подробнее"; +"settings.application_settings.leak_protection.more_info" = "Подробнее"; +"settings.application_settings.allow_local_network.title" = "Разрешить доступ к устройствам в локальной сети"; +"settings.application_settings.allow_local_network.footer" = "Оставайтесь подключенными к устройствам в локальной сети, таким как принтеры или файловые серверы, пользуясь при этом VPN-подключением (включайте эту опцию только если доверяете людям и устройствам в вашей сети.)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ блокирует рекламу, следящие программы и вредоносное ПО, когда вы подключены к VPN."; +"settings.application_settings.leak_protection.alert.title" = "Изменения в настройках VPN будут применены при следующем подключении"; "settings.content_blocker.title" = "Состояние блокировщика контента для Safari"; "settings.content_blocker.state.title" = "Текущее состояние"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "Кнопка VPN-подключения. VPN сейчас подключен"; "dashboard.accessibility.vpn.button.isOff" = "Кнопка VPN-подключения. VPN сейчас отключен"; +"dashboard.vpn.leakprotection.alert.title" = "Обнаружена незащищенная сеть Wi-Fi"; +"dashboard.vpn.leakprotection.alert.message" = "Во избежание утечек данных, нажмите «Отключить сейчас», чтобы выключить опцию «Разрешить доступ к устройствам в локальной сети» и автоматически переподключиться."; +"dashboard.vpn.leakprotection.alert.cta1" = "Отключить сейчас"; +"dashboard.vpn.leakprotection.alert.cta2" = "Узнать больше"; +"dashboard.vpn.leakprotection.alert.cta3" = "Игнорировать"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Для предотвращения утечек данных, нажмите «Переключить сейчас», чтобы перейти на протокол IKEv2 VPN и автоматически переподключиться."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Переключить сейчас"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "Показать служебные сообщения обмена данными"; "inapp.messages.settings.updated" = "Настройки обновлены"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Регион"; +"widget.liveActivity.protocol.title" = "Протокол"; diff --git a/PIA VPN/th.lproj/Localizable.strings b/PIA VPN/th.lproj/Localizable.strings index 5ecc26642..e4f396f7b 100644 --- a/PIA VPN/th.lproj/Localizable.strings +++ b/PIA VPN/th.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "การต่ออายุ"; "expiration.message" = "สถานะสมาชิกของคุณจะหมดอายุเร็วๆนี้ ต่ออายุเพื่อรับการป้องกันต่อ"; +"local_notification.non_compliant_wifi.title" = "Wi-Fi ที่ไม่ปลอดภัย: %@"; +"local_notification.non_compliant_wifi.text" = "แตะที่นี่เพื่อรักษาความปลอดภัยให้อุปกรณ์ของคุณ"; + // SHORTCUTS "shortcuts.connect" = "เชื่อมต่อ"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "ธีมที่ใช้งานอยู่"; "settings.application_settings.kill_switch.title" = "ปุ่มตัดการทำงาน VPN"; "settings.application_settings.kill_switch.footer" = "Kill switch ของ VPN จะป้องกันการเข้าถึงอินเทอร์เน็ตหากการเชื่อมต่อ VPN กำลังเชื่อมต่อใหม่ ไม่รวมการตัดการเชื่อมต่อด้วยตนเอง"; +"settings.application_settings.leak_protection.title" = "การป้องกันการรั่วไหล"; +"settings.application_settings.leak_protection.footer" = "iOS มีคุณสมบัติที่ออกแบบมาเพื่อทำงานนอก VPN ตามค่าเริ่มต้น เช่น AirDrop, CarPlay, AirPlay และฮอตสปอตส่วนบุคคล การเปิดใช้งานการปกป้องการรั่วไหลแบบกำหนดเองจะนำทางการรับส่งข้อมูลเหล่านี้ผ่าน VPN แต่อาจส่งผลกระทบต่อวิธีการทำงานของคุณสมบัติดังกล่าว ข้อมูลเพิ่มเติม"; +"settings.application_settings.leak_protection.more_info" = "ข้อมูลเพิ่มเติม"; +"settings.application_settings.allow_local_network.title" = "อนุญาตการเข้าถึงอุปกรณ์บนเครือข่ายท้องถิ่น"; +"settings.application_settings.allow_local_network.footer" = "คงความเชื่อมต่อกับอุปกรณ์ท้องถิ่นอย่างเครื่องพิมพ์หรือเซิร์ฟเวอร์ไฟล์ระหว่างที่เชื่อมต่อกับ VPN (อนุญาตเฉพาะหากคุณไว้ใจผู้คนและอุปกรณ์ในเครือข่ายของคุณ)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ บล็อกโฆษณา, ตัวติดตาม และมัลแวร์ ในขณะที่คุณกำลังเชื่อมต่อ VPN อยู่"; +"settings.application_settings.leak_protection.alert.title" = "การเปลี่ยนแปลงการตั้งค่า VPN จะมีผลในการเชื่อมต่อครั้งต่อไป"; "settings.content_blocker.title" = "สถานะตัวปิดกั้นเนื้อหา Safari"; "settings.content_blocker.state.title" = "สถานะปัจจุบัน"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "ปุ่มเชื่อมต่อ VPN ขณะนี้ VPN เชื่อมต่ออยู่"; "dashboard.accessibility.vpn.button.isOff" = "ปุ่มเชื่อมต่อ VPN ขณะนี้ VPN ขาดการเชื่อมต่อ"; +"dashboard.vpn.leakprotection.alert.title" = "ตรวจพบ Wi-Fi ที่ไม่ปลอดภัย"; +"dashboard.vpn.leakprotection.alert.message" = "หากต้องการป้องกันการรั่วไหลของข้อมูล ให้แตะ ปิดใช้งานเลย เพื่อปิด “อนุญาตการเข้าถึงอุปกรณ์บนเครือข่ายท้องถิ่น” และเชื่อมต่อใหม่โดยอัตโนมัติ"; +"dashboard.vpn.leakprotection.alert.cta1" = "ปิดใช้งานเลย"; +"dashboard.vpn.leakprotection.alert.cta2" = "เรียนรู้เพิ่มเติม"; +"dashboard.vpn.leakprotection.alert.cta3" = "เพิกเฉย"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "หากต้องการป้องกันการรั่วไหลของข้อมูล ให้แตะ เปลี่ยนเลย เพื่อเปลี่ยนเป็นโปรโตคอล VPN IKEv2 และเชื่อมต่อใหม่โดยอัตโนมัติ"; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "เปลี่ยนเลย"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "แสดงข้อความสื่อสารบริการ"; "inapp.messages.settings.updated" = "อัปเดตการตั้งค่าแล้ว"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "ภูมิภาค"; +"widget.liveActivity.protocol.title" = "โปรโตคอล"; diff --git a/PIA VPN/tr.lproj/Localizable.strings b/PIA VPN/tr.lproj/Localizable.strings index 66f0be472..7a498a6b3 100644 --- a/PIA VPN/tr.lproj/Localizable.strings +++ b/PIA VPN/tr.lproj/Localizable.strings @@ -1,345 +1,440 @@ -"Localizable" = "Yerelleştirilebilir"; -"about.accessibility.component.expand" = "Lisansın tamamını görmek için dokunun"; -"about.app" = "Private Internet Access'ten VPN"; -"about.intro" = "Bu program şu bileşenleri kullanmaktadır:"; -"account.accessibility.eye" = "Göz simgesi"; -"account.accessibility.eye.hint.conceal" = "Şifreyi gizlemek için dokunun"; -"account.accessibility.eye.hint.reveal" = "Şifreyi açmak için dokunun"; -"account.email.caption" = "E-posta"; -"account.email.placeholder" = "E-posta adresi"; -"account.error.unauthorized" = "Kullanıcı adınız ya da şifreniz hatalı."; -"account.expiry_date.expired" = "Planınızın süresi dolmuş."; -"account.expiry_date.information" = "Planınızın süresi %@ tarihinde sona erecek."; -"account.eye.footer" = "Şifrenizi açmak ya da gizlemek için göz simgesine dokunun."; -"account.other.footer" = "Diğer cihazlarınıza Private Internet Access uygulamasını yükleyip yukarıdaki kullanıcı adı ve şifre ile giriş yaparak İnternet'e güvenli şekilde bağlanın."; -"account.password.caption" = "Şifre"; -"account.restore.button" = "Satın alınanı geri yükle"; -"account.restore.description" = "Planınızı yenilemenize rağmen hesabınızdan hâlâ süresinin dolmak üzere olduğu uyarısını alıyorsanız, buradan yenilemeyi baştan başlatabilirsiniz. Bu işlem için sizden para kesilmeyecektir."; -"account.restore.failure.message" = "Yenileme işlemi için geri yüklenebilecek satın alım işlemi bulunamadı."; -"account.restore.failure.title" = "Satın alınanı geri yükle"; -"account.restore.title" = "Hesaba yansıtılmamış satın alma işlemini geri yükleyin"; -"account.reveal.prompt" = "Ortaya çıkarmak için doğrulayın"; -"account.save.item" = "E-postayı güncelle"; -"account.save.prompt" = "Değişiklikleri kaydetmek için doğrulayın"; -"account.save.success" = "E-posta adresiniz kaydedildi."; -"account.set.email.error" = "E-posta adresi eklenirken bir hata oluştu. Lütfen daha sonra tekrar deneyin."; -"account.subscriptions.linkMessage" = "buraya tıklayın."; -"account.subscriptions.message" = "Üyelik ayarlarınızı değiştirmek için buraya tıklayın."; -"account.subscriptions.monthly" = "Aylık plan"; -"account.subscriptions.short.linkMessage" = "Aboneliği yönetin"; -"account.subscriptions.short.message" = "Aboneliği yönetin"; -"account.subscriptions.trial" = "Deneme planı"; -"account.subscriptions.yearly" = "Yıllık plan"; -"account.unauthorized" = "Bir sorun oluştu. Lütfen tekrar giriş yapmayı deneyin"; -"account.update.email.require.password.button" = "Gönder"; -"account.update.email.require.password.message" = "Güvenlik açısından hesabınızda değişiklik yapabilmeniz için PIA şifrenizi girmelisiniz. Devam etmek için lütfen PIA şifrenizi girin."; -"account.update.email.require.password.title" = "PIA Şifresi Gerekli"; -"account.username.caption" = "Kullanıcı Adı"; -"card.wireguard.cta.activate" = "WireGuard®'ı şimdi deneyin"; -"card.wireguard.cta.learn" = "Daha fazla bilgi"; -"card.wireguard.cta.settings" = "Ayarları açın"; -"card.wireguard.description" = "Bu, daha iyi performans, daha düşük CPU kullanımı ve daha uzun pil ömrü sunan, yeni, daha verimli bir VPN protokolü."; -"card.wireguard.title" = "WireGuard®'ı bugün deneyin!"; -"content_blocker.body.footer" = "Lütfen unutmayın: Bu İçerik Engelleyicinin çalışması için VPN bağlantınızın olmasına gerek yoktur ancak yalnızca Safari ile gezindiğinizde çalışacaktır."; -"content_blocker.body.subtitle" = "İçerik Engelleyicimizin Safari ile kullanılmasını etkinleştirmek için lütfen Genel bölümü altından Ayarlar > Safari kısmına gidin ve PIA VPN'de İçerik Engelleyicileri açık hale getirin."; -"content_blocker.title" = "Safari İçerik Engelleyici"; -"dashboard.accessibility.vpn.button" = "VPN Bağlantı düğmesi"; -"dashboard.accessibility.vpn.button.isOff" = "VPN Bağlantı düğmesi. Şu anda VPN'ye bağlı değil"; -"dashboard.accessibility.vpn.button.isOn" = "VPN Bağlantı düğmesi. Şu anda VPN'ye bağlı değil"; -"dashboard.connection.ip.caption" = "HERKESE AÇIK IP"; -"dashboard.connection.ip.unreachable" = "İnternet'e erişilemiyor"; -"dashboard.connection.region.caption" = "MEVCUT BÖLGE"; -"dashboard.connection.region.change" = "BÖLGEYİ DEĞİŞTİR"; -"dashboard.content_blocker.intro.message" = "Bu sürüm, MACE'i Safari İçerik Engelleyicimizle değiştirir.\n\n'Ayarlar' bölümünde bunu işaretleyin."; -"dashboard.status" = "Durum"; -"dashboard.vpn.changing_region" = "Bölge değiştiriliyor..."; -"dashboard.vpn.connected" = "VPN'ye Bağlandı"; -"dashboard.vpn.connecting" = "Bağlanıyor..."; -"dashboard.vpn.disconnect.untrusted" = "Bu güvenilir bir ağ değil. VPN bağlantısını kesmek istediğinizden emin misiniz?"; -"dashboard.vpn.disconnected" = "Bağlantı Kesildi"; -"dashboard.vpn.disconnecting" = "Bağlantı Kesiliyor"; -"dashboard.vpn.on" = "VPN: AÇIK"; -"dedicated.ip.activate.button.title" = "Etkinleştir"; -"dedicated.ip.activation.description" = "Belirtecinizi aşağı yapıştırarak Özel IP'nizi etkinleştirin. Kısa süre önce bir özel IP aldıysanız PIA web sitesine giderek belirteci üretebilirsiniz."; -"dedicated.ip.country.flag.accessibility" = "%@ için ülke bayrağı"; -"dedicated.ip.limit.title" = "Seçeceğiniz bir ülkeden bir özel IP alarak, herhangi bir valığa olan uzak bağlantılarınızı güvence altına alın. Aboneliğiniz süresince bu IP yalnızca ama yalnızca size ait olacak ve veri aktarımlarınızı mümkün olan en güçlü şifrelemeyle koruyacak."; -"dedicated.ip.message.error.token" = "Belirtecinizin süresi dolmuş. Lütfen web sitesindeki Hesap sayfanıza giderek yenisini üretin."; -"dedicated.ip.message.expired.token" = "Belirtecinizin süresi dolmuş. Lütfen web sitesindeki Hesap sayfanıza giderek yenisini üretin."; -"dedicated.ip.message.incorrect.token" = "Lütfen belirteci doğru şekilde girdiğinizden emin olun"; -"dedicated.ip.message.invalid.token" = "Belirteciniz geçersiz. Lütfen belirteci doğru şekilde girdiğinizden emin olun"; -"dedicated.ip.message.ip.updated" = "Özel IP'niz güncellendi"; -"dedicated.ip.message.token.willexpire" = "Özel IP'nizin süresi yakında dolacak. Yenisini alın"; -"dedicated.ip.message.token.willexpire.link" = "Yenisini alın"; -"dedicated.ip.message.valid.token" = "Özel IP'niz başarıyla etkinleştirildi. Bölge seçim listenizde mevcut olacak."; -"dedicated.ip.plural.title" = "Özel IP'leriniz"; -"dedicated.ip.remove" = "Seçilen bölgeyi silmek istediğinizden emin misiniz?"; -"dedicated.ip.title" = "Özel IP"; -"dedicated.ip.token.textfield.accessibility" = "Özel IP belirtecinin yazılacağı metin alanı"; -"dedicated.ip.token.textfield.placeholder" = "Belirtecinizi buraya yapıştırın"; -"expiration.message" = "Üyeliğiniz yakında sona erecek. Koruma altında kalmak için yenileyin."; -"expiration.title" = "Yenileme"; -"friend.referrals.days.acquired" = "Ücretsiz günler alındı"; -"friend.referrals.days.number" = "%d gün"; -"friend.referrals.description.short" = "BİR ARKADAŞINIZI ARAMIZA KATIN. 30 GÜN ÜCRETSİZ KULLANIN."; -"friend.referrals.email.validation" = "Geçersiz e-posta adresi. Lütfen tekrar deneyin."; -"friend.referrals.family.friends.program" = "Aile ve Arkadaş Referans Programı"; -"friend.referrals.friends.family.title" = "Arkadaşlarınız ve aile bireylerinizi aramıza katın. Kaydolan her kişi için her ikinize birden 30'ar gün ücretsiz kullanım hakkı vereceğiz. "; -"friend.referrals.fullName" = "Adı ve soyadı"; -"friend.referrals.invitation.terms" = "Bu daveti göndererek Aile ve Arkadaş Referans Programının tüm şart ve koşullarını kabul ediyorum."; -"friend.referrals.invite.error" = "Davet tekrar gönderilemedi. Daha sonra tekrar deneyin."; -"friend.referrals.invite.success" = "Davet başarıyla gönderildi"; -"friend.referrals.invites.number" = "%d davet gönderdiniz"; -"friend.referrals.invites.sent.title" = "Davetler gönderildi"; -"friend.referrals.pending.invites" = "%d davet bekliyor"; -"friend.referrals.pending.invites.title" = "Bekleyen davet"; -"friend.referrals.privacy.note" = "Gizlilikle ilgili sebeplerden ötürü bekleme süresi 30 günü aşan davetler silinir."; -"friend.referrals.reward.given" = "Ödül verildi"; -"friend.referrals.send.invite" = "Davet gönder"; -"friend.referrals.share.link" = "Benzersiz referans linkinizi paylaşın"; -"friend.referrals.share.link.terms" = "Bu daveti gönderdiğinizde Aile ve Arkadaş Referans Programının tüm şart ve koşullarını kabul etmiş olursunuz."; -"friend.referrals.signedup" = "Kaydolan"; -"friend.referrals.signups.number" = "%d kayıt"; -"friend.referrals.title" = "Arkadaşınızı Aramıza Katın"; -"friend.referrals.view.invites.sent" = "Gönderilen davetleri göster"; -"gdpr.accept.button.title" = "Kabul edip devam et"; -"gdpr.collect.data.description" = "E-posta Adresi sadece hesap yönetimi ve ihlale karşı koruma amaçlarıyla kullanılır.\n\nE-posta adresi; abonelik bilgilerini, ödeme onaylarını, müşteri yazışmalarını ve Private Internet Access promosyonlarını göndermek için kullanılır."; -"gdpr.collect.data.title" = "Topladığımız kişisel bilgiler"; -"global.add" = "Ekle"; -"global.automatic" = "Otomatik"; +// GLOBAL + +"global.ok" = "Tamam"; "global.cancel" = "İptal"; -"global.clear" = "Temizle"; "global.close" = "Kapat"; -"global.copied" = "Panoya kopyalandı"; -"global.copy" = "Kopyala"; -"global.disable" = "Kapat"; -"global.disabled" = "Kapalı"; -"global.edit" = "Düzenle"; -"global.empty" = "Boş"; -"global.enable" = "Aç"; -"global.enabled" = "Açık"; "global.error" = "Hata"; -"global.general.settings" = "Genel Ayarlar"; -"global.no" = "Hayır"; -"global.ok" = "Tamam"; -"global.optional" = "İsteğe bağlı"; -"global.or" = "veya"; -"global.remove" = "Kaldır"; -"global.required" = "Gerekli"; -"global.row.selection" = "Sıra seçimi"; -"global.share" = "Paylaş"; -"global.unreachable" = "İnternet bağlantısı bulunamadı. Lütfen İnternet bağlantınızın olduğunu doğrulayın."; +"global.automatic" = "Otomatik"; +"global.required" = "Required"; +"global.optional" = "Optional"; +"global.clear" = "Temizle"; "global.update" = "Güncelle"; -"global.version" = "Sürüm"; -"global.vpn.settings" = "VPN Ayarları"; +"global.edit" = "Düzenle"; +"global.unreachable" = "No internet connection found. Please confirm that you have an internet connection."; +"global.enabled" = "Etkin"; +"global.disabled" = "Devre Dışı"; +"global.enable" = "Etkinleştir"; +"global.disable" = "Kapat"; +"global.add" = "Ekle"; +"global.remove" = "Kaldır"; +"global.empty" = "Empty"; +"global.copy" = "Kopyala"; +"global.share" = "Share"; +"global.copied" = "Panoya kopyalandı"; "global.yes" = "Evet"; -"hotspothelper.display.name" = "🔒 Bu bağlantıyı güvenlik altına almak için PIA Ayarları kısmından VPN WiFi Korumasını açın."; -"hotspothelper.display.protected.name" = "🔒 PIA VPN WiFi Koruması Açık! Arkanızdayız."; -"inapp.messages.settings.updated" = "Ayarlar güncellendi"; -"inapp.messages.toggle.title" = "Hizmet İletişim Mesajlarını Göster"; +"global.no" = "Hayır"; +"global.or" = "or"; +"global.row.selection" = "Row selection"; +"global.vpn.settings" = "VPN Ayarları"; +"global.general.settings" = "General Settings"; +"global.version" = "Sürüm"; + +// NOTIFICATIONS + +"notifications.disabled.title" = "Notifications disabled"; +"notifications.disabled.message" = "Enable notifications to get a reminder to renew your subscription before it expires."; +"notifications.disabled.settings" = "Ayarlar"; + +"expiration.title" = "Renewal"; +"expiration.message" = "Your subscription expires soon. Renew to stay protected."; + +"local_notification.non_compliant_wifi.title" = "Güvenilmeyen Wi-Fi: %@"; +"local_notification.non_compliant_wifi.text" = "Cihazınızı güvence altına almak için buraya dokunun"; + +// SHORTCUTS + +"shortcuts.connect" = "Bağlan"; +"shortcuts.disconnect" = "bağlantısını sonlandırın"; +"shortcuts.select_region" = "Select a region"; + +// RENEWAL + +"renewal.success.title" = "Thank you"; +"renewal.success.message" = "Your account was successfully renewed."; +"renewal.failure.message" = "Your purchase receipt couldn't be submitted, please retry at a later time."; + +// MENU "menu.accessibility.edit.tile" = "Düzenle"; "menu.accessibility.item" = "Menü"; -"menu.accessibility.logged_as" = "%@ olarak giriş yapıldı"; +"menu.accessibility.logged_as" = "Logged in as %@"; +"menu.expiration.expires_in" = "Subscription expires in"; "menu.expiration.days" = "%d gün"; -"menu.expiration.expires_in" = "Üyeliğin sona erme süresi:"; "menu.expiration.hours" = "%d saat"; "menu.expiration.one_hour" = "bir saat"; -"menu.expiration.upgrade" = "HESABI YÜKSELTİN"; +"menu.expiration.upgrade" = "UPGRADE ACCOUNT"; +"menu.item.region" = "Region selection"; "menu.item.about" = "Hakkında"; "menu.item.account" = "Hesap"; -"menu.item.logout" = "Çıkış yap"; -"menu.item.region" = "Bölge seçimi"; "menu.item.settings" = "Ayarlar"; -"menu.item.web.home" = "Ana sayfa"; -"menu.item.web.privacy" = "Gizlilik politikası"; +"menu.item.logout" = "Çıkış yap"; +"menu.item.web.privacy" = "Privacy policy"; +"menu.item.web.home" = "Home page"; "menu.item.web.support" = "Destek"; -"menu.logout.confirm" = "Çıkış yap"; -"menu.logout.message" = "Çıkış yaptığınızda VPN devre dışı kalacak ve korunmasız olacaksınız."; + "menu.logout.title" = "Çıkış yap"; -"menu.renewal.message.trial" = "Deneme hesabı yenilenemez. Hizmeti kullanmaya devam etmek için süresi dolduktan sonra lütfen yeni bir hesap satın alın."; -"menu.renewal.message.unavailable" = "Apple sunucuları şu anda kullanılamıyor. Lütfen daha sonra tekrar deneyin."; -"menu.renewal.message.website" = "Lütfen üyeliğinizi yenilemek için internet sitemizi kullanın."; +"menu.logout.message" = "Logging out will disable the VPN and leave you unprotected."; +"menu.logout.confirm" = "Çıkış yap"; + +"menu.renewal.title" = "Renewal"; "menu.renewal.purchase" = "Satın Al"; "menu.renewal.renew" = "Yenile"; -"menu.renewal.title" = "Yenileme"; -"network.management.tool.add.rule" = "Yeni kural ekle"; -"network.management.tool.alert" = "Otomatik işlev ayarlarınız, mevcut ağ koşulları altında VPN'nin bağlantısını kesik tutacak şekilde yapılandırılmış."; -"network.management.tool.always.connect" = "Daima VPN'ye bağlan"; -"network.management.tool.always.disconnect" = "Daima VPN bağlantısını kes"; -"network.management.tool.choose.wifi" = "Yeni kural eklemek için bir WiFi ağı seçin. "; -"network.management.tool.disable" = "Otomasyonu Kapat"; -"network.management.tool.enable.automation" = "Otomasyonu Etkinleştir"; -"network.management.tool.mobile.data" = "Mobil veri"; -"network.management.tool.open.wifi" = "Ortak WiFi"; -"network.management.tool.retain.state" = "VPN Durumunu Koru"; -"network.management.tool.secure.wifi" = "Güvenli VPN"; -"network.management.tool.title" = "Otomasyonu Yönet"; -"notifications.disabled.message" = "Aboneliğinizi süresi dolmadan önce yenilemek için bildirimleri etkinleştirerek bir hatırlatıcı alın."; -"notifications.disabled.settings" = "Ayarlar"; -"notifications.disabled.title" = "Bildirimler kapalı"; -"rating.enjoy.question" = "PIA VPN hoşunuza gidiyor mu?"; -"rating.enjoy.subtitle" = "Umarız VPN ürünümüz beklentilerinizi karşılıyordur"; -"rating.error.button.send" = "Geri bildirim gönder"; -"rating.error.question" = "Bağlantı kurulamadı"; -"rating.error.subtitle" = "Farklı bir bölge seçebilir ya da bir destek bileti açarak bize bilgi verebilirsiniz."; -"rating.problems.question" = "Sorun nedir?"; -"rating.problems.subtitle" = "Geri bildirim göndermek ister misiniz? PIA kullanırken yaşadığınız deneyimi geliştirmenize yardımcı olabiliriz"; -"rating.rate.question" = "AppStore değerlendirmesi verebilir misiniz?"; -"rating.rate.subtitle" = "Deneyiminizi paylaşmanız bizi memnun eder"; -"region.accessibility.favorite" = "Favori bölge ekleyin"; -"region.accessibility.filter" = "Filtre"; -"region.accessibility.unfavorite" = "Bir favori bölgeyi kaldırın"; -"region.filter.favorites" = "Favoriler"; -"region.filter.latency" = "Gecikme"; -"region.filter.name" = "Ad"; -"region.filter.sortby" = "Bölgeleri sıralama kıstası:"; -"region.search.placeholder" = "Bir bölge arayın"; -"renewal.failure.message" = "Satın alım işleminizin faturası gönderilemedi; lütfen daha sonra tekrar deneyin."; -"renewal.success.message" = "Hesabınız başarıyla yenilendi."; -"renewal.success.title" = "Teşekkürler"; -"server.reconnection.please.wait" = "Lütfen bekleyin..."; -"server.reconnection.still.connection" = "Bağlanma işlemi devam ediyor..."; -"set.email.error.validation" = "Bir e-posta adresi girmeniz gerekiyor."; -"set.email.form.email" = "E-posta adresinizi girin"; -"set.email.password.caption" = "Şifre"; -"set.email.success.message_format" = "Hesap kullanıcı adınızı ve şifrenizi %@ adresinize gönderdik"; -"set.email.why" = "Kullanıcı adınızla şifrenizi gönderebilmemiz için e-posta adresinize ihtiyacımız var."; -"settings.application_information.debug.empty.message" = "Hata ayıklama bilgileri boş; lütfen tekrar göndermeyi denemeden önce bir bağlantı kurun."; -"settings.application_information.debug.empty.title" = "Boş hata ayıklama bilgisi"; -"settings.application_information.debug.failure.message" = "Hata ayıklama bilgileri gönderilemedi."; -"settings.application_information.debug.failure.title" = "Gönderme sırasında hata oluştu"; -"settings.application_information.debug.success.message" = "Hata ayıklama bilgileri başarıyla gönderildi.\nKimlik: %@\nLütfen bu kimliği not edin; destek ekibimiz gönderdiğiniz bilgileri bulmak için bu kimliği kullanacaktır."; -"settings.application_information.debug.success.title" = "Hata ayıklama bilgileri gönderildi"; -"settings.application_information.debug.title" = "Hata Ayıklamayı destek birimine gönderin"; -"settings.application_information.title" = "UYGULAMA BİLGİLERİ"; -"settings.application_settings.active_theme.title" = "Aktif tema"; -"settings.application_settings.dark_theme.title" = "Koyu tema"; -"settings.application_settings.kill_switch.footer" = "VPN kill switch, VPN bağlantısı kesilip yeniden bağlanmaya çalışırken İnternet bağlantısını devre dışı bırakır. Bağlantının elle kesildiği durumlar hariç."; -"settings.application_settings.kill_switch.title" = "VPN Sonlandırma Anahtarı"; -"settings.application_settings.mace.footer" = "PIA MACE™ VPN'e bağlı iken reklam, iz sürücüler ve kötü amaçlı yazılımları engeller."; -"settings.application_settings.mace.title" = "PIA MACE™"; -"settings.application_settings.title" = "UYGULAMA AYARLARI"; -"settings.cards.history.title" = "Son Haberler"; -"settings.commit.buttons.later" = "Daha Sonra"; -"settings.commit.buttons.reconnect" = "Tekrar Bağlan"; -"settings.commit.messages.must_disconnect" = "Bazı değişikliklerin etki etmesi için VPN'nin tekrar bağlanması gerekmektedir."; -"settings.commit.messages.should_reconnect" = "Değişikliklerin etki etmesi için VPN'yi tekrar bağlayın."; -"settings.connection.remote_port.title" = "Uzaktan Bağlantı Noktası"; -"settings.connection.socket_protocol.title" = "Socket"; +"menu.renewal.message.trial" = "Deneme hesabı yenilenemez. Hizmeti kullanmaya devam etmek için süresi dolduktan sonra lütfen yeni bir hesap satın alın."; +"menu.renewal.message.website" = "Please use our website to renew your subscription."; +"menu.renewal.message.unavailable" = "Apple servers currently unavailable. Please try again later."; + +// ACCOUNT + +"account.email.caption" = "E-posta"; +"account.email.placeholder" = "E-posta adresi"; +"account.username.caption" = "Kullanıcı Adı"; +"account.other.footer" = "Get the Private Internet Access app for your other devices and use the above username and password to login and secure your connection."; +"account.restore.title" = "Restore uncredited purchase"; +"account.restore.description" = "If you renewed your plan but your account still says it's about to expire, you can restart the renewal from here. You will not be charged during this process."; +"account.restore.button" = "RESTORE PURCHASE"; +"account.restore.failure.title" = "Restore purchase"; +"account.restore.failure.message" = "No redeemable purchase was found for renewal."; +"account.save.item" = "E-posta adresini güncelle"; +"account.save.prompt" = "Authenticate to save changes"; +"account.save.success" = "Your email address has been saved."; +"account.reveal.prompt" = "Authenticate to reveal"; +"account.expiry_date.information" = "Your plan will expire on %@."; +"account.expiry_date.expired" = "Your plan has expired."; +"account.update.email.require.password.title" = "PIA Parolası Gerekli"; +"account.update.email.require.password.message" = "Güvenlik nedenleriyle, hesabınızda herhangi bir değişiklik yapmak için PIA parolanızı girmeniz gerekli. Lütfen devam etmek için PIA parolanızı girin."; +"account.update.email.require.password.button" = "Gönder"; +"account.error.unauthorized" = "Your username or password is incorrect."; +"account.subscriptions.message" = "You can manage your subscription from here."; +"account.subscriptions.linkMessage" = "buradan ulaşabilirsiniz"; +"account.set.email.error" = "There was an error adding email. Please try again later."; +"account.subscriptions.short.message" = "Manage subscription"; +"account.subscriptions.short.linkMessage" = "Manage subscription"; +"account.subscriptions.yearly" = "Yearly plan"; +"account.subscriptions.monthly" = "Monthly plan"; +"account.subscriptions.trial" = "Trial plan"; +"account.unauthorized" = "Bir sorun oluştu. Lütfen tekrar oturum açmayı deneyin"; +"account.delete" = "Hesabı Sil"; +"account.delete.alert.title" = "Emin misiniz?"; +"account.delete.alert.message" = "Deleting your PIA account is permanent and irreversible. You will not be able to retrieve your PIA credentials after performing this action. Please note that this action only deletes your PIA account from our database, but it does NOT delete your subscription. You will need to go to your Apple account and cancel the Private Internet Access subscription from there. Otherwise, you will still be charged, even though your PIA account will no longer be active."; +"account.delete.alert.failureMessage" = "Something went wrong while deleting your account, please try again later."; +"account.survey.message" = "Want to help make PIA better? Let us know how we can improve!\nTake The Survey"; +"account.survey.messageLink" = "Take The Survey"; + +// SETTINGS + "settings.connection.title" = "BAĞLANTI"; -"settings.connection.transport.title" = "Nakil"; "settings.connection.vpn_protocol.title" = "Protokol Seçimi"; -"settings.content_blocker.footer" = "İçerik Engelleyiciyi etkinleştirmek veya devre dışı bırakmak için Ayarlar > Safari > İçerik Engelleyici bölümüne gidin ve PIA VPN'i açık hale getirin."; -"settings.content_blocker.refresh.title" = "Engelleme listesini yenile"; -"settings.content_blocker.state.title" = "Mevcut durum"; -"settings.content_blocker.title" = "Safari İçerik Engelleyici durumu"; -"settings.dns.alert.clear.message" = "Bu işlem özel DNS'yi temizler ve varsayılan PIA DNS ayarını uygular."; -"settings.dns.alert.clear.title" = "DNS'yi temizle"; -"settings.dns.alert.create.message" = "PIA DNS harici bir şey kullandığınızda DNS trafiğiniz üçüncü kısımlara açık hale gelebilir ve gizliliğiniz risk altına girebilir."; +"settings.connection.transport.title" = "Taşıma"; +"settings.connection.socket_protocol.title" = "Socket"; +"settings.connection.remote_port.title" = "Uzak Bağlantı Noktası"; + +"settings.encryption.title" = "ŞİFRELEME"; +"settings.encryption.cipher.title" = "Veri Şifrelemesi"; +"settings.encryption.digest.title" = "Veri Kimlik Doğrulama"; +"settings.encryption.handshake.title" = "El sıkışma"; + +"settings.application_settings.title" = "APPLICATION SETTINGS"; +"settings.application_settings.dark_theme.title" = "Dark theme"; +"settings.application_settings.active_theme.title" = "Active theme"; +"settings.application_settings.kill_switch.title" = "VPN Acil Anahtarı"; +"settings.application_settings.kill_switch.footer" = "The VPN kill switch prevents access to the Internet if the VPN connection is reconnecting. This excludes disconnecting manually."; +"settings.application_settings.leak_protection.title" = "Sızıntı Koruması"; +"settings.application_settings.leak_protection.footer" = "iOS, varsayılan olarak VPN dışında çalışacak şekilde tasarlanmış özellikleri içerir. Bunlar AirDrop, CarPlay, AirPlay ve Kişisel Erişim Noktaları gibi özellikleri içerir. Özel sızıntı koruması etkinleştirildiğinde, bu trafiğin VPN üzerinden yönlendirilmesi ancak bu özelliklerin işlevselliğini etkileyebilir. Daha fazla bilgi"; +"settings.application_settings.leak_protection.more_info" = "Daha fazla bilgi"; +"settings.application_settings.allow_local_network.title" = "Yerel ağdaki cihazlara erişim izni ver"; +"settings.application_settings.allow_local_network.footer" = "VPN'e bağlıyken yazıcılar veya dosya sunucuları gibi yerel cihazlara bağlı kalın. (Buna yalnızca ağınızdaki kişilere ve cihazlara güveniyorsanız izin verin.)"; +"settings.application_settings.mace.title" = "PIA MACE™"; +"settings.application_settings.mace.footer" = "PIA MACE™ blocks ads, trackers, and malware while you're connected to the VPN."; +"settings.application_settings.leak_protection.alert.title" = "VPN Ayarlarındaki değişiklikler, bir sonraki bağlantıda etkili olacak"; + +"settings.content_blocker.title" = "Safari Content Blocker state"; +"settings.content_blocker.state.title" = "Current state"; +"settings.content_blocker.refresh.title" = "Refresh block list"; +"settings.content_blocker.footer" = "To enable or disable Content Blocker go to Settings > Safari > Content Blockers and toggle PIA VPN."; + +"settings.application_information.title" = "UYGULAMA BİLGİLERİ"; +"settings.application_information.debug.title" = "Hata Ayıklama Kaydını Destek Ekibine Gönderin"; +"settings.application_information.debug.failure.title" = "Error during submission"; +"settings.application_information.debug.failure.message" = "Debug information could not be submitted."; +"settings.application_information.debug.empty.title" = "Empty debug information"; +"settings.application_information.debug.empty.message" = "Debug information is empty, please attempt a connection before retrying submission."; +"settings.application_information.debug.success.title" = "Hata ayıklama bilgileri gönderildi"; +"settings.application_information.debug.success.message" = "Debug information successfully submitted.\nID: %@\nPlease note this ID, as our support team will require this to locate your submission."; + +"settings.commit.messages.must_disconnect" = "The VPN must reconnect for some changes to take effect."; +"settings.commit.messages.should_reconnect" = "Reconnect the VPN to apply changes."; +"settings.commit.buttons.reconnect" = "Yeniden bağlan"; +"settings.commit.buttons.later" = "Daha sonra"; + +"settings.reset.title" = "RESET"; +"settings.reset.defaults.title" = "Ayarları varsayılanlara sıfırla"; +"settings.reset.defaults.confirm.title" = "Reset settings"; +"settings.reset.defaults.confirm.message" = "Bu işlem uygulama ayarlarını sıfırlayacak. Yapmış olduğunuz bütün değişiklikler kaybolacaktır."; +"settings.reset.defaults.confirm.button" = "Sıfırla"; +"settings.reset.footer" = "This will reset all of the above settings to default."; + +"settings.small.packets.title" = "Küçük Paketler Kullan"; +"settings.small.packets.description" = "Bazı yönlendirici ve mobil ağlarla olan uyumluluğu artırmak için IP paket boyutunu hafif düşürecek."; + +"settings.log.connected.error" = "A VPN connection is required. Please connect to the VPN and retry."; +"settings.log.information" = "Sorunların giderilmesine yardımcı olması için teknik desteğe gönderilebilen hata ayıklama günlüklerini kaydedin."; + +"settings.preview.title" = "Preview"; +"settings.server.network.description" = "Next generation network"; +"settings.server.network.alert" = "The VPN has to be disconnected to change the server network."; + +"settings.geo.servers.description" = "Coğrafi Konum Bölgelerini Göster"; +"settings.cards.history.title" = "Son haberler"; + +"settings.ovpn.migration.footer" = "OpenVPN uygulamamızı güncelliyoruz, daha fazla bilgi için buraya tıklayın"; +"settings.ovpn.migration.footer.link" = "buradan"; + +"settings.section.general" = "Genel"; +"settings.section.protocols" = "Protokoller."; +"settings.section.network" = "AĞ"; +"settings.section.privacyFeatures" = "Privacy Features"; +"settings.section.automation" = "Otomasyon"; +"settings.section.help" = "Yardım"; + +// CONTENT BLOCKER + +"content_blocker.title" = "Safari Content Blocker"; +"content_blocker.body.subtitle" = "To enable our Content Blocker for use with Safari please go to Settings > Safari, and under General touch Content Blockers toggle on PIA VPN."; +"content_blocker.body.footer" = "Please note: You do not need to be connected to the VPN for this Content Blocker to work, but it will only work while browsing with Safari."; + +// ABOUT + +"about.app" = "Private Internet Access'ten VPN"; +"about.intro" = "This program uses the following components:"; +"about.accessibility.component.expand" = "Tap to read full license"; + +// DASHBOARD + +"dashboard.content_blocker.intro.message" = "This version replaces MACE with our Safari Content Blocker.\n\nCheck it out in the 'Settings' section."; + +"dashboard.connection.ip.unreachable" = "Internet unreachable"; + +"dashboard.vpn.disconnected" = "Bağlantı Kesildi"; +"dashboard.vpn.connecting" = "Bağlanıyor..."; +"dashboard.vpn.connected" = "Connected to VPN"; +"dashboard.vpn.on" = "VPN: ON"; +"dashboard.vpn.disconnecting" = "Bağlantı kesiliyor..."; +"dashboard.vpn.changing_region" = "Changing region..."; +"dashboard.vpn.disconnect.untrusted" = "This network is untrusted. Do you really want to disconnect the VPN?"; +"dashboard.accessibility.vpn.button" = "VPN Connection button"; +"dashboard.accessibility.vpn.button.isOn" = "VPN Connection button. The VPN is currently connected"; +"dashboard.accessibility.vpn.button.isOff" = "VPN Connection button. The VPN is currently disconnected"; + +"dashboard.vpn.leakprotection.alert.title" = "Güvenilmeyen Wi-Fi algılandı"; +"dashboard.vpn.leakprotection.alert.message" = "Veri sızıntısını önlemek için, \"Yerel ağdaki cihazlara erişime izin ver\" özelliğini devre dışı bırakmak ve otomatik olarak yeniden bağlanmak için Şimdi Devre Dışı Bırak'a dokunun."; +"dashboard.vpn.leakprotection.alert.cta1" = "Şimdi Kapat"; +"dashboard.vpn.leakprotection.alert.cta2" = "Daha fazlasını öğrenin"; +"dashboard.vpn.leakprotection.alert.cta3" = "Yoksay"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "Veri sızıntısını önlemek için, IKEv2 VPN protokolüne geçmek ve otomatik olarak yeniden bağlanmak için Şimdi Değiştir'e dokunun."; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "Şimdi Değiştir"; + +// VPN PERMISSION + +"vpn_permission.title" = "PIA"; +"vpn_permission.body.title" = "PIA needs access to your VPN profiles to secure your traffic"; +"vpn_permission.body.subtitle" = "You’ll see a prompt for PIA VPN and need to allow access to VPN configurations.\nTo proceed tap on “%@”."; +"vpn_permission.body.footer" = "We don’t monitor, filter or log any network activity."; +"vpn_permission.disallow.message.basic" = "We need this permission for the application to function."; +"vpn_permission.disallow.message.support" = "You can also get in touch with customer support if you need assistance."; +"vpn_permission.disallow.contact" = "İletişim"; + +// CUSTOM DNS + "settings.dns.custom" = "Özel"; +"settings.dns.alert.create.message" = "Using non PIA DNS could expose your DNS traffic to third parties and compromise your privacy."; +"settings.dns.alert.clear.title" = "Clear DNS"; +"settings.dns.alert.clear.message" = "This will clear your custom DNS and default to PIA DNS."; "settings.dns.custom.dns" = "Özel DNS"; "settings.dns.primaryDNS" = "Birincil DNS"; "settings.dns.secondaryDNS" = "İkincil DNS"; +"settings.dns.validation.primary.mandatory" = "Primary DNS is mandatory."; "settings.dns.validation.primary.invalid" = "Birincil DNS geçerli değil."; -"settings.dns.validation.primary.mandatory" = "Birincil DNS boş bırakılamaz."; "settings.dns.validation.secondary.invalid" = "İkincil DNS geçerli değil."; -"settings.encryption.cipher.title" = "Veri Şifreleme"; -"settings.encryption.digest.title" = "Veri Doğrulama"; -"settings.encryption.handshake.title" = "Handshake"; -"settings.encryption.title" = "ŞİFRELEME"; -"settings.geo.servers.description" = "Coğrafi Konum Bölgelerini Göster"; -"settings.hotspothelper.all.description" = "VPN WiFi Koruması, güvenilen ağlar da dâhil olmak üzere tüm ağlarda etkinleşecek."; -"settings.hotspothelper.all.title" = "Tüm ağları koru"; -"settings.hotspothelper.available.add.help" = "Güvenilen ağları eklemek için + simgesine dokunun."; -"settings.hotspothelper.available.help" = "Bu listeyi doldurmak için iOS Ayarları > WiFi kısmına gidin."; -"settings.hotspothelper.cellular.description" = "Bu seçenek etkinleştirildiğinde, PIA, hücresel ağlara bağlanırken VPN'yi otomatik olarak açar."; -"settings.hotspothelper.cellular.networks" = "Hücresel ağlar"; -"settings.hotspothelper.cellular.title" = "Hücresel ağlarda korunun"; -"settings.hotspothelper.description" = "WiFi ağına ya da hücresel ağlara bağlandığınızda PIA'nın nasıl davranacağını yapılandırın. Elle bağlanma durumunda geçerli değildir."; -"settings.hotspothelper.enable.description" = "Bu seçenek açıldığında, PIA, güvenilmeyen WiFi ağlarına bağlandığınızda VPN'yi otomatik olarak açar."; -"settings.hotspothelper.rules.title" = "Kurallar"; -"settings.hotspothelper.title" = "Ağ yönetim aracı"; -"settings.hotspothelper.wifi.networks" = "WiFi ağları"; -"settings.hotspothelper.wifi.trust.title" = "VPN WiFi Koruması"; -"settings.log.connected.error" = "VPN bağlantısı gerekli. Lütfen VPN'ye bağlanıp tekrar deneyin."; -"settings.log.information" = "Sorunların giderilmesine yardımcı olması için, teknik desteğe gönderilebilen hata ayıklama günlüklerini kaydedin."; -"settings.nmt.killswitch.disabled" = "VPN sonlandırma anahtarı şu anda devre dışı. Ağ Yönetim Aracının çalıştığından ve ağ değiştirdiğinizde bağlanabileceğinizden emin olmak için lütfen ayarlarınızdan VPN sonlandırma anahtarını etkinleştirin."; -"settings.nmt.optout.disconnect.alerts" = "Bağlantı kesilmesi onay uyarısını kapat"; -"settings.nmt.optout.disconnect.alerts.description" = "VPN bağlantısı kesilirken gösterilen uyarıyı devre dışı bırakır."; -"settings.nmt.wireguard.warning" = "Farklı ağlar arasında geçiş yaptığınızda WireGuard®'ın tekrar bağlanmasına gerek yoktur. VPN bağlantısını güvenilir ağlarda manuel yoldan kesmeniz gerekebilir."; -"settings.ovpn.migration.footer" = "OpenVPN hizmetinin gerçekleştirilme şeklini güncelliyoruz; daha çok bilgi almak için buraya tıklayın"; -"settings.ovpn.migration.footer.link" = "buraya"; -"settings.preview.title" = "Önizleme"; -"settings.reset.defaults.confirm.button" = "Sıfırla"; -"settings.reset.defaults.confirm.message" = "Bu işlem uygulama ayarlarını sıfırlayacak. Yapmış olduğun bütün değişiklikler kaybolacaktır."; -"settings.reset.defaults.confirm.title" = "Ayarları sıfırla"; -"settings.reset.defaults.title" = "Ayarları varsayılana sıfırla"; -"settings.reset.footer" = "Bu işlem yukarıdaki bütün ayarları sıfırlayarak varsayılan değerlere döndürecektir."; -"settings.reset.title" = "SIFIRLA"; -"settings.section.automation" = "Otomasyon"; -"settings.section.general" = "Genel"; -"settings.section.help" = "Yardım"; -"settings.section.network" = "Ağ"; -"settings.section.privacyFeatures" = "Gizlilik Özellikleri"; -"settings.section.protocols" = "Protokoller"; -"settings.server.network.alert" = "Sunucu ağını değiştirmek için VPN bağlantısının sonlandırılması gerekiyor."; -"settings.server.network.description" = "Yeni nesil ağ"; -"settings.service.quality.share.description" = "VPN bağlantı istatistiklerini paylaşarak gelişmemize yardımcı olun. Bu raporlarda asla kişiyi tanımlayabilecek bilgiler yer almaz."; -"settings.service.quality.share.findoutmore" = "Daha çok bilgi"; -"settings.service.quality.share.title" = "PIA gelişimine yardım edin"; -"settings.service.quality.show.title" = "Bağlantı istatistikleri"; -"settings.small.packets.description" = "Bazı yönlendirici ve mobil ağlarla olan uyumluluğu artırmak için IP paket boyutunu hafif düşürecek."; -"settings.small.packets.title" = "Küçük Paketler Kullanın"; -"settings.trusted.networks.connect.message" = "VPN'ye bağlanarak bu ağı korumak istiyor musunuz?"; -"settings.trusted.networks.message" = "PIA, bu ağlara otomatik olarak bağlanmayacak."; -"settings.trusted.networks.sections.available" = "Mevcut ağlar"; -"settings.trusted.networks.sections.current" = "Mevcut ağ"; -"settings.trusted.networks.sections.trusted" = "Güvenilen ağlar"; -"settings.trusted.networks.sections.trusted.rule.action" = "PIA VPN bağlantısını kes"; -"settings.trusted.networks.sections.trusted.rule.description" = "PIA'nın WiFi ağında ve hücresel ağlarda nasıl davranacağını ayarlamak için VPN sonlandırma anahtarını etkinleştirdikten sonra bu özelliği açın. Bağlantıyı elle sonlandırdığınızda, Ağ Yönetim Aracının işlevselliğinin devre dışı kalacağını lütfen göz önünde bulundurun."; -"settings.trusted.networks.sections.untrusted" = "Güvenilmeyen ağlar"; -"shortcuts.connect" = "Bağlan"; -"shortcuts.disconnect" = "Bağlantıyı Kes"; -"shortcuts.select_region" = "Bir Bölge Seçin"; -"siri.shortcuts.add.error" = "Siri kısayolu eklenirken bir hata meydana geldi. Lütfen tekrar deneyin."; -"siri.shortcuts.connect.row.title" = "'Bağlan' Siri Kısayolu"; -"siri.shortcuts.connect.title" = "PIA VPN'ye bağlan"; -"siri.shortcuts.disconnect.row.title" = "'Bağlantıyı Kes' Siri Kısayolu"; -"siri.shortcuts.disconnect.title" = "PIA VPN bağlantısını kes"; -"tiles.accessibility.invisible.tile.action" = "Bu kısmı panoya eklemek için dokunun"; -"tiles.accessibility.visible.tile.action" = "Bu kısmı panodan kaldırmak için dokunun"; -"tiles.favorite.servers.title" = "Favori sunucular"; -"tiles.nmt.accessibility.trusted" = "Güvenilir ağ"; -"tiles.nmt.accessibility.untrusted" = "Güvenilmeyen ağ"; -"tiles.nmt.cellular" = "Hücresel"; -"tiles.quick.connect.title" = "Hızlı bağlan"; + +// HOTSPOT HELPER + +"settings.hotspothelper.title" = "Network management tool"; +"settings.hotspothelper.description" = "Configure how PIA will behaves on connection to WiFi or cellular networks. This excludes disconnecting manually."; +"settings.hotspothelper.enable.description" = "PIA automatically enables the VPN when connecting to untrusted WiFi networks if this option is enabled."; +"settings.hotspothelper.all.title" = "Protect all networks"; +"settings.hotspothelper.all.description" = "VPN WiFi Protection will activate on all networks, including trusted networks."; +"settings.hotspothelper.available.help" = "To populate this list go to iOS Settings > WiFi."; +"settings.hotspothelper.available.add.help" = "Tap + to add to Trusted networks."; +"settings.trusted.networks.sections.current" = "Current network"; +"settings.trusted.networks.sections.available" = "Available networks"; +"settings.trusted.networks.sections.trusted" = "Trusted networks"; +"settings.trusted.networks.message" = "PIA won't automatically connect on these networks."; +"settings.trusted.networks.connect.message" = "Protect this network by connecting to VPN?"; +"hotspothelper.display.name" = "🔒 Activate VPN WiFi Protection in PIA Settings to secure this connection."; +"hotspothelper.display.protected.name" = "🔒 PIA VPN WiFi Protection Enabled - We got your back."; +"settings.hotspothelper.cellular.title" = "Protect over cellular networks"; +"settings.hotspothelper.wifi.trust.title" = "VPN WiFi Protection"; +"settings.hotspothelper.cellular.description" = "PIA automatically enables the VPN when connecting to cellular networks if this option is enabled."; +"settings.hotspothelper.cellular.networks" = "Cellular networks"; +"settings.hotspothelper.wifi.networks" = "WiFi networks"; +"settings.trusted.networks.sections.untrusted" = "Untrusted networks"; +"settings.hotspothelper.rules.title" = "Rules"; +"settings.trusted.networks.sections.trusted.rule.description" = "Enable this feature, with the VPN kill switch enabled, to customize how PIA will behave on WiFi and cellular networks. Please be aware, functionality of the Network Management Tool will be disabled if you manually disconnect."; +"settings.trusted.networks.sections.trusted.rule.action" = "Disconnect from PIA VPN"; "tiles.quicksetting.nmt.title" = "Ağ Yönetimi"; "tiles.quicksetting.private.browser.title" = "Özel Tarayıcı"; -"tiles.quicksettings.min.elements.message" = "Hızlı Ayarlar Kısmında en az bir unsuru görünür tutmanız gerekiyor"; -"tiles.quicksettings.title" = "Hızlı ayarlar"; +"settings.nmt.killswitch.disabled" = "The VPN kill switch is currently disabled. In order to ensure that the Network Management Tool is functioning, and that you are able to reconnect when switching networks, please enable the VPN kill switch in your settings."; +"settings.nmt.optout.disconnect.alerts" = "Opt-out disconnect confirmation alert"; +"settings.nmt.optout.disconnect.alerts.description" = "Disables the warning alert when disconnecting from the VPN."; +"settings.nmt.wireguard.warning" = "WireGuard® doesn't need to reconnect when you switch between different networks. It may be necessary to manually disconnect the VPN on trusted networks."; +"settings.service.quality.share.title" = "PIA'nın iyileştirilmesine yardım edin"; +"settings.service.quality.share.description" = "VPN bağlantı istatistiklerini bizimle paylaşarak uygulamamızı geliştirmemize yardımcı olun. Bu raporlar hiç bir şekilde kişisel olarak tanımlanabilir bilgiler içermez."; +"settings.service.quality.share.findoutmore" = "Daha çok bilgi"; +"settings.service.quality.show.title" = "Connection stats"; + +"network.management.tool.open.wifi" = "Open WiFi"; +"network.management.tool.secure.wifi" = "Secure WiFi"; +"network.management.tool.mobile.data" = "Mobil veri"; +"network.management.tool.always.connect" = "Her zaman VPN bağlantısı yap"; +"network.management.tool.always.disconnect" = "Her zaman VPN bağlantısını kes"; +"network.management.tool.retain.state" = "Retain VPN State"; +"network.management.tool.add.rule" = "Yeni kural ekle"; +"network.management.tool.choose.wifi" = "Choose a WiFi network to add a new rule. "; +"network.management.tool.title" = "Otomasyonu Yönet"; +"network.management.tool.alert" = "Your automation settings are configured to keep the VPN disconnected under the current network conditions."; +"network.management.tool.disable" = "Disable Automation"; +"network.management.tool.enable.automation" = "Enable Automation"; + +// REGION + +"region.search.placeholder" = "Bir bölge ara"; +"region.accessibility.filter" = "Filter"; +"region.filter.sortby" = "Bölgeleri sırala:"; +"region.filter.name" = "İsim"; +"region.filter.latency" = "Gecikme"; +"region.filter.favorites" = "Favoriler"; +"region.accessibility.favorite" = "Add a favorite region"; +"region.accessibility.unfavorite" = "Remove a favorite region"; + +// TILES +"tiles.quick.connect.title" = "Quick connect"; +"tiles.favorite.servers.title" = "Favorite servers"; "tiles.region.title" = "VPN Sunucusu"; -"tiles.subscription.days.left" = "(%d gün kaldı)"; -"tiles.subscription.monthly" = "Aylık"; "tiles.subscription.title" = "Üyelik"; "tiles.subscription.trial" = "Deneme"; +"tiles.subscription.monthly" = "Aylık"; "tiles.subscription.yearly" = "Yıllık"; +"tiles.subscription.days.left" = "(%d gün kaldı)"; +"tiles.usage.title" = "Usage"; +"tiles.usage.ipsec.title" = "USAGE (Not available on IKEv2)"; +"tiles.usage.upload" = "Yükle"; "tiles.usage.download" = "İndir"; -"tiles.usage.ipsec.title" = "KULLANIM (IKEv2 üzerinde kullanılamaz)"; -"tiles.usage.title" = "Kullanım"; -"tiles.usage.upload" = "Karşıya yükle"; -"today.widget.login" = "Giriş"; -"vpn_permission.body.footer" = "Hiçbir ağ aktivitesini izlemiyor, filtrelemiyor ya da kayıt altına almıyoruz."; -"vpn_permission.body.subtitle" = "PIA VPN için bir açılır pencere göreceksiniz ve VPN yapılandırmalarına erişim izni vermeniz gerekecek.\nDevam etmek için “%@” düğmesine dokunun."; -"vpn_permission.body.title" = "PIA'nın veri trafiğinizi güven altına alabilmesi için VPN yapılandırma ayarlarınıza erişebilmesi gerekmektedir."; -"vpn_permission.disallow.contact" = "İletişim"; -"vpn_permission.disallow.message.basic" = "Uygulamanın çalışabilmesi için bu izne ihtiyaç duymaktayız."; -"vpn_permission.disallow.message.support" = "Yardıma ihtiyacınız olursa, müşteri desteği ile iletişime geçebilirsiniz."; -"vpn_permission.title" = "PIA"; -"walkthrough.action.done" = "BİTTİ"; -"walkthrough.action.next" = "İLERİ"; -"walkthrough.action.skip" = "ATLA"; -"walkthrough.page.1.description" = "Aynı anda 10 cihazda koruma sağlayın."; -"walkthrough.page.1.title" = "Aynı anda 10 cihazı destekler"; -"walkthrough.page.2.description" = "Dünya çapındaki sunucularla daima koruma altındasınız."; -"walkthrough.page.2.title" = "Herhangi bir bölgeye kolayca bağlanın"; -"walkthrough.page.3.description" = "İçerik Engelleyicimizi etkinleştirdiğinizde Safari'de reklamların gösterilmesi engellenir."; -"walkthrough.page.3.title" = "Kendinizi reklamlardan koruyun"; +"tiles.nmt.cellular" = "Cellular"; +"tiles.nmt.accessibility.trusted" = "Trusted network"; +"tiles.nmt.accessibility.untrusted" = "Untrusted network"; +"tiles.quicksettings.title" = "Quick settings"; +"tiles.quicksettings.min.elements.message" = "You should keep at least one element visible in the Quick Settings Tile"; +"tiles.accessibility.visible.tile.action" = "Tap to remove this tile from the dashboard"; +"tiles.accessibility.invisible.tile.action" = "Tap to add this tile to the dashboard"; + +//SIRI SHORTCUTS +"siri.shortcuts.connect.row.title" = "'Connect' Siri Shortcut"; +"siri.shortcuts.disconnect.row.title" = "'Disconnect' Siri Shortcut"; +"siri.shortcuts.connect.title" = "Connect PIA VPN"; +"siri.shortcuts.disconnect.title" = "Disconnect PIA VPN"; +"siri.shortcuts.add.error" = "There was an error adding the Siri shortcut. Please, try it again."; + +//TODAY WIDGET +"today.widget.login" = "Giriş Yapın"; + +//FRIEND REFERRALS +"friend.referrals.email.validation" = "Invalid email. Please try again."; +"friend.referrals.title" = "Arkadaş Referansı"; +"friend.referrals.view.invites.sent" = "View invites sent"; +"friend.referrals.pending.invites" = "%d bekleyen davet"; +"friend.referrals.signups.number" = "%d kayıt"; +"friend.referrals.fullName" = "Ad soyad"; +"friend.referrals.invitation.terms" = "By sending this invitation, I agree to all of the terms and conditions of the Family and Friends Referral Program."; +"friend.referrals.family.friends.program" = "Family and Friends Referral Program"; +"friend.referrals.send.invite" = "Send invite"; +"friend.referrals.invite.error" = "Could not resend invite. Try again later."; +"friend.referrals.invite.success" = "Invite sent successfully"; +"friend.referrals.share.link" = "Kişiye özel tavsiye bağlantınızı paylaşın"; +"friend.referrals.share.link.terms" = "By sharing this link, you agree to all of the terms and conditions of the Family and Friends Referral Program."; +"friend.referrals.invites.sent.title" = "Invites sent"; +"friend.referrals.pending.invites.title" = "Bekleyen davet"; +"friend.referrals.invites.number" = "%d davet gönderdiniz"; +"friend.referrals.privacy.note" = "Lütfen unutmayın, gizlilik nedeniyle, 30 günden eski tüm davetler silinir."; +"friend.referrals.signedup" = "Kayıt yaptı"; +"friend.referrals.reward.given" = "Verilen ödül"; +"friend.referrals.days.acquired" = "Alınan ücretsiz günler"; +"friend.referrals.days.number" = "%d gün"; + +"friend.referrals.friends.family.title" = "Arkadaşlarınıza ve aile bireylerinize referans olun. Her kayıtta, hem kaydolan kişi hem de siz 30'ar gün ücretsiz kullanım hakkı alacaksınız. "; +"friend.referrals.description.short" = "BİR ARKADAŞINIZI ARAMIZA KATIN. 30 GÜN ÜCRETSİZ KULLANIM KAZANIN."; + +// GDPR +"gdpr.collect.data.title" = "Personal information we collect"; +"gdpr.collect.data.description" = "E-mail Address for the purposes of account management and protection from abuse.\n\nE-mail address is used to send subscription information, payment confirmations, customer correspondence, and Private Internet Access promotional offers only."; +"gdpr.accept.button.title" = "Agree and continue"; + +// SET EMAIL +"set.email.form.email" = "E-posta adresinizi girin"; +"set.email.why" = "Kullanıcı adınızla parolanızı gönderebilmemiz için e-posta adresinize ihtiyacımız var."; +"set.email.success.message_format" = "We have sent your account username and password at your email address at %@"; +"set.email.password.caption" = "Şifre"; +"set.email.error.validation" = "You must enter an email address."; + +// RATING +"rating.enjoy.question" = "PIA VPN'i beğeniyor musunuz?"; +"rating.enjoy.subtitle" = "Umarız VPN ürünümüz beklentilerinizi karşılıyordur"; +"rating.problems.question" = "Sorun nedir?"; +"rating.problems.subtitle" = "Geri bildirim göndermek ister misiniz? Bu, PIA kullanma deneyiminizi iyileştirmemize yardımcı olabilir"; +"rating.review.question" = "How about an AppStore review?"; +"rating.rate.question" = "How about a rating on the AppStore?"; +"rating.rate.subtitle" = "Deneyiminizi paylaşmanız bizi memnun eder"; +"rating.error.question" = "Bağlantı kurulamadı"; +"rating.error.subtitle" = "Farklı bir bölge seçebilir ya da bir destek bileti açarak bize bilgi verebilirsiniz."; +"rating.error.button.send" = "Send feedback"; +"rating.alert.button.notreally" = "Not Really"; +"rating.alert.button.nothanks" = "No, thanks."; +"rating.alert.button.oksure" = "Ok, sure!"; + +// CALLING CARDS +"card.wireguard.title" = "WireGuard®'ı bugün deneyin!"; +"card.wireguard.description" = "Bu, daha iyi performans, daha düşük CPU kullanımı ve daha uzun pil ömrü sunan, yeni, daha verimli bir VPN protokolü."; +"card.wireguard.cta.activate" = "WireGuard®'ı hemen deneyin"; +"card.wireguard.cta.settings" = "Ayarlar'ı Açın"; +"card.wireguard.cta.learn" = "Daha fazlasını öğrenin"; + +// DEDICATED IP +"dedicated.ip.title" = "Atanmış IP VPN"; +"dedicated.ip.plural.title" = "Your Dedicated IPs"; +"dedicated.ip.activation.description" = "Belirtecinizi aşağıdaki forma yapıştırarak Özel IP'nizi etkinleştirin. Kısa süre önce bir özel IP satın aldıysanız belirteci PIA web sitesine giderek oluşturabilirsiniz."; +"dedicated.ip.token.textfield.placeholder" = "Belirtecinizi buraya yapıştırın"; +"dedicated.ip.token.textfield.accessibility" = "The textfield to type the Dedicated IP token"; +"dedicated.ip.activate.button.title" = "Etkinleştir"; +"dedicated.ip.message.incorrect.token" = "Please make sure you have entered the token correctly"; +"dedicated.ip.message.invalid.token" = "Belirteciniz geçersiz. Lütfen belirteci doğru şekilde girdiğinizden emin olun."; +"dedicated.ip.message.valid.token" = "Özel IP'niz başarıyla etkinleştirildi. Bölge seçim listenizde mevcut olacak."; +"dedicated.ip.message.expired.token" = "Your token is expired. Please generate a new one from your Account page on the website."; +"dedicated.ip.message.error.token" = "Your token is expired. Please generate a new one from your Account page on the website."; +"dedicated.ip.message.error.retryafter" = "Too many failed token activation requests. Please try again after %@ second(s)."; +"dedicated.ip.message.token.willexpire" = "Your dedicated IP will expire soon. Get a new one"; +"dedicated.ip.message.token.willexpire.link" = "Yenisini al"; +"dedicated.ip.message.ip.updated" = "Özel IP'niz güncellendi"; +"dedicated.ip.country.flag.accessibility" = "Country flag for %@"; +"dedicated.ip.remove" = "Are you sure you want to remove the selected region?"; +"dedicated.ip.limit.title" = "Herhangi bir varlıkla olan uzaktan bağlantılarınızı, seçtiğiniz bir ülkeden özel bir IP ile sabitleyin. Aboneliğiniz sırasında bu IP sadece size ait olacak ve veri transferleriniz en güçlü şifrelemeyle koruyacaktır."; + +// RECONNECTIONS +"server.reconnection.please.wait" = "Lütfen bekleyin..."; +"server.reconnection.still.connection" = "Hâlâ bağlanmaya çalışıyor..."; + +// INAPP MESSAGES +"inapp.messages.toggle.title" = "Servis İletişim Mesajlarını Göster"; +"inapp.messages.settings.updated" = "Ayarlar güncellendi"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "Bölge"; +"widget.liveActivity.protocol.title" = "Protokol"; diff --git a/PIA VPN/zh-Hans.lproj/Localizable.strings b/PIA VPN/zh-Hans.lproj/Localizable.strings index 93625b161..89aa75b87 100644 --- a/PIA VPN/zh-Hans.lproj/Localizable.strings +++ b/PIA VPN/zh-Hans.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "续订"; "expiration.message" = "您的订阅即将到期。请续期以持续受到保护。"; +"local_notification.non_compliant_wifi.title" = "不安全的 Wi-Fi:%@"; +"local_notification.non_compliant_wifi.text" = "轻点此处以保护您的设备"; + // SHORTCUTS "shortcuts.connect" = "连接"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "活跃主题"; "settings.application_settings.kill_switch.title" = "VPN 切断开关"; "settings.application_settings.kill_switch.footer" = "如果 VPN 连接重新连线,VPN 终止开关会阻止访问互联网。这不包括手动断开连接。"; +"settings.application_settings.leak_protection.title" = "泄露保护"; +"settings.application_settings.leak_protection.footer" = "iOS 包含默认在 VPN 之外运行的功能,例如 AirDrop、CarPlay、AirPlay 和个人热点。启用自定义泄露保护会通过 VPN 路由这些流量,但可能会影响这些功能的运行。更多信息"; +"settings.application_settings.leak_protection.more_info" = "更多信息"; +"settings.application_settings.allow_local_network.title" = "允许访问本地网络上的设备"; +"settings.application_settings.allow_local_network.footer" = "连接到 VPN 时,保持与打印机或文件服务器等本地设备的连接。(仅当您信任网络上的人员和设备时才允许此功能。)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™可在您连接到 VPN 时阻止广告、跟踪和恶意软件。"; +"settings.application_settings.leak_protection.alert.title" = "对 VPN 设置的更改将在下次连接时生效"; "settings.content_blocker.title" = "Safari 内容拦截器状态"; "settings.content_blocker.state.title" = "当前状态"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN 连接按钮。VPN 当前已断开连接"; "dashboard.accessibility.vpn.button.isOff" = "VPN 连接按钮。VPN 当前已断开连接"; +"dashboard.vpn.leakprotection.alert.title" = "检测到不安全的 Wi-Fi"; +"dashboard.vpn.leakprotection.alert.message" = "为防止数据泄露,请轻点“立即停用”以关闭“允许访问本地网络上的设备”并自动重新连接。"; +"dashboard.vpn.leakprotection.alert.cta1" = "立即停用"; +"dashboard.vpn.leakprotection.alert.cta2" = "了解详情"; +"dashboard.vpn.leakprotection.alert.cta3" = "忽略"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "为防止数据泄露,请轻点“立即切换”以更改为 IKEv2 VPN 协议并自动重新连接。"; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "立即切换"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "显示服务通信消息"; "inapp.messages.settings.updated" = "设置已更新"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "地区"; +"widget.liveActivity.protocol.title" = "协议"; diff --git a/PIA VPN/zh-Hant.lproj/Localizable.strings b/PIA VPN/zh-Hant.lproj/Localizable.strings index 98795d30e..48a0d5a27 100644 --- a/PIA VPN/zh-Hant.lproj/Localizable.strings +++ b/PIA VPN/zh-Hant.lproj/Localizable.strings @@ -38,6 +38,9 @@ "expiration.title" = "續訂"; "expiration.message" = "您的訂購計劃即將屆滿,請續約以讓自己繼續獲得保障。"; +"local_notification.non_compliant_wifi.title" = "不安全的 Wi-Fi 網路:%@"; +"local_notification.non_compliant_wifi.text" = "點一下這裡即可保護裝置"; + // SHORTCUTS "shortcuts.connect" = "連線"; @@ -134,8 +137,14 @@ "settings.application_settings.active_theme.title" = "使用中的主題"; "settings.application_settings.kill_switch.title" = "VPN 切斷開關"; "settings.application_settings.kill_switch.footer" = "如果 VPN 重新連接,VPN 的終止開關將阻止互聯網連線。這不包括手動斷開連接。"; +"settings.application_settings.leak_protection.title" = "防漏"; +"settings.application_settings.leak_protection.footer" = "iOS 內建功能依預設能在 VPN 以外運作,例如 AirDrop、CarPlay、AirPlay 和個人熱點。如果啟用自定防漏功能,就會把這個流量透過 VPN 轉出,但也可能影響這些功能。詳情"; +"settings.application_settings.leak_protection.more_info" = "詳情"; +"settings.application_settings.allow_local_network.title" = "同意取用本機網路上的裝置"; +"settings.application_settings.allow_local_network.footer" = "在連接到 VPN 時繼續連線到本機裝置,例如印表機或檔案伺服器。(只有在您相信網路上的人和裝置時才能同意)"; "settings.application_settings.mace.title" = "PIA MACE™"; "settings.application_settings.mace.footer" = "PIA MACE™ 會在您連線到 VPN 時封鎖廣告、追蹤器及惡意程式。"; +"settings.application_settings.leak_protection.alert.title" = "更改 VPN 設定後,將在下次連線時生效"; "settings.content_blocker.title" = "Safari 內容阻擋器狀態"; "settings.content_blocker.state.title" = "目前狀態"; @@ -215,6 +224,15 @@ "dashboard.accessibility.vpn.button.isOn" = "VPN 連線按鈕。目前已連線至 VPN"; "dashboard.accessibility.vpn.button.isOff" = "VPN 連線按鈕。目前已解除 VPN 連線"; +"dashboard.vpn.leakprotection.alert.title" = "系統偵測到無安全保護的 Wi-Fi 網路"; +"dashboard.vpn.leakprotection.alert.message" = "若要避免資料洩漏,請點一下「立即停用」,以便關掉「同意取用本機網路上的裝置」,然後自動重新連線。"; +"dashboard.vpn.leakprotection.alert.cta1" = "立即停用"; +"dashboard.vpn.leakprotection.alert.cta2" = "更多內容"; +"dashboard.vpn.leakprotection.alert.cta3" = "忽略"; + +"dashboard.vpn.leakprotection.ikev2.alert.message" = "若要避免資料洩漏,請點一下「立即切換」,以便改成 IKEv2 VPN 通訊協定,然後自動重新連線。"; +"dashboard.vpn.leakprotection.ikev2.alert.cta1" = "立即切換"; + // VPN PERMISSION "vpn_permission.title" = "PIA"; @@ -416,3 +434,7 @@ // INAPP MESSAGES "inapp.messages.toggle.title" = "顯示服務通訊訊息"; "inapp.messages.settings.updated" = "已更新設定"; + +// PIA WIDGET +"widget.liveActivity.region.title" = "區域"; +"widget.liveActivity.protocol.title" = "通訊協定"; diff --git a/PIA VPNTests/Core/PIACardTests.swift b/PIA VPNTests/Core/PIACardTests.swift index b104b9c8f..48e6b02c5 100644 --- a/PIA VPNTests/Core/PIACardTests.swift +++ b/PIA VPNTests/Core/PIACardTests.swift @@ -24,15 +24,19 @@ import PIALibrary @testable import PIA_VPN class PIACardTests: XCTestCase { - - func testCards() throws { - - let appVersion = "3.7.1" - - let cards = CardFactory.getCardsForVersion(appVersion) - XCTAssertTrue(cards.count == 1, "one card for version 3.7.1") - - } + + func testCards() throws { + + let appVersion = "3.7.1" + + let cards = CardFactory.getCardsForVersion(appVersion) + XCTAssertTrue(cards.count == 1, "one card for version 3.7.1") + + } + + func testShouldFail() { + XCTAssertFalse(true) + } func testCardsInvalidVersion() throws { diff --git a/PIA VPNTests/Core/Utils/PIAHotspotHelperTests.swift b/PIA VPNTests/Core/Utils/PIAHotspotHelperTests.swift index 26140bcbe..cb578b8f4 100644 --- a/PIA VPNTests/Core/Utils/PIAHotspotHelperTests.swift +++ b/PIA VPNTests/Core/Utils/PIAHotspotHelperTests.swift @@ -69,7 +69,7 @@ class PIAHotspotHelperTests: XCTestCase { } func testConfiguration() { - + /* #if arch(i386) || arch(x86_64) XCTAssertTrue(true) #else @@ -87,5 +87,6 @@ class PIAHotspotHelperTests: XCTestCase { response = hotspotHelper.configureHotspotHelper() XCTAssertFalse(response) #endif + */ } } diff --git a/PIA-VPN_E2E_Tests/Core/BaseTest.swift b/PIA-VPN_E2E_Tests/Core/BaseTest.swift new file mode 100644 index 000000000..837cfc9b1 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Core/BaseTest.swift @@ -0,0 +1,28 @@ +// +// BaseTest.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 17/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import Quick +import Nimble +import XCTest + +class BaseTest: QuickSpec{ + static var app: XCUIApplication! + + override class func spec(){ + beforeEach { + app = XCUIApplication() + app.launch() + app.logOut() + app.navigateToLoginScreen() + } + + afterEach { + app.terminate() + } + } +} diff --git a/PIA-VPN_E2E_Tests/Helpers/ElementHelper.swift b/PIA-VPN_E2E_Tests/Helpers/ElementHelper.swift new file mode 100644 index 000000000..91c468989 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Helpers/ElementHelper.swift @@ -0,0 +1,55 @@ +// +// ElementHelper.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 23/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication { + var defaultTimeout: TimeInterval { 10.0 } + var shortTimeout: TimeInterval { 5.0 } + + func navigationbar(with id: String) -> XCUIElement{ + return navigationBars[id] + } + + func button(with id: String) -> XCUIElement { + return buttons[id] + } + + func textField(with id: String) -> XCUIElement { + return textFields[id] + } + + func secureTextField(with id: String) -> XCUIElement { + return secureTextFields[id] + } + + func staticText(with id: String) -> XCUIElement{ + return staticTexts[id] + } + + func alert(with id: String) -> XCUIElement{ + return alerts[id] + } + + func otherElement(with id: String) -> XCUIElement { + return otherElements[id] + } + + func cell(with id: String) -> XCUIElement { + return cells[id] + } + + func searchField(with id: String) -> XCUIElement { + return searchFields[id] + } + + func image(with id: String) -> XCUIElement { + return images[id] + } +} + diff --git a/PIA-VPN_E2E_Tests/Helpers/WaitHelper.swift b/PIA-VPN_E2E_Tests/Helpers/WaitHelper.swift new file mode 100644 index 000000000..b761a71fc --- /dev/null +++ b/PIA-VPN_E2E_Tests/Helpers/WaitHelper.swift @@ -0,0 +1,55 @@ +// +// WaitHelper.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 24/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +enum ElementError: Error, CustomStringConvertible{ + case visibilityTimeout + case invisibilityTimeout + + var description: String{ + switch self{ + case .visibilityTimeout: + return "Element visibility check timed out." + case .invisibilityTimeout: + return "Element invisibility check timed out." + } + } +} + +class WaitHelper{ + static var app: XCUIApplication! + + static func waitForElementToBeVisible(_ element:XCUIElement,timeout: TimeInterval = app.defaultTimeout, onSuccess:() -> Void, onFailure:(ElementError) -> Void){ + let predicate = NSPredicate(format:"exists == true") + let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element) + let result = XCTWaiter.wait(for: [expectation], timeout: timeout) + + if result == .completed { + onSuccess() + } + + else{ + onFailure(.visibilityTimeout) + } + } + + static func waitForElementToNotBeVisible(_ element:XCUIElement, timeout: TimeInterval = app.defaultTimeout, onSuccess:() -> Void, onFailure:(ElementError) -> Void){ + let predicate = NSPredicate(format:"exists == false") + let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element) + let result = XCTWaiter.wait(for: [expectation], timeout: timeout) + + if result == .completed { + onSuccess() + } + + else{ + onFailure(.invisibilityTimeout) + } + } +} diff --git a/PIA-VPN_E2E_Tests/PIA-VPN-e2e-simulator.xctestplan b/PIA-VPN_E2E_Tests/PIA-VPN-e2e-simulator.xctestplan new file mode 100644 index 000000000..68724644a --- /dev/null +++ b/PIA-VPN_E2E_Tests/PIA-VPN-e2e-simulator.xctestplan @@ -0,0 +1,33 @@ +{ + "configurations" : [ + { + "id" : "266D4459-F88E-44D2-B611-230657A392ED", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "environmentVariableEntries" : [ + { + "key" : "PIA_TEST_USER", + "value" : "xxx" + }, + { + "key" : "PIA_TEST_PASSWORD", + "value" : "xxx" + } + ] + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:PIA VPN.xcodeproj", + "identifier" : "69B70AAF2ACBF51C0072A09D", + "name" : "PIA-VPN_E2E_Tests" + } + } + ], + "version" : 1 +} diff --git a/PIA-VPN_E2E_Tests/Screens/Common.swift b/PIA-VPN_E2E_Tests/Screens/Common.swift new file mode 100644 index 000000000..a8b44cbff --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/Common.swift @@ -0,0 +1,31 @@ +// +// Common.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 24/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication{ + /// Sometimes a system alert to request permissions about Notifications or VPN profile installation can appear + /// at any time when the app is running + /// This makes not possible to contitnue with the test unless the alert is dismissed + /// This method dismisses any system alert by pressing 'Allow' button + /// It is adviced that we call this method from all the `setUp` method of the tests from the authentication flow + /// For tests where we require the app to be authenticated, + /// use the method `loginAndInstallVPNProfile(from test: XCTestCase)` from the `setUp` method of the `XCTestCase` + func dismissAnyPermissionSystemAlert(from test: XCTestCase) { + test.addUIInterruptionMonitor(withDescription: "Any system permission alert") { element in + + let allowButton = element.buttons["Allow"].firstMatch + if element.elementType == .alert && allowButton.exists { + allowButton.tap() + return true + } else { + return false + } + } + } +} diff --git a/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift b/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift new file mode 100644 index 000000000..ad183db20 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift @@ -0,0 +1,40 @@ +// +// DashboardScreen.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 17/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication{ + var dashboardMenuButton: XCUIElement{ + button(with: PIALibraryAccessibility.Id.Dashboard.menu) + } + + var connectionButton: XCUIElement { + button(with: AccessibilityId.Dashboard.connectionButton) + } + + var confirmationDialogButton: XCUIElement{ + button(with: PIALibraryAccessibility.Id.Dialog.destructive) + } + + var logOutButton: XCUIElement{ + staticText(with: "Log out") + } + + func logOut() { + guard dashboardMenuButton.exists else { return } + dashboardMenuButton.tap() + + if logOutButton.waitForExistence(timeout: defaultTimeout) { + logOutButton.tap() + if confirmationDialogButton.waitForExistence(timeout: shortTimeout) { + confirmationDialogButton.tap() + } + welcomeLoginButton.waitForExistence(timeout: defaultTimeout) + } + } +} diff --git a/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift b/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift new file mode 100644 index 000000000..17701694b --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift @@ -0,0 +1,55 @@ + +import XCTest + +extension XCUIApplication { + var loginButton: XCUIElement { + button(with: PIALibraryAccessibility.Id.Login.submit) + } + + var loginUsernameTextField: XCUIElement { + textField(with: PIALibraryAccessibility.Id.Login.username) + } + + var loginPasswordTextField: XCUIElement { + secureTextField(with: PIALibraryAccessibility.Id.Login.password) + } + + var loginErrorMessage: XCUIElement { + otherElement(with: PIALibraryAccessibility.Id.Login.Error.banner) + } + + func fillLoginScreen(with credentials: Credentials) { + loginUsernameTextField.waitForExistence(timeout: defaultTimeout) && loginPasswordTextField.waitForExistence(timeout: defaultTimeout) + loginUsernameTextField.tap() + loginUsernameTextField.typeText(credentials.username) + loginPasswordTextField.tap() + loginPasswordTextField.typeText(credentials.password) + } + + /// This method authenticates the user and installs the VPN profile + /// Use this method when we are testing flows where the app has to be logged in already. + /// In such cases, it is recommended to call this method from the `setUp` of each `XCTestCase` class + /// NOTE: the app must be already in the Login Screen for this method to work + /// So before calling this method, make sure to navigate to the login screen + func loginAndInstallVPNProfile(from test: XCTestCase) { + // Listens to any interruption due to a system alert permission + // and presses the 'Allow' button + // (like the VPN Permission system alert) + dismissAnyPermissionSystemAlert(from: test) + + // Log out if needed + logOut() + + navigateToLoginScreen() + fillLoginScreen(with: CredentialsUtil.credentials(type: .valid)) + loginButton.tap() + + guard vpnPermissionScreen.waitForExistence(timeout: defaultTimeout) else { return } + guard vpnPermissionButton.exists else { return } + vpnPermissionButton.tap() + + swipeUp() + + connectionButton.waitForExistence(timeout: defaultTimeout) + } +} diff --git a/PIA-VPN_E2E_Tests/Screens/VPNPermissionScreen.swift b/PIA-VPN_E2E_Tests/Screens/VPNPermissionScreen.swift new file mode 100644 index 000000000..d75594192 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/VPNPermissionScreen.swift @@ -0,0 +1,28 @@ +// +// VPNPermissionScreen.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 17/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication{ + + var vpnPermissionScreen: XCUIElement { + otherElement(with: AccessibilityId.VPNPermission.screen) + } + + var vpnPermissionButton: XCUIElement{ + button(with: AccessibilityId.VPNPermission.submit) + } + + var vpnPermissionAlertText: XCUIElement{ + alert(with: "PIA VPN dev” Would Like to Add VPN Configurations") + } + + var vpnAllowButton: XCUIElement{ + button(with: "Allow").firstMatch + } +} diff --git a/PIA-VPN_E2E_Tests/Screens/WelcomeScreen.swift b/PIA-VPN_E2E_Tests/Screens/WelcomeScreen.swift new file mode 100644 index 000000000..b02e21827 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/WelcomeScreen.swift @@ -0,0 +1,29 @@ +// +// WelcomeScreen.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 24/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication { + var welcomeLoginButton: XCUIElement { + button(with: PIALibraryAccessibility.Id.Login.submitNew) + } + + var welcomeLoginButtonOldVersion: XCUIElement { + button(with: PIALibraryAccessibility.Id.Login.submit) + } + + func navigateToLoginScreen() { + if welcomeLoginButton.waitForExistence(timeout: shortTimeout) { + welcomeLoginButton.tap() + } else { + if welcomeLoginButtonOldVersion.waitForExistence(timeout: shortTimeout) { + welcomeLoginButtonOldVersion.tap() + } + } + } +} diff --git a/PIA-VPN_E2E_Tests/Tests/OnboardingTests.swift b/PIA-VPN_E2E_Tests/Tests/OnboardingTests.swift new file mode 100644 index 000000000..cad093f5c --- /dev/null +++ b/PIA-VPN_E2E_Tests/Tests/OnboardingTests.swift @@ -0,0 +1,35 @@ +// +// OnboardingTests.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 17/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import Nimble + +class OnboardingTests:BaseTest{ + override class func spec(){ + super.spec() + + describe("onboarding vpn permission tests"){ + context("vpn profile installation permission"){ + it("should display the home screen after allowing vpn profile installation"){ + app.fillLoginScreen(with: CredentialsUtil.credentials(type: .valid)) + app.loginButton.tap() + app.vpnPermissionScreen.waitForExistence(timeout:app.defaultTimeout) + app.vpnPermissionButton.waitForExistence(timeout:app.defaultTimeout) + + app.vpnPermissionButton.tap() + + app.vpnPermissionAlertText.waitForExistence(timeout: app.defaultTimeout) + app.vpnAllowButton.waitForExistence(timeout: app.defaultTimeout) + app.swipeUp() + + expect(app.dashboardMenuButton.waitForExistence(timeout: app.defaultTimeout)) + expect(app.vpnPermissionScreen.exists).to(beFalse()) + } + } + } + } +} diff --git a/PIA-VPN_E2E_Tests/Tests/PIAExampleWithAuthenticatedAppTest.swift b/PIA-VPN_E2E_Tests/Tests/PIAExampleWithAuthenticatedAppTest.swift new file mode 100644 index 000000000..720a33649 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Tests/PIAExampleWithAuthenticatedAppTest.swift @@ -0,0 +1,45 @@ +// +// PIAExampleWithAuthenticatedAppTest.swift +// PIA-VPN_E2E_Tests +// +// Created by Laura S on 10/6/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +/// This is an example of how to setup a XCTestCase +/// with the app on Authenticated state and the VPN Profile installed +/// from the Onboarding flow +final class PIAExampleWithAuthenticatedAppTest: XCTestCase { + private var app: XCUIApplication! + + override func setUpWithError() throws { + continueAfterFailure = false + // 1. Instantiate the app process + app = XCUIApplication(bundleIdentifier: "com.privateinternetaccess.ios.PIA-VPN") + // 2. Launch the app process + app.launch() + + // 3. Authenticates with valid credentials coming from the Environment variables and installs the VPN Profile + app.loginAndInstallVPNProfile(from: self) + + // NOTE: To add valid credentials in the Environment Variables: + // - Select `PIA-VPN_E2E_Tests` schema + // - On the dropdown menu -> Edit Scheme + // - Tap the 'Run' Button from the left side + // - Add correct values on the Env Variables called `PIA_TEST_USER` and `PIA_TEST_PASSWORD` -> IMPORTANT: Do not commit these updates + } + + override func tearDownWithError() throws { + // Terminates the app process everytime a test has finished its execution + app.terminate() + } + + func testExample() throws { + + // Additional test steps here... + } + + +} diff --git a/PIA-VPN_E2E_Tests/Tests/SignInTests.swift b/PIA-VPN_E2E_Tests/Tests/SignInTests.swift new file mode 100644 index 000000000..28c47ccd0 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Tests/SignInTests.swift @@ -0,0 +1,32 @@ +// +// SignInTests.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 17/10/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import Nimble + +class SignInTests: BaseTest { + override class func spec(){ + super.spec() + + describe("test sign-in"){ + context("account validations"){ + it("should successfully sign in with valid credentials"){ + app.fillLoginScreen(with: CredentialsUtil.credentials(type: .valid)) + app.loginButton.tap() + expect(app.vpnPermissionScreen.waitForExistence(timeout:app.defaultTimeout)).to(beTrue()) + } + + it("should display error mesages with invalid credentials"){ + app.fillLoginScreen(with: CredentialsUtil.credentials(type: .invalid)) + app.loginButton.tap() + expect(app.loginErrorMessage.waitForExistence(timeout: app.shortTimeout)).to(beTrue()) + expect(app.vpnPermissionScreen.waitForExistence(timeout:app.defaultTimeout)).to(beFalse()) + } + } + } + } +} diff --git a/PIA-VPN_E2E_Tests/Util/CredentialsUtil.swift b/PIA-VPN_E2E_Tests/Util/CredentialsUtil.swift new file mode 100644 index 000000000..48d744d0e --- /dev/null +++ b/PIA-VPN_E2E_Tests/Util/CredentialsUtil.swift @@ -0,0 +1,32 @@ +// +// CredentialsUtil.swift +// PIA VPN +// +// Created by Waleed Mahmood on 08.03.22. +// Copyright © 2022 Private Internet Access Inc. All rights reserved. +// + +import Foundation + +public enum CredentialsType: String { + case valid = "valid" + case invalid = "invalid" +} + +public struct Credentials: Codable { + let username: String + let password: String +} + +public class CredentialsUtil { + public static func credentials(type: CredentialsType) -> Credentials { + switch type { + case .invalid: + return Credentials(username: "fakeUser", password: "fakePassword123") + case .valid: + let testUser = ProcessInfo.processInfo.environment["PIA_TEST_USER"] ?? "user-not-found" + let testPassword = ProcessInfo.processInfo.environment["PIA_TEST_PASSWORD"] ?? "password-not-found" + return Credentials(username: testUser, password: testPassword) + } + } +} diff --git a/PIAWidget/Assets.xcassets/PIA-logo.imageset/Contents.json b/PIAWidget/Assets.xcassets/PIA-logo.imageset/Contents.json new file mode 100644 index 000000000..02b5d87ae --- /dev/null +++ b/PIAWidget/Assets.xcassets/PIA-logo.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Group.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/PIA-logo.imageset/Group.pdf b/PIAWidget/Assets.xcassets/PIA-logo.imageset/Group.pdf new file mode 100644 index 000000000..9936158f2 Binary files /dev/null and b/PIAWidget/Assets.xcassets/PIA-logo.imageset/Group.pdf differ diff --git a/PIAWidget/Assets.xcassets/connected-button.imageset/Contents.json b/PIAWidget/Assets.xcassets/connected-button.imageset/Contents.json new file mode 100644 index 000000000..84d9e024a --- /dev/null +++ b/PIAWidget/Assets.xcassets/connected-button.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Group 13.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/connected-button.imageset/Group 13.pdf b/PIAWidget/Assets.xcassets/connected-button.imageset/Group 13.pdf new file mode 100644 index 000000000..af5a88943 Binary files /dev/null and b/PIAWidget/Assets.xcassets/connected-button.imageset/Group 13.pdf differ diff --git a/PIAWidget/Assets.xcassets/connecting-button.imageset/Contents.json b/PIAWidget/Assets.xcassets/connecting-button.imageset/Contents.json new file mode 100644 index 000000000..065a20d84 --- /dev/null +++ b/PIAWidget/Assets.xcassets/connecting-button.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "State=Connecting.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/connecting-button.imageset/State=Connecting.pdf b/PIAWidget/Assets.xcassets/connecting-button.imageset/State=Connecting.pdf new file mode 100644 index 000000000..c80d3069a Binary files /dev/null and b/PIAWidget/Assets.xcassets/connecting-button.imageset/State=Connecting.pdf differ diff --git a/PIAWidget/Assets.xcassets/disconnected-button.imageset/ButtonDisconnected.pdf b/PIAWidget/Assets.xcassets/disconnected-button.imageset/ButtonDisconnected.pdf new file mode 100644 index 000000000..cfcdb2c48 Binary files /dev/null and b/PIAWidget/Assets.xcassets/disconnected-button.imageset/ButtonDisconnected.pdf differ diff --git a/PIAWidget/Assets.xcassets/disconnected-button.imageset/Contents.json b/PIAWidget/Assets.xcassets/disconnected-button.imageset/Contents.json new file mode 100644 index 000000000..f2933b6fa --- /dev/null +++ b/PIAWidget/Assets.xcassets/disconnected-button.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "ButtonDisconnected.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/disconnected-cross.imageset/Contents.json b/PIAWidget/Assets.xcassets/disconnected-cross.imageset/Contents.json new file mode 100644 index 000000000..8f0a02cbc --- /dev/null +++ b/PIAWidget/Assets.xcassets/disconnected-cross.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "IconDisconnected.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/disconnected-cross.imageset/IconDisconnected.pdf b/PIAWidget/Assets.xcassets/disconnected-cross.imageset/IconDisconnected.pdf new file mode 100644 index 000000000..a627c0ed8 Binary files /dev/null and b/PIAWidget/Assets.xcassets/disconnected-cross.imageset/IconDisconnected.pdf differ diff --git a/PIAWidget/Assets.xcassets/green-checkmark.imageset/Contents.json b/PIAWidget/Assets.xcassets/green-checkmark.imageset/Contents.json new file mode 100644 index 000000000..5c2f805eb --- /dev/null +++ b/PIAWidget/Assets.xcassets/green-checkmark.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Icon.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Assets.xcassets/green-checkmark.imageset/Icon.pdf b/PIAWidget/Assets.xcassets/green-checkmark.imageset/Icon.pdf new file mode 100644 index 000000000..bf5bcc075 Binary files /dev/null and b/PIAWidget/Assets.xcassets/green-checkmark.imageset/Icon.pdf differ diff --git a/PIAWidget/Assets.xcassets/ios-widget.imageset/Badge.pdf b/PIAWidget/Assets.xcassets/ios-widget.imageset/Badge.pdf new file mode 100644 index 000000000..10ca08c10 Binary files /dev/null and b/PIAWidget/Assets.xcassets/ios-widget.imageset/Badge.pdf differ diff --git a/PIAWidget/Assets.xcassets/ios-widget.imageset/Contents.json b/PIAWidget/Assets.xcassets/ios-widget.imageset/Contents.json new file mode 100644 index 000000000..c9eb8c559 --- /dev/null +++ b/PIAWidget/Assets.xcassets/ios-widget.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Badge.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/PIAWidget/Domain/UI/PIACircleIcon.swift b/PIAWidget/Domain/UI/PIACircleIcon.swift new file mode 100644 index 000000000..628e06a4e --- /dev/null +++ b/PIAWidget/Domain/UI/PIACircleIcon.swift @@ -0,0 +1,26 @@ + +import SwiftUI + +internal struct PIACircleIcon: View { + + internal let size: CGFloat + internal let iconWidth: CGFloat + + init(size: CGFloat) { + self.size = size + self.iconWidth = (size / 2) + } + + var body: some View { + return ZStack { + Circle() + .fill(Color("BorderColor")) + .frame(width: size) + Image("ios-widget") + .resizable() + .frame(width: iconWidth, height: (iconWidth + 3)) + .padding() + } + } +} + diff --git a/PIAWidget/Domain/UI/PIACircleImageView.swift b/PIAWidget/Domain/UI/PIACircleImageView.swift new file mode 100644 index 000000000..486118d7b --- /dev/null +++ b/PIAWidget/Domain/UI/PIACircleImageView.swift @@ -0,0 +1,26 @@ + +import SwiftUI + +internal struct PIACircleImageView: View { + + internal let size: CGFloat + internal let image: String + internal let contentMode: ContentMode + + + init(size: CGFloat, image: String, contentMode: ContentMode = .fit) { + self.size = size + self.image = image + self.contentMode = contentMode + } + + var body: some View { + Image(image) + .resizable() + .aspectRatio(contentMode: contentMode) + .frame(width: size, height: size) + .clipShape(Circle()) + } +} + + diff --git a/PIAWidget/Domain/UI/PIAConnectionView.swift b/PIAWidget/Domain/UI/PIAConnectionView.swift new file mode 100644 index 000000000..e947e9017 --- /dev/null +++ b/PIAWidget/Domain/UI/PIAConnectionView.swift @@ -0,0 +1,61 @@ + +import SwiftUI +import WidgetKit + +@available(iOSApplicationExtension 16.1, *) +internal struct PIAConnectionView: View { + + internal let context: ActivityViewContext + internal let showProtocol: Bool + let localizedRegionText = L10n.Widget.LiveActivity.Region.title + let localizedProtocolText = L10n.Widget.LiveActivity.SelectedProtocol.title + + init(context: ActivityViewContext, showProtocol: Bool = false) { + self.context = context + self.showProtocol = showProtocol + } + + var body: some View { + HStack { + HStack { + PIACircleImageView(size: 24, image: context.state.regionFlag, contentMode: .fill) + VStack(alignment: .leading) { + Text(localizedRegionText) + .font(.caption) + .foregroundColor(.white) + Text(context.state.regionName) + .font(.caption) + .foregroundColor(.white) + .bold() + } + if showProtocol && context.state.connected { + HStack { + Spacer() + PIACircleImageView(size: 24, image: "green-checkmark") + VStack(alignment: .leading) { + Text(localizedProtocolText) + .font(.caption) + .foregroundColor(.white) + Text(context.state.vpnProtocol) + .font(.caption) + .foregroundColor(.white) + .bold() + } + Spacer() + } + } else { + Spacer() + } + + Link(destination: URL(string: "piavpn:connect")!) { + PIACircleImageView( + size: 54, + image: context.state.connected ? "connected-button" : "disconnected-button" + ) + } + } + } + + } +} + diff --git a/PIAWidget/Domain/Widget/PIAConnectionActivityWidget.swift b/PIAWidget/Domain/Widget/PIAConnectionActivityWidget.swift new file mode 100644 index 000000000..1bd6eb2dc --- /dev/null +++ b/PIAWidget/Domain/Widget/PIAConnectionActivityWidget.swift @@ -0,0 +1,84 @@ + +import WidgetKit +import SwiftUI + +@available(iOSApplicationExtension 16.1, *) +struct PIAConnectionActivityWidget: Widget { + let localizedRegionText = L10n.Widget.LiveActivity.Region.title + + var body: some WidgetConfiguration { + ActivityConfiguration(for: PIAConnectionAttributes.self) { context in + // Create the view that appears on the Lock Screen and as a + // banner on the Home Screen of devices that don't support the + // Dynamic Island. + VStack { + HStack(alignment: .bottom, spacing: 4) { + Image("ios-widget") + .resizable() + .frame(width: 16, height: 22) + Image("PIA-logo") + .resizable() + .frame(width: 30, height: 14) + .padding(.bottom, 1) + } + .padding(.bottom) + PIAConnectionView(context: context, showProtocol: true) + .activityBackgroundTint(Color.black.opacity(0.85)) + } + .padding() + + } dynamicIsland: { context in + // Create the views that appear in the Dynamic Island. + DynamicIsland { + // This content will be shown when user expands the island + DynamicIslandExpandedRegion(.leading, priority: 300) { + PIACircleImageView(size: 46, image: context.state.regionFlag, contentMode: .fill) + } + + DynamicIslandExpandedRegion(.trailing, priority: 200) { + Link(destination: URL(string: "piavpn:connect")!) { + PIACircleImageView( + size: 50, + image: context.state.connected ? "connected-button" : "disconnected-button" + ) + + } + } + + DynamicIslandExpandedRegion(.center, priority: 100) { + VStack(alignment: .leading) { + Text(localizedRegionText) + .font(.caption) + .foregroundColor(.white) + .padding(.top, -8) + Text(context.state.regionName) + .font(.caption) + .foregroundColor(.white) + .bold() + } + .frame(minWidth: (UIScreen.main.bounds.size.width * 0.56), alignment: .leading) + .dynamicIsland(verticalPlacement: .belowIfTooWide) + + } + DynamicIslandExpandedRegion(.bottom) { + // Empty + } + } compactLeading: { + // When the island is wider than the display cutout + PIACircleIcon(size: 28.0) + } compactTrailing: { + // When the island is wider than the display cutout + PIACircleImageView( + size: 24, + image: context.state.connected ? "green-checkmark" : "disconnected-cross" + ) + } minimal: { + // This is used when there are multiple activities + PIACircleIcon(size: 28.0) + } + .contentMargins(.leading, 0, for: .compactLeading) + + } + } +} + diff --git a/PIAWidget/Domain/Widget/PIAConnectionLiveActivityManager.swift b/PIAWidget/Domain/Widget/PIAConnectionLiveActivityManager.swift new file mode 100644 index 000000000..2c2994853 --- /dev/null +++ b/PIAWidget/Domain/Widget/PIAConnectionLiveActivityManager.swift @@ -0,0 +1,85 @@ + +import Foundation +import ActivityKit + +public protocol PIAConnectionLiveActivityManagerType { + func startLiveActivity(with state: PIAConnectionAttributes.ContentState) + func endLiveActivities() +} + +@available(iOS 16.2, *) +public final class PIAConnectionLiveActivityManager: PIAConnectionLiveActivityManagerType { + + private var activity: Activity? + private var currentActivityPriority = 0 + + static let shared = PIAConnectionLiveActivityManager() + + private init() {} + + deinit { + endLiveActivities() + } + + public func startLiveActivity(with state: PIAConnectionAttributes.ContentState) { + guard activity == nil else { + updateLiveActivity(with: state) + return + } + + createNewLiveActivity(with: state) + + } + + public func endLiveActivities() { + let currentActivities = Activity.activities + + guard !currentActivities.isEmpty else { return } + + let semaphore = DispatchSemaphore(value: 0) + + Task { + for act in currentActivities { + await act.end(dismissalPolicy: .immediate) + + semaphore.signal() + } + } + semaphore.wait() + + } + + public func endPreviousActivities() { + let currentActivities = Activity.activities + for act in currentActivities { + Task { + await act.end(dismissalPolicy: .immediate) + } + } + activity = nil + } + + private func createNewLiveActivity(with state: PIAConnectionAttributes.ContentState) { + // Clear all the Live Activities before starting a new one + endPreviousActivities() + + let attributes = PIAConnectionAttributes() + + activity = try? Activity.request(attributes: attributes, contentState: state, pushType: nil) + } + + private func updateLiveActivity(with state: PIAConnectionAttributes.ContentState) { + guard activity?.activityState == .active else { + createNewLiveActivity(with: state) + return + } + // Only update the live activity if there is new content + guard state != activity?.content.state else { return } + + Task { + await activity?.update(using: state) + } + + } + +} diff --git a/PIAWidget/Domain/Widget/PIAWidget.swift b/PIAWidget/Domain/Widget/PIAWidget.swift index 35268132b..b92986256 100644 --- a/PIAWidget/Domain/Widget/PIAWidget.swift +++ b/PIAWidget/Domain/Widget/PIAWidget.swift @@ -22,8 +22,9 @@ import WidgetKit import SwiftUI import Intents +import ActivityKit -@main +//@main struct PIAWidget: Widget { let kind: String = "PIAWidget" diff --git a/PIAWidget/Domain/Widget/PIAWidgetAttributes.swift b/PIAWidget/Domain/Widget/PIAWidgetAttributes.swift new file mode 100644 index 000000000..cca8d72ab --- /dev/null +++ b/PIAWidget/Domain/Widget/PIAWidgetAttributes.swift @@ -0,0 +1,17 @@ + +import Foundation +import ActivityKit + +public struct PIAConnectionAttributes: ActivityAttributes { + public typealias PIAConnectionStatus = ContentState + + public struct ContentState: Codable, Hashable { + var connected: Bool + var regionName: String + var regionFlag: String + var vpnProtocol: String + + } + +} + diff --git a/PIAWidget/Domain/Widget/PIAWidgetBundle.swift b/PIAWidget/Domain/Widget/PIAWidgetBundle.swift new file mode 100644 index 000000000..4c2613b53 --- /dev/null +++ b/PIAWidget/Domain/Widget/PIAWidgetBundle.swift @@ -0,0 +1,14 @@ +import WidgetKit +import SwiftUI + +@main +struct PIAWidgetBundle: WidgetBundle { + var body: some Widget { + PIAWidget() + + if #available(iOS 16.1, *) { + PIAConnectionActivityWidget() + } + } +} + diff --git a/PIAWidget/PIAWidget.swift b/PIAWidget/PIAWidget.swift deleted file mode 100644 index 9338a85f2..000000000 --- a/PIAWidget/PIAWidget.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// PIAWidget.swift -// PIA VPN -// -// Created by Jose Blaya on 24/09/2020. -// Copyright © 2020 Private Internet Access, Inc. -// -// This file is part of the Private Internet Access iOS Client. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// - -import WidgetKit -import SwiftUI -import Intents - -struct Provider: TimelineProvider { - - func placeholder(in context: Context) -> WidgetContent { - WidgetContent(date: Date(), - connected: false, - vpnProtocol: "IPSec (IKEv2)", - vpnPort: "500", - vpnSocket: "UDP") - } - - func getSnapshot(in context: Context, completion: @escaping (WidgetContent) -> ()) { - let entry: WidgetContent - entry = WidgetContent(date: Date(), - connected: WidgetUtils.isVPNConnected, - vpnProtocol: WidgetUtils.vpnProtocol, - vpnPort: WidgetUtils.vpnPort, - vpnSocket: WidgetUtils.vpnSocket) - completion(entry) - } - - func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { - var entries: [WidgetContent] = [] - - // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let currentDate = Date() - for hourOffset in 0 ..< 5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = WidgetContent(date: entryDate, - connected: WidgetUtils.isVPNConnected, - vpnProtocol: WidgetUtils.vpnProtocol, - vpnPort: WidgetUtils.vpnPort, - vpnSocket: WidgetUtils.vpnSocket) - entries.append(entry) - } - - let timeline = Timeline(entries: entries, policy: .atEnd) - completion(timeline) - } -} - -struct PIAWidgetEntryView : View { - - @Environment(\.widgetFamily) var widgetFamily - - var entry: Provider.Entry - - var body: some View { - - ZStack(alignment: .bottomTrailing) { - - Image("robot") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: widgetFamily == .systemMedium ? 100 : 50, height: widgetFamily == .systemMedium ? 100 : 50, alignment: .center) - .rotationEffect(Angle(degrees: -35.0)) - .padding(widgetFamily == .systemMedium ? -25 : -9) - - HStack { - - if WidgetUtils.isTrustedNetwork { - - Circle() - .strokeBorder(Color("BorderColor"),lineWidth: 6) - .background(Circle() - .strokeBorder(Color("TrustedNetworkColor"),lineWidth: 8) - .background(Image("vpn-button") - .resizable() - .renderingMode(.template).foregroundColor(Color("TrustedNetworkColor")) - .aspectRatio(contentMode: .fit) - .frame(width: 40, height: 40, alignment: .center) - .padding(0))) - .padding(20) - - } else { - Circle() - .strokeBorder(Color("BorderColor"),lineWidth: 6) - .background(Circle() - .strokeBorder(Color(WidgetUtils.isVPNConnected ? "AccentColor" : "RedColor"),lineWidth: 8) - .background(Image("vpn-button") - .resizable() - .renderingMode(.template).foregroundColor(Color(WidgetUtils.isVPNConnected ? "AccentColor" : "RedColor")) - .aspectRatio(contentMode: .fit) - .frame(width: 40, height: 40, alignment: .center) - .padding(0))) - .padding(20) - - } - - if widgetFamily == .systemMedium { - VStack { - HStack(alignment: .center, spacing: 0) { - Image("icon-protocol").resizable().frame(width: 25, height: 25, alignment: .leading) - Spacer() - Text(WidgetUtils.vpnProtocol).font(.system(size: 14)).foregroundColor(Color("FontColor")).frame(maxWidth: .infinity, alignment: .leading) - } - HStack(alignment: .center, spacing: 0) { - Image("icon-port").resizable().frame(width: 25, height: 25, alignment: .leading) - Spacer() - Text(WidgetUtils.vpnPort).font(.system(size: 14)).foregroundColor(Color("FontColor")).frame(maxWidth: .infinity, alignment: .leading) - } - HStack(alignment: .center, spacing: 0) { - Image("icon-socket").resizable().frame(width: 25, height: 25, alignment: .leading) - Spacer() - Text(WidgetUtils.vpnSocket).font(.system(size: 14)).foregroundColor(Color("FontColor")).frame(maxWidth: .infinity, alignment: .leading) - } - }.padding(.trailing, 40) - - } - - } - - }.widgetURL(URL(string: widgetFamily == .systemMedium ? "piavpn:view" : "piavpn:connect")) - .background(Color("WidgetBackground")) - - } - -} - -@main -struct PIAWidget: Widget { - let kind: String = "PIAWidget" - - var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in - PIAWidgetEntryView(entry: entry) - } - .configurationDisplayName("PIA VPN") - .description("") - .supportedFamilies([.systemSmall, .systemMedium]) - - } -} - -struct PIAWidget_Previews: PreviewProvider { - static var previews: some View { - PIAWidgetEntryView(entry: WidgetContent(date: Date(), connected: true, vpnProtocol: "IKEv2", vpnPort: "500", vpnSocket: "UDP")) - .previewContext(WidgetPreviewContext(family: .systemSmall)) - PIAWidgetEntryView(entry: WidgetContent(date: Date(), connected: false, vpnProtocol: "WireGuard", vpnPort: "1443", vpnSocket: "UDP")) - .previewContext(WidgetPreviewContext(family: .systemMedium)) - } -} diff --git a/PIAWidget/WidgetContent.swift b/PIAWidget/WidgetContent.swift deleted file mode 100644 index e15c8f53f..000000000 --- a/PIAWidget/WidgetContent.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// WidgetContent.swift -// PIA VPN -// -// Created by Jose Blaya on 24/09/2020. -// Copyright © 2020 Private Internet Access, Inc. -// -// This file is part of the Private Internet Access iOS Client. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// - -import Foundation -import WidgetKit - -struct WidgetContent: Codable, TimelineEntry { - - var date = Date() - - let connected: Bool - let vpnProtocol: String - let vpnPort: String - let vpnSocket: String - -} diff --git a/PIAWidget/WidgetUtils.swift b/PIAWidget/WidgetUtils.swift deleted file mode 100644 index 90af3576e..000000000 --- a/PIAWidget/WidgetUtils.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// WidgetUtils.swift -// PIA VPN -// -// Created by Jose Blaya on 25/09/2020. -// Copyright © 2020 Private Internet Access, Inc. -// -// This file is part of the Private Internet Access iOS Client. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// - -import Foundation - -public class WidgetUtils { - - private static let appGroup = "group.com.privateinternetaccess" - - static var isVPNConnected: Bool { - var connected = false - if let sharedDefaults = UserDefaults(suiteName: appGroup), - let status = sharedDefaults.string(forKey: "vpn.status") { - - if status == "connected" { - connected = true - } - - } - return connected - } - - static var isTrustedNetwork: Bool { - if let sharedDefaults = UserDefaults(suiteName: appGroup) { - return sharedDefaults.bool(forKey: "vpn.widget.trusted.network") - } - return false - } - - static var vpnProtocol: String { - if let sharedDefaults = UserDefaults(suiteName: appGroup), - let value = sharedDefaults.string(forKey: "vpn.widget.protocol") { - return value - } - return "--" - } - - static var vpnPort: String { - if let sharedDefaults = UserDefaults(suiteName: appGroup), - let value = sharedDefaults.string(forKey: "vpn.widget.port") { - return value - } - return "--" - } - - static var vpnSocket: String { - if let sharedDefaults = UserDefaults(suiteName: appGroup), - let value = sharedDefaults.string(forKey: "vpn.widget.socket") { - return value - } - return "--" - } - - -} diff --git a/Resources/GoogleService-Info.plist b/Resources/GoogleService-Info.plist deleted file mode 100644 index 0c67376eb..000000000 --- a/Resources/GoogleService-Info.plist +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/Resources/UI/en.lproj/Main.storyboard b/Resources/UI/en.lproj/Main.storyboard index b6eec2637..52056da2e 100644 --- a/Resources/UI/en.lproj/Main.storyboard +++ b/Resources/UI/en.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -14,20 +14,20 @@ - + - + - + - + @@ -43,7 +43,7 @@ - - + @@ -165,10 +165,10 @@ - +