diff --git a/PIA VPN-tvOS/Dashboard/CompositionRoot/DashboardFactory.swift b/PIA VPN-tvOS/Dashboard/CompositionRoot/DashboardFactory.swift index 86aafc16..10c2e2ec 100644 --- a/PIA VPN-tvOS/Dashboard/CompositionRoot/DashboardFactory.swift +++ b/PIA VPN-tvOS/Dashboard/CompositionRoot/DashboardFactory.swift @@ -5,10 +5,7 @@ import PIALibrary class DashboardFactory { static func makeDashboardView() -> DashboardView { - return DashboardView( - viewModel: makeDashboardViewModel(), - connectionButton: makePIAConnectionButton() - ) + return DashboardView(viewModel: makeDashboardViewModel()) } static func makeDashboardViewModel() -> DashboardViewModel { @@ -36,7 +33,52 @@ extension DashboardFactory { } private static func makeVpnConnectionUseCase() -> VpnConnectionUseCaseType { - return VpnConnectionUseCase() + return VpnConnectionUseCase(serverProvider: makeServerProvider()) + } + + private static func makeSelectedServerUserCase() -> SelectedServerUseCaseType { + return SelectedServerUseCase(serverProvider: makeServerProvider()) + } + + private static func makeSelectedServerViewModel() -> SelectedServerViewModel { + return SelectedServerViewModel(useCase: makeSelectedServerUserCase()) + } + + internal static func makeSelectedServerView() -> SelectedServerView { + SelectedServerView(viewModel: makeSelectedServerViewModel()) + } + +} + + +// MARK: QuickConnect section + +extension DashboardFactory { + + static func makeServerProvider() -> ServerProviderType { + guard let defaultServerProvider: DefaultServerProvider = + Client.providers.serverProvider as? DefaultServerProvider else { + fatalError("Incorrect server provider type") + } + + return defaultServerProvider + + } + + static internal func makeQuickConnectButtonViewModel(for server: ServerType, delegate: QuickConnectButtonViewModelDelegate?) -> QuickConnectButtonViewModel { + QuickConnectButtonViewModel(server: server, delegate: delegate) + } + + static func makeQuickConnectButton(for server: ServerType, delegate: QuickConnectButtonViewModelDelegate?) -> QuickConnectButton { + QuickConnectButton(viewModel: makeQuickConnectButtonViewModel(for: server, delegate: delegate)) + } + + static internal func makeQuickConnectViewModel() -> QuickConnectViewModel { + QuickConnectViewModel(connectUseCase: makeVpnConnectionUseCase(), selectedServerUseCase: makeSelectedServerUserCase()) + } + + static func makeQuickConnectView() -> QuickConnectView { + QuickConnectView(viewModel: makeQuickConnectViewModel()) } } diff --git a/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectButtonViewModel.swift b/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectButtonViewModel.swift new file mode 100644 index 00000000..d0583327 --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectButtonViewModel.swift @@ -0,0 +1,31 @@ + +import Foundation + +protocol QuickConnectButtonViewModelDelegate: AnyObject { + func quickConnectButtonViewModel(didSelect server: ServerType) +} + +class QuickConnectButtonViewModel: ObservableObject { + + private let server: ServerType + + @Published var flagName = "" + + weak var delegate: QuickConnectButtonViewModelDelegate? + + init(server: ServerType, delegate: QuickConnectButtonViewModelDelegate?) { + self.server = server + self.delegate = delegate + updateStatus() + } + + func connectButtonDidTap() { + delegate?.quickConnectButtonViewModel(didSelect: server) + } + + private func updateStatus() { + flagName = "flag-\(server.country.lowercased())" + } + + +} diff --git a/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectViewModel.swift b/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectViewModel.swift new file mode 100644 index 00000000..07c9c013 --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/Presentation/QuickConnectViewModel.swift @@ -0,0 +1,33 @@ + +import Foundation + +class QuickConnectViewModel: ObservableObject { + + @Published private (set) var servers: [ServerType] = [] + + private let connectUseCase: VpnConnectionUseCaseType + private let selectedServerUseCase: SelectedServerUseCaseType + + + init(connectUseCase: VpnConnectionUseCaseType, + selectedServerUseCase: SelectedServerUseCaseType) { + self.connectUseCase = connectUseCase + self.selectedServerUseCase = selectedServerUseCase + + updateStatus() + } + + func updateStatus() { + servers = selectedServerUseCase.getHistoricalServers() + } + +} + +extension QuickConnectViewModel: QuickConnectButtonViewModelDelegate { + + func quickConnectButtonViewModel(didSelect server: ServerType) { + connectUseCase.connect(to: server) + } + +} + diff --git a/PIA VPN-tvOS/Dashboard/Presentation/SelectedServerViewModel.swift b/PIA VPN-tvOS/Dashboard/Presentation/SelectedServerViewModel.swift new file mode 100644 index 00000000..7c7d93cc --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/Presentation/SelectedServerViewModel.swift @@ -0,0 +1,20 @@ + +import Foundation + + +class SelectedServerViewModel: ObservableObject { + let selectedSeverSectionTitle = L10n.Localizable.Tiles.Region.title.uppercased() + @Published var serverName: String = "" + + let useCase: SelectedServerUseCaseType + + init(useCase: SelectedServerUseCaseType) { + self.useCase = useCase + updateState() + } + + private func updateState() { + serverName = useCase.getSelectedServer().name + } + +} diff --git a/PIA VPN-tvOS/Dashboard/UI/DashboardView.swift b/PIA VPN-tvOS/Dashboard/UI/DashboardView.swift index a6ed2b3f..5f064f43 100644 --- a/PIA VPN-tvOS/Dashboard/UI/DashboardView.swift +++ b/PIA VPN-tvOS/Dashboard/UI/DashboardView.swift @@ -6,20 +6,32 @@ struct DashboardView: View { let viewHeight = UIScreen.main.bounds.height let viewModel: DashboardViewModel - let connectionButton: PIAConnectionButton var body: some View { VStack { - VStack(spacing: 20) { - connectionButton + VStack(alignment: .leading) { + DashboardConnectionButtonSection() .padding() + Divider() + + SelectedServerSection() + .padding() + + Divider() + + QuickConnectSection() + .frame(width: (viewWidth/2)) + + Divider() + + // TODO: Remove logout button from the Dashboard + // when we have it in the settings screen Button { viewModel.logOut() } label: { Text("LogOut") } - .padding() } .frame(maxWidth: (viewWidth/2)) @@ -33,9 +45,38 @@ struct DashboardView: View { } } +// MARK: Dashboard sections + +fileprivate struct DashboardConnectionButtonSection: View { + var body: some View { + HStack { + Spacer() + DashboardFactory.makePIAConnectionButton() + Spacer() + } + } +} + +fileprivate struct SelectedServerSection: View { + var body: some View { + Button { + // TODO: Navigate to the regions list + } label: { + DashboardFactory.makeSelectedServerView() + } + .buttonStyle(.plain) + .buttonBorderShape(.roundedRectangle(radius: 4)) + } +} + +fileprivate struct QuickConnectSection: View { + var body: some View { + DashboardFactory.makeQuickConnectView() + } +} + #Preview { DashboardView( - viewModel: DashboardFactory.makeDashboardViewModel(), - connectionButton: DashboardFactory.makePIAConnectionButton() + viewModel: DashboardFactory.makeDashboardViewModel() ) } diff --git a/PIA VPN-tvOS/Dashboard/UI/QuickConnectButton.swift b/PIA VPN-tvOS/Dashboard/UI/QuickConnectButton.swift new file mode 100644 index 00000000..df57bc10 --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/UI/QuickConnectButton.swift @@ -0,0 +1,29 @@ +// +// QuickConnectButton.swift +// PIA VPN-tvOS +// +// Created by Laura S on 12/26/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import SwiftUI + +struct QuickConnectButton: View { + @ObservedObject var viewModel: QuickConnectButtonViewModel + + var size: CGFloat = 65 + + var body: some View { + Button { + viewModel.connectButtonDidTap() + } label: { + Image(viewModel.flagName) + .resizable() + .frame(width: size, height: size*0.75) + } + .buttonStyle(.card) + .buttonBorderShape(.roundedRectangle(radius: 2)) + + } +} + diff --git a/PIA VPN-tvOS/Dashboard/UI/QuickConnectView.swift b/PIA VPN-tvOS/Dashboard/UI/QuickConnectView.swift new file mode 100644 index 00000000..c3ee3c9f --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/UI/QuickConnectView.swift @@ -0,0 +1,22 @@ + +import SwiftUI + +struct QuickConnectView: View { + @ObservedObject var viewModel: QuickConnectViewModel + + let rows = [ GridItem(.adaptive(minimum: 80)) ] + var body: some View { + ScrollView(.horizontal) { + LazyHGrid(rows: rows) { + ForEach(viewModel.servers, id: \.regionIdentifier) { item in + DashboardFactory.makeQuickConnectButton(for: item, delegate: viewModel) + } + } + } + + } +} + +#Preview { + QuickConnectView(viewModel: DashboardFactory.makeQuickConnectViewModel()) +} diff --git a/PIA VPN-tvOS/Dashboard/UI/SelectedServerView.swift b/PIA VPN-tvOS/Dashboard/UI/SelectedServerView.swift new file mode 100644 index 00000000..b3843f16 --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/UI/SelectedServerView.swift @@ -0,0 +1,38 @@ + +import SwiftUI + +struct SelectedServerView: View { + @Environment(\.colorScheme) var colorScheme + + @ObservedObject var viewModel: SelectedServerViewModel + + var body: some View { + + HStack(alignment: .top) { + VStack(alignment: .leading) { + Text(viewModel.selectedSeverSectionTitle) + .font(.callout) + Text(viewModel.serverName) + .font(.caption) + } + + Spacer() + + HStack(alignment: .center) { + if colorScheme == .light { + Image.map + } else { + Image.map + .blendMode(.hardLight) + } + + Image(systemName: "chevron.forward") + .foregroundStyle(Color.gray) + .frame(width: 50) + + } + + } + } +} + diff --git a/PIA VPN-tvOS/Dashboard/UseCases/SelectedServerUseCase.swift b/PIA VPN-tvOS/Dashboard/UseCases/SelectedServerUseCase.swift new file mode 100644 index 00000000..341a9bc4 --- /dev/null +++ b/PIA VPN-tvOS/Dashboard/UseCases/SelectedServerUseCase.swift @@ -0,0 +1,67 @@ + +import Foundation +import PIALibrary + +protocol SelectedServerUseCaseType { + func getSelectedServer() -> ServerType + func getHistoricalServers() -> [ServerType] +} + +class SelectedServerUseCase: SelectedServerUseCaseType { + + let serverProvider: ServerProviderType + + init(serverProvider: ServerProviderType) { + self.serverProvider = serverProvider + } + + func getSelectedServer() -> ServerType { + // TODO: get real selected server + return automaticServer() + } + + func getHistoricalServers() -> [ServerType] { + // TODO: Remove this `guard` statement when we get + // the real historical servers + guard !serverProvider.historicalServers.isEmpty else { + return Self.generateDemoServers() + } + return serverProvider.historicalServers + } + + private func automaticServer() -> ServerType { + Server( + serial: "", + name: L10n.Localizable.Global.automatic, + country: "universal", + hostname: "auto.bogus.domain", + pingAddress: nil, + regionIdentifier: "auto" + ) + } +} + +// TODO: Remove this extension when we have implemented +// getting the real historical servers (for QuickConnect) +extension SelectedServerUseCase { + private static func generateDemoServers() -> [ServerType] { + var servers: [ServerType] = [] + func createDemoServer(name: String, country: String, regionIdentifier: String) -> ServerType { + Server(serial: "", name: name, country: country, hostname: "auto.bogus.domain", pingAddress: nil, regionIdentifier: regionIdentifier) + } + + servers.append(createDemoServer(name: "Spain", country: "ES", regionIdentifier: "Spain")) + servers.append(createDemoServer(name: "France", country: "FR", regionIdentifier: "France")) + servers.append(createDemoServer(name: "Germany", country: "DE", regionIdentifier: "Germany")) + servers.append(createDemoServer(name: "Netherlands", country: "NL", regionIdentifier: "Netherlands")) + servers.append(createDemoServer(name: "Australia", country: "AU", regionIdentifier: "Australia")) + servers.append(createDemoServer(name: "Portugal", country: "PT", regionIdentifier: "Portugal")) + servers.append(createDemoServer(name: "Ireland", country: "IR", regionIdentifier: "Ireland")) + servers.append(createDemoServer(name: "Italy", country: "IT", regionIdentifier: "Italy")) + servers.append(createDemoServer(name: "Canada", country: "CA", regionIdentifier: "Canada")) + + + return servers + + } +} diff --git a/PIA VPN-tvOS/Dashboard/UseCases/VpnConnectionUseCase.swift b/PIA VPN-tvOS/Dashboard/UseCases/VpnConnectionUseCase.swift index 4e46f490..07d75a12 100644 --- a/PIA VPN-tvOS/Dashboard/UseCases/VpnConnectionUseCase.swift +++ b/PIA VPN-tvOS/Dashboard/UseCases/VpnConnectionUseCase.swift @@ -2,19 +2,32 @@ import Foundation protocol VpnConnectionUseCaseType { - func connect() - func disconnect() + func connect() + func connect(to server: ServerType) + func disconnect() } class VpnConnectionUseCase: VpnConnectionUseCaseType { - - func connect() { - // TODO: Implement - } - - func disconnect() { - // TODO: Implement - } - - + + let serverProvider: ServerProviderType + + init(serverProvider: ServerProviderType) { + self.serverProvider = serverProvider + } + + func connect() { + // TODO: Implement + } + + func disconnect() { + // TODO: Implement + } + + func connect(to server: ServerType) { + // TODO: Implement me + print("VpnConnectionUseCase: connect to: \(server.name)") + } + + + } diff --git a/PIA VPN-tvOS/Shared/UI/PIAImages+SwiftUI.swift b/PIA VPN-tvOS/Shared/UI/PIAImages+SwiftUI.swift new file mode 100644 index 00000000..d7b09a6f --- /dev/null +++ b/PIA VPN-tvOS/Shared/UI/PIAImages+SwiftUI.swift @@ -0,0 +1,7 @@ + +import Foundation +import SwiftUI + +extension Image { + static let map = Image("Dark-Map") +} diff --git a/PIA VPN-tvOS/Shared/Utils/PIALibrary+Protocols.swift b/PIA VPN-tvOS/Shared/Utils/PIALibrary+Protocols.swift index eb018ca1..87c39e4d 100644 --- a/PIA VPN-tvOS/Shared/Utils/PIALibrary+Protocols.swift +++ b/PIA VPN-tvOS/Shared/Utils/PIALibrary+Protocols.swift @@ -9,3 +9,24 @@ protocol AccountProviderType { } extension DefaultAccountProvider: AccountProviderType { } + +protocol ServerType { + var name: String { get } + var identifier: String { get } + var regionIdentifier: String { get } + var country: String { get } + var geo: Bool { get } +} + +extension Server: ServerType {} + +protocol ServerProviderType { + var historicalServers: [Server] { get } + var targetServer: Server { get } + var currentServers: [Server] { get } + + // Add methods from ServerProvider to this protocol as needed +} + +extension DefaultServerProvider: ServerProviderType { +} diff --git a/PIA VPN-tvOSTests/Dashboard/Mocks/NotificationCenterMock.swift b/PIA VPN-tvOSTests/Common/Mocks/NotificationCenterMock.swift similarity index 100% rename from PIA VPN-tvOSTests/Dashboard/Mocks/NotificationCenterMock.swift rename to PIA VPN-tvOSTests/Common/Mocks/NotificationCenterMock.swift diff --git a/PIA VPN-tvOSTests/Common/Mocks/SelectedServerUseCaseMock.swift b/PIA VPN-tvOSTests/Common/Mocks/SelectedServerUseCaseMock.swift new file mode 100644 index 00000000..9576255e --- /dev/null +++ b/PIA VPN-tvOSTests/Common/Mocks/SelectedServerUseCaseMock.swift @@ -0,0 +1,28 @@ + +import Foundation +@testable import PIA_VPN_tvOS + +class SelectedServerUseCaseMock: SelectedServerUseCaseType { + var getSelectedServerCalled = false + var getSelectedServerAttempt = 0 + var getSelectedServerResult: ServerType = ServerMock() + + func getSelectedServer() -> ServerType { + getSelectedServerCalled = true + getSelectedServerAttempt += 1 + return getSelectedServerResult + } + + var getHistoricalServersCalled = false + var getHistoricalServersttempt = 0 + var getHistoricalServersResult: [ServerType] = [] + + func getHistoricalServers() -> [ServerType] { + getHistoricalServersCalled = true + getHistoricalServersttempt += 1 + return getHistoricalServersResult + } + + + +} diff --git a/PIA VPN-tvOSTests/Common/Mocks/ServerMock.swift b/PIA VPN-tvOSTests/Common/Mocks/ServerMock.swift new file mode 100644 index 00000000..a70257ce --- /dev/null +++ b/PIA VPN-tvOSTests/Common/Mocks/ServerMock.swift @@ -0,0 +1,29 @@ + +import Foundation +@testable import PIA_VPN_tvOS + +class ServerMock: ServerType { + var name: String + + var identifier: String + + var regionIdentifier: String + + var country: String + + var geo: Bool + + init(name: String, identifier: String, regionIdentifier: String, country: String, geo: Bool) { + self.name = name + self.identifier = identifier + self.regionIdentifier = regionIdentifier + self.country = country + self.geo = geo + } + + convenience init() { + self.init(name: "mock-server-name", identifier: "mock-server-id", regionIdentifier: "mock-server-region-id", country: "mock-country", geo: false) + } + + +} diff --git a/PIA VPN-tvOSTests/Dashboard/Mocks/VpnConnectionUseCaseMock.swift b/PIA VPN-tvOSTests/Common/Mocks/VpnConnectionUseCaseMock.swift similarity index 66% rename from PIA VPN-tvOSTests/Dashboard/Mocks/VpnConnectionUseCaseMock.swift rename to PIA VPN-tvOSTests/Common/Mocks/VpnConnectionUseCaseMock.swift index f6aaff84..c36b2811 100644 --- a/PIA VPN-tvOSTests/Dashboard/Mocks/VpnConnectionUseCaseMock.swift +++ b/PIA VPN-tvOSTests/Common/Mocks/VpnConnectionUseCaseMock.swift @@ -11,6 +11,16 @@ import Foundation class VpnConnectionUseCaseMock: VpnConnectionUseCaseType { + var connectToServerCalled: Bool = false + var connectCalledToServerAttempt: Int = 0 + var connectToServerCalledWithArgument: ServerType? + + func connect(to server: ServerType) { + connectToServerCalled = true + connectCalledToServerAttempt += 1 + connectToServerCalledWithArgument = server + } + var connectCalled: Bool = false var connectCalledAttempt: Int = 0 diff --git a/PIA VPN-tvOSTests/Dashboard/Mocks/QuickConnectButtonViewModelDelegateMock.swift b/PIA VPN-tvOSTests/Dashboard/Mocks/QuickConnectButtonViewModelDelegateMock.swift new file mode 100644 index 00000000..08ce55c9 --- /dev/null +++ b/PIA VPN-tvOSTests/Dashboard/Mocks/QuickConnectButtonViewModelDelegateMock.swift @@ -0,0 +1,19 @@ + +import Foundation +@testable import PIA_VPN_tvOS + +class QuickConnectButtonViewModelDelegateMock: QuickConnectButtonViewModelDelegate { + + var quickConnectButtonViewModelDelegateDidSelectServerCalled = false + var quickConnectButtonViewModelDelegateDidSelectServerAttempt = 0 + var quickConnectButtonViewModelDelegateDidSelectServerCalledWithServer: ServerType? + + func quickConnectButtonViewModel(didSelect server: ServerType) { + quickConnectButtonViewModelDelegateDidSelectServerCalled = true + quickConnectButtonViewModelDelegateDidSelectServerAttempt += 1 + quickConnectButtonViewModelDelegateDidSelectServerCalledWithServer = server + + } + + +} diff --git a/PIA VPN-tvOSTests/Dashboard/QuickConnectButtonViewModelTests.swift b/PIA VPN-tvOSTests/Dashboard/QuickConnectButtonViewModelTests.swift new file mode 100644 index 00000000..e369fd5b --- /dev/null +++ b/PIA VPN-tvOSTests/Dashboard/QuickConnectButtonViewModelTests.swift @@ -0,0 +1,60 @@ + + +import XCTest +@testable import PIA_VPN_tvOS + +final class QuickConnectButtonViewModelTests: XCTestCase { + + class Fixture { + var serverMock = ServerMock() + var spyDelegate = QuickConnectButtonViewModelDelegateMock() + } + + var fixture: Fixture! + var sut: QuickConnectButtonViewModel! + + override func setUp() { + fixture = Fixture() + + } + + override func tearDown() { + fixture = nil + sut = nil + } + + + private func initializeSut() { + sut = QuickConnectButtonViewModel(server: fixture.serverMock, delegate: fixture.spyDelegate) + } + + func test_displayedFlag_whenButtonCreated() { + // GIVEN that the server country is 'ES' + fixture.serverMock.country = "ES" + + // WHEN the Quick Connect button is created + initializeSut() + + // THEN the flag displayed is 'flag-es' + XCTAssertEqual(sut.flagName, "flag-es") + + } + + func test_quickConnectButtonAction() { + // GIVEN that the server is "Canada-Toronto" + fixture.serverMock.country = "CA" + fixture.serverMock.name = "Canada-Toronto" + + initializeSut() + + // WHEN tapping the Quick Connect Button + sut.connectButtonDidTap() + + // THEN the delegate is called ONE time with the "Canada-Toronto" server + XCTAssertTrue(fixture.spyDelegate.quickConnectButtonViewModelDelegateDidSelectServerCalled) + XCTAssertEqual(fixture.spyDelegate.quickConnectButtonViewModelDelegateDidSelectServerAttempt, 1) + XCTAssertEqual(fixture.spyDelegate.quickConnectButtonViewModelDelegateDidSelectServerCalledWithServer?.name, "Canada-Toronto") + + } + +} diff --git a/PIA VPN-tvOSTests/Dashboard/QuickConnectViewModelTests.swift b/PIA VPN-tvOSTests/Dashboard/QuickConnectViewModelTests.swift new file mode 100644 index 00000000..b6ae228a --- /dev/null +++ b/PIA VPN-tvOSTests/Dashboard/QuickConnectViewModelTests.swift @@ -0,0 +1,55 @@ + +import XCTest +@testable import PIA_VPN_tvOS + +final class QuickConnectViewModelTests: XCTestCase { + class Fixture { + let connectUseCaseMock = VpnConnectionUseCaseMock() + let selectedServerUseCaseMock = SelectedServerUseCaseMock() + let serverMock = ServerMock() + } + + var fixture: Fixture! + var sut: QuickConnectViewModel! + + override func setUp() { + fixture = Fixture() + } + + override func tearDown() { + fixture = nil + } + + private func initilizeSut() { + sut = QuickConnectViewModel(connectUseCase: fixture.connectUseCaseMock, selectedServerUseCase: fixture.selectedServerUseCaseMock) + } + + func test_quickConnectServers_on_launch() { + // GIVEN that there are 2 historical servers + fixture.selectedServerUseCaseMock.getHistoricalServersResult = [ServerMock(), ServerMock()] + + // WHEN showing the Quick Connect section + initilizeSut() + + // THEN there are 2 Quick Connect buttons displayed + XCTAssertEqual(sut.servers.count, 2) + } + + + func test_quickConnectButtonViewModelDelegate() { + // GIVEN that the selected server is 'Italy-Milano' + fixture.serverMock.country = "IT" + fixture.serverMock.name = "Italy-Milano" + + initilizeSut() + + // WHEN the sut is informed via `QuickConnectButtonViewModelDelegate` to connect + sut.quickConnectButtonViewModel(didSelect: fixture.serverMock) + + // THEN the vpn connect use case is called to connect to "Italy-Milano" + XCTAssertTrue(fixture.connectUseCaseMock.connectToServerCalled) + XCTAssertEqual(fixture.connectUseCaseMock.connectCalledToServerAttempt, 1) + XCTAssertEqual(fixture.connectUseCaseMock.connectToServerCalledWithArgument?.name, "Italy-Milano") + } + +} diff --git a/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITests.swift b/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITests.swift index 2c1f73fc..e55ad4b4 100644 --- a/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITests.swift +++ b/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITests.swift @@ -31,12 +31,4 @@ final class PIA_VPN_tvOSUITests: XCTestCase { // Use XCTAssert and related functions to verify your tests produce the correct results. } - func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTApplicationLaunchMetric()]) { - XCUIApplication().launch() - } - } - } } diff --git a/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITestsLaunchTests.swift b/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITestsLaunchTests.swift deleted file mode 100644 index 489a0129..00000000 --- a/PIA VPN-tvOSUITests/PIA_VPN_tvOSUITestsLaunchTests.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// PIA_VPN_tvOSUITestsLaunchTests.swift -// PIA VPN-tvOSUITests -// -// Created by Said Rehouni on 22/11/23. -// Copyright © 2023 Private Internet Access Inc. All rights reserved. -// - -import XCTest - -final class PIA_VPN_tvOSUITestsLaunchTests: XCTestCase { - - override class var runsForEachTargetApplicationUIConfiguration: Bool { - true - } - - override func setUpWithError() throws { - continueAfterFailure = false - } - - func testLaunch() throws { - let app = XCUIApplication() - app.launch() - - // Insert steps here to perform after app launch but before taking a screenshot, - // such as logging into a test account or navigating somewhere in the app - - let attachment = XCTAttachment(screenshot: app.screenshot()) - attachment.name = "Launch Screen" - attachment.lifetime = .keepAlways - add(attachment) - } -} diff --git a/PIA VPN.xcodeproj/project.pbxproj b/PIA VPN.xcodeproj/project.pbxproj index 2fe3ea70..ed8e83ff 100644 --- a/PIA VPN.xcodeproj/project.pbxproj +++ b/PIA VPN.xcodeproj/project.pbxproj @@ -162,6 +162,11 @@ 35EDD65A2B035B51007B9ACB /* SideMenuScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6592B035B51007B9ACB /* SideMenuScreen.swift */; }; 35EDD65C2B047839007B9ACB /* QuickSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD65B2B047839007B9ACB /* QuickSettingsTests.swift */; }; 35EDD65E2B048C68007B9ACB /* QuickSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD65D2B048C68007B9ACB /* QuickSettingsScreen.swift */; }; + 690FC4802B3C59AF00F6DCC8 /* QuickConnectButtonViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690FC47F2B3C59AF00F6DCC8 /* QuickConnectButtonViewModelTests.swift */; }; + 690FC4822B3C5A4300F6DCC8 /* ServerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690FC4812B3C5A4300F6DCC8 /* ServerMock.swift */; }; + 690FC4842B3C5B0500F6DCC8 /* QuickConnectButtonViewModelDelegateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690FC4832B3C5B0500F6DCC8 /* QuickConnectButtonViewModelDelegateMock.swift */; }; + 690FC4862B3C5F7300F6DCC8 /* SelectedServerUseCaseMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690FC4852B3C5F7300F6DCC8 /* SelectedServerUseCaseMock.swift */; }; + 690FC4882B3C60F500F6DCC8 /* QuickConnectViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 690FC4872B3C60F500F6DCC8 /* QuickConnectViewModelTests.swift */; }; 6913179F2B32E4D4009B4E85 /* PIALibrary+Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6913179E2B32E4D4009B4E85 /* PIALibrary+Protocols.swift */; }; 691317A12B32ED76009B4E85 /* AccountProviderTypeMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691317A02B32ED76009B4E85 /* AccountProviderTypeMock.swift */; }; 6924831A2AB045A5002A0407 /* PIAWidgetAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */; }; @@ -213,6 +218,15 @@ 69F1C2972B2B239000E924AE /* PIAConnectionButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F1C2962B2B239000E924AE /* PIAConnectionButtonViewModel.swift */; }; 69F1C2992B2B28DA00E924AE /* PIAConnectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F1C2982B2B28DA00E924AE /* PIAConnectionButton.swift */; }; 69F1C29C2B2B299300E924AE /* VpnConnectionUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69F1C29B2B2B299300E924AE /* VpnConnectionUseCase.swift */; }; + 69FF0B042B3AD1D40074AA04 /* SelectedServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B032B3AD1D40074AA04 /* SelectedServerView.swift */; }; + 69FF0B062B3AD2860074AA04 /* QuickConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B052B3AD2860074AA04 /* QuickConnectView.swift */; }; + 69FF0B082B3AD3E60074AA04 /* SelectedServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B072B3AD3E60074AA04 /* SelectedServerViewModel.swift */; }; + 69FF0B0A2B3AD3F60074AA04 /* QuickConnectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B092B3AD3F60074AA04 /* QuickConnectViewModel.swift */; }; + 69FF0B0B2B3AD4C70074AA04 /* SwiftGen+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51693D02AFADCC20089FB8F /* SwiftGen+Strings.swift */; }; + 69FF0B0D2B3AD57C0074AA04 /* SelectedServerUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B0C2B3AD57C0074AA04 /* SelectedServerUseCase.swift */; }; + 69FF0B0F2B3AE8F60074AA04 /* PIAImages+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B0E2B3AE8F60074AA04 /* PIAImages+SwiftUI.swift */; }; + 69FF0B112B3AF1F00074AA04 /* QuickConnectButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B102B3AF1F00074AA04 /* QuickConnectButton.swift */; }; + 69FF0B132B3AF2050074AA04 /* QuickConnectButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FF0B122B3AF2050074AA04 /* QuickConnectButtonViewModel.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 */; }; @@ -577,7 +591,6 @@ E5C507812B0E145000200A6A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E5C507802B0E145000200A6A /* Preview Assets.xcassets */; }; E5C5078B2B0E145100200A6A /* PIA_VPN_tvOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C5078A2B0E145100200A6A /* PIA_VPN_tvOSTests.swift */; }; E5C507952B0E145100200A6A /* PIA_VPN_tvOSUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C507942B0E145100200A6A /* PIA_VPN_tvOSUITests.swift */; }; - E5C507972B0E145100200A6A /* PIA_VPN_tvOSUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C507962B0E145100200A6A /* PIA_VPN_tvOSUITestsLaunchTests.swift */; }; E5C507A22B0FE40000200A6A /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C507A12B0FE40000200A6A /* LoginView.swift */; }; E5C507A52B153A2F00200A6A /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C507A42B153A2F00200A6A /* LoginViewModel.swift */; }; E5C507A82B153E6B00200A6A /* LoginViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C507A72B153E6B00200A6A /* LoginViewModelTests.swift */; }; @@ -874,6 +887,11 @@ 35EDD6592B035B51007B9ACB /* SideMenuScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuScreen.swift; sourceTree = ""; }; 35EDD65B2B047839007B9ACB /* QuickSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSettingsTests.swift; sourceTree = ""; }; 35EDD65D2B048C68007B9ACB /* QuickSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSettingsScreen.swift; sourceTree = ""; }; + 690FC47F2B3C59AF00F6DCC8 /* QuickConnectButtonViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectButtonViewModelTests.swift; sourceTree = ""; }; + 690FC4812B3C5A4300F6DCC8 /* ServerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerMock.swift; sourceTree = ""; }; + 690FC4832B3C5B0500F6DCC8 /* QuickConnectButtonViewModelDelegateMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectButtonViewModelDelegateMock.swift; sourceTree = ""; }; + 690FC4852B3C5F7300F6DCC8 /* SelectedServerUseCaseMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedServerUseCaseMock.swift; sourceTree = ""; }; + 690FC4872B3C60F500F6DCC8 /* QuickConnectViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectViewModelTests.swift; sourceTree = ""; }; 6913179E2B32E4D4009B4E85 /* PIALibrary+Protocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PIALibrary+Protocols.swift"; sourceTree = ""; }; 691317A02B32ED76009B4E85 /* AccountProviderTypeMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountProviderTypeMock.swift; sourceTree = ""; }; 692483192AB045A5002A0407 /* PIAWidgetAttributes.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAWidgetAttributes.swift; sourceTree = ""; tabWidth = 4; }; @@ -914,6 +932,14 @@ 69F1C2962B2B239000E924AE /* PIAConnectionButtonViewModel.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAConnectionButtonViewModel.swift; sourceTree = ""; tabWidth = 4; }; 69F1C2982B2B28DA00E924AE /* PIAConnectionButton.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PIAConnectionButton.swift; sourceTree = ""; tabWidth = 4; }; 69F1C29B2B2B299300E924AE /* VpnConnectionUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VpnConnectionUseCase.swift; sourceTree = ""; }; + 69FF0B032B3AD1D40074AA04 /* SelectedServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedServerView.swift; sourceTree = ""; }; + 69FF0B052B3AD2860074AA04 /* QuickConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectView.swift; sourceTree = ""; }; + 69FF0B072B3AD3E60074AA04 /* SelectedServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedServerViewModel.swift; sourceTree = ""; }; + 69FF0B092B3AD3F60074AA04 /* QuickConnectViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectViewModel.swift; sourceTree = ""; }; + 69FF0B0C2B3AD57C0074AA04 /* SelectedServerUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedServerUseCase.swift; sourceTree = ""; }; + 69FF0B0E2B3AE8F60074AA04 /* PIAImages+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PIAImages+SwiftUI.swift"; sourceTree = ""; }; + 69FF0B102B3AF1F00074AA04 /* QuickConnectButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectButton.swift; sourceTree = ""; }; + 69FF0B122B3AF2050074AA04 /* QuickConnectButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickConnectButtonViewModel.swift; sourceTree = ""; }; 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 = ""; }; @@ -1170,7 +1196,6 @@ E5C5078A2B0E145100200A6A /* PIA_VPN_tvOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA_VPN_tvOSTests.swift; sourceTree = ""; }; E5C507902B0E145100200A6A /* PIA VPN-tvOSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "PIA VPN-tvOSUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; E5C507942B0E145100200A6A /* PIA_VPN_tvOSUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA_VPN_tvOSUITests.swift; sourceTree = ""; }; - E5C507962B0E145100200A6A /* PIA_VPN_tvOSUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIA_VPN_tvOSUITestsLaunchTests.swift; sourceTree = ""; }; E5C507A12B0FE40000200A6A /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; E5C507A42B153A2F00200A6A /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = ""; }; E5C507A72B153E6B00200A6A /* LoginViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModelTests.swift; sourceTree = ""; }; @@ -1740,6 +1765,9 @@ children = ( 694AC74D2B17AB9C007E7B56 /* DashboardView.swift */, 69F1C2982B2B28DA00E924AE /* PIAConnectionButton.swift */, + 69FF0B032B3AD1D40074AA04 /* SelectedServerView.swift */, + 69FF0B052B3AD2860074AA04 /* QuickConnectView.swift */, + 69FF0B102B3AF1F00074AA04 /* QuickConnectButton.swift */, ); path = UI; sourceTree = ""; @@ -1763,7 +1791,11 @@ 696E8F142B31AF200080BB31 /* Mocks */ = { isa = PBXGroup; children = ( + 698C3B482B2B33650012D527 /* VpnConnectionUseCaseMock.swift */, + 696E8F0C2B31A8760080BB31 /* NotificationCenterMock.swift */, 691317A02B32ED76009B4E85 /* AccountProviderTypeMock.swift */, + 690FC4812B3C5A4300F6DCC8 /* ServerMock.swift */, + 690FC4852B3C5F7300F6DCC8 /* SelectedServerUseCaseMock.swift */, ); path = Mocks; sourceTree = ""; @@ -1773,6 +1805,8 @@ children = ( 698C3B472B2B33440012D527 /* Mocks */, 698C3B4A2B2B34760012D527 /* PIAConnectionButtonViewModelTests.swift */, + 690FC47F2B3C59AF00F6DCC8 /* QuickConnectButtonViewModelTests.swift */, + 690FC4872B3C60F500F6DCC8 /* QuickConnectViewModelTests.swift */, ); path = Dashboard; sourceTree = ""; @@ -1780,8 +1814,7 @@ 698C3B472B2B33440012D527 /* Mocks */ = { isa = PBXGroup; children = ( - 698C3B482B2B33650012D527 /* VpnConnectionUseCaseMock.swift */, - 696E8F0C2B31A8760080BB31 /* NotificationCenterMock.swift */, + 690FC4832B3C5B0500F6DCC8 /* QuickConnectButtonViewModelDelegateMock.swift */, ); path = Mocks; sourceTree = ""; @@ -1888,6 +1921,7 @@ 69F053462B1E056400AE0665 /* PIAColors+SwitUI.swift */, 69F053492B1F1D2800AE0665 /* Colors.xcassets */, 69F1C2942B2B216100E924AE /* PIA+Animation.swift */, + 69FF0B0E2B3AE8F60074AA04 /* PIAImages+SwiftUI.swift */, ); path = UI; sourceTree = ""; @@ -1905,6 +1939,9 @@ children = ( 69F1C2962B2B239000E924AE /* PIAConnectionButtonViewModel.swift */, 699311A12B318F6B00D316C8 /* DashboardViewModel.swift */, + 69FF0B072B3AD3E60074AA04 /* SelectedServerViewModel.swift */, + 69FF0B092B3AD3F60074AA04 /* QuickConnectViewModel.swift */, + 69FF0B122B3AF2050074AA04 /* QuickConnectButtonViewModel.swift */, ); path = Presentation; sourceTree = ""; @@ -1913,6 +1950,7 @@ isa = PBXGroup; children = ( 69F1C29B2B2B299300E924AE /* VpnConnectionUseCase.swift */, + 69FF0B0C2B3AD57C0074AA04 /* SelectedServerUseCase.swift */, ); path = UseCases; sourceTree = ""; @@ -2283,7 +2321,6 @@ isa = PBXGroup; children = ( E5C507942B0E145100200A6A /* PIA_VPN_tvOSUITests.swift */, - E5C507962B0E145100200A6A /* PIA_VPN_tvOSUITestsLaunchTests.swift */, ); path = "PIA VPN-tvOSUITests"; sourceTree = ""; @@ -3488,25 +3525,33 @@ buildActionMask = 2147483647; files = ( 6913179F2B32E4D4009B4E85 /* PIALibrary+Protocols.swift in Sources */, + 69FF0B082B3AD3E60074AA04 /* SelectedServerViewModel.swift in Sources */, + 69FF0B0B2B3AD4C70074AA04 /* SwiftGen+Strings.swift in Sources */, + 69FF0B062B3AD2860074AA04 /* QuickConnectView.swift in Sources */, E5AB288C2B2A487A00744E5F /* LoginViewModelErrorHandler.swift in Sources */, E5AB28732B279B7000744E5F /* LoginProvider.swift in Sources */, E5C507A52B153A2F00200A6A /* LoginViewModel.swift in Sources */, E5C507B72B17E75B00200A6A /* CheckLoginAvailability.swift in Sources */, E5AB288E2B2A489500744E5F /* LoginStatus.swift in Sources */, + 69FF0B132B3AF2050074AA04 /* QuickConnectButtonViewModel.swift in Sources */, E5AB286F2B27977000744E5F /* LoginFactory.swift in Sources */, 699311A22B318F6B00D316C8 /* DashboardViewModel.swift in Sources */, + 69FF0B042B3AD1D40074AA04 /* SelectedServerView.swift in Sources */, 69A226B82B3079EA0065EDDB /* PIA+String.swift in Sources */, 69F1C29C2B2B299300E924AE /* VpnConnectionUseCase.swift in Sources */, 69A226B32B3074D30065EDDB /* AppRouter.swift in Sources */, E5AB288A2B29BDED00744E5F /* Foundation+PIA.swift in Sources */, E5C507A22B0FE40000200A6A /* LoginView.swift in Sources */, E5AB287D2B28E4E700744E5F /* UserAccountMapper.swift in Sources */, + 69FF0B0A2B3AD3F60074AA04 /* QuickConnectViewModel.swift in Sources */, 699311A02B31894D00D316C8 /* Foundation+Protocols.swift in Sources */, E5AB28792B28B4B300744E5F /* AccountInfo.swift in Sources */, E5C507B12B17E48900200A6A /* LoginWithCredentialsUseCase.swift in Sources */, E5C507B92B17E7A400200A6A /* ValidateCredentialsFormat.swift in Sources */, 69F1C2992B2B28DA00E924AE /* PIAConnectionButton.swift in Sources */, E5C507AE2B17E45800200A6A /* LoginPresentableErrorMapper.swift in Sources */, + 69FF0B0D2B3AD57C0074AA04 /* SelectedServerUseCase.swift in Sources */, + 69FF0B112B3AF1F00074AA04 /* QuickConnectButton.swift in Sources */, E5AB28712B279B4000744E5F /* LoginProviderType.swift in Sources */, E5AB287B2B28B4C400744E5F /* Credentials.swift in Sources */, E5C5077C2B0E144E00200A6A /* ContentView.swift in Sources */, @@ -3520,6 +3565,7 @@ 69F1C2972B2B239000E924AE /* PIAConnectionButtonViewModel.swift in Sources */, E5C507B32B17E5AD00200A6A /* LoginError.swift in Sources */, E5C507CA2B1FAC3600200A6A /* LoginDomainErrorMapper.swift in Sources */, + 69FF0B0F2B3AE8F60074AA04 /* PIAImages+SwiftUI.swift in Sources */, E5AB28772B28B49A00744E5F /* UserAccount.swift in Sources */, 69A226C02B307DBF0065EDDB /* RootContainerFactory.swift in Sources */, 69F053472B1E056400AE0665 /* PIAColors+SwitUI.swift in Sources */, @@ -3539,9 +3585,14 @@ 696E8F102B31AC690080BB31 /* RootContainerViewModelTests.swift in Sources */, 698C3B4E2B2B3CBE0012D527 /* LoginIntegrationTests.swift in Sources */, E5C5078B2B0E145100200A6A /* PIA_VPN_tvOSTests.swift in Sources */, + 690FC4802B3C59AF00F6DCC8 /* QuickConnectButtonViewModelTests.swift in Sources */, 698C3B4B2B2B34760012D527 /* PIAConnectionButtonViewModelTests.swift in Sources */, + 690FC4862B3C5F7300F6DCC8 /* SelectedServerUseCaseMock.swift in Sources */, + 690FC4822B3C5A4300F6DCC8 /* ServerMock.swift in Sources */, + 690FC4842B3C5B0500F6DCC8 /* QuickConnectButtonViewModelDelegateMock.swift in Sources */, E5AB287F2B28F6EF00744E5F /* Stubs.swift in Sources */, E5AB28972B2C782C00744E5F /* Stubs+PIALibrary.swift in Sources */, + 690FC4882B3C60F500F6DCC8 /* QuickConnectViewModelTests.swift in Sources */, E5AB28992B2C783600744E5F /* LoginProviderTests.swift in Sources */, E5C507C22B1F702700200A6A /* LoginWithCredentialsUseCaseMock.swift in Sources */, E5C507C42B1F72E700200A6A /* CheckLoginAvailabilityTests.swift in Sources */, @@ -3554,7 +3605,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E5C507972B0E145100200A6A /* PIA_VPN_tvOSUITestsLaunchTests.swift in Sources */, E5C507952B0E145100200A6A /* PIA_VPN_tvOSUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN-tvOS.xcscheme b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN-tvOS.xcscheme new file mode 100644 index 00000000..9f542bb1 --- /dev/null +++ b/PIA VPN.xcodeproj/xcshareddata/xcschemes/PIA VPN-tvOS.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +