Skip to content

Commit

Permalink
PIA-1219: Separate Onboarding flow from UserAuthenticated flow
Browse files Browse the repository at this point in the history
  • Loading branch information
kp-said-rehouni committed Feb 1, 2024
1 parent 1a40f29 commit 41acb50
Show file tree
Hide file tree
Showing 19 changed files with 51 additions and 93 deletions.
4 changes: 1 addition & 3 deletions PIA VPN-tvOS/Login/CompositionRoot/LoginFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ class LoginFactory {
checkLoginAvailability: CheckLoginAvailability(),
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: makeLoginViewModelErrorHandler(),
appRouter: AppRouter.shared,
successDestination: OnboardingDestinations.installVPNProfile)

onSuccessAction: .navigate(router: AppRouter.shared, destination: OnboardingDestinations.installVPNProfile))
}

private static func makeLoginWithCredentialsUseCase() -> LoginWithCredentialsUseCaseType {
Expand Down
11 changes: 4 additions & 7 deletions PIA VPN-tvOS/Login/Presentation/LoginViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,18 @@ class LoginViewModel: ObservableObject {
private let checkLoginAvailability: CheckLoginAvailabilityType
private let validateLoginCredentials: ValidateCredentialsFormatType
private let errorHandler: LoginViewModelErrorHandlerType
private let appRouter: AppRouterType

private let successDestination: any Destinations
private let onSuccessAction: AppRouter.Actions

@Published var isAccountExpired = false
@Published var shouldShowErrorMessage = false
@Published var loginStatus: LoginStatus = .none

init(loginWithCredentialsUseCase: LoginWithCredentialsUseCaseType, checkLoginAvailability: CheckLoginAvailabilityType, validateLoginCredentials: ValidateCredentialsFormatType, errorHandler: LoginViewModelErrorHandlerType, appRouter: AppRouterType, successDestination: any Destinations) {
init(loginWithCredentialsUseCase: LoginWithCredentialsUseCaseType, checkLoginAvailability: CheckLoginAvailabilityType, validateLoginCredentials: ValidateCredentialsFormatType, errorHandler: LoginViewModelErrorHandlerType, onSuccessAction: AppRouter.Actions) {
self.loginWithCredentialsUseCase = loginWithCredentialsUseCase
self.checkLoginAvailability = checkLoginAvailability
self.validateLoginCredentials = validateLoginCredentials
self.errorHandler = errorHandler
self.appRouter = appRouter
self.successDestination = successDestination
self.onSuccessAction = onSuccessAction
}

func login(username: String, password: String) {
Expand All @@ -54,7 +51,7 @@ class LoginViewModel: ObservableObject {
case .success(let userAccount):
Task { @MainActor in
self.loginStatus = .succeeded(userAccount: userAccount)
self.appRouter.navigate(to: self.successDestination)
self.onSuccessAction()
}

case .failure(let error):
Expand Down
18 changes: 2 additions & 16 deletions PIA VPN-tvOS/Navigation/AppRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ protocol AppRouterType {
func navigate(to destination: any Destinations)
func pop()
func goBackToRoot()

func execute(action: AppRouter.Actions)
}


Expand Down Expand Up @@ -41,18 +39,6 @@ class AppRouter: ObservableObject, AppRouterType {
func goBackToRoot() {
path.removeLast(path.count)
}
/*
func execute(action: AppRouter.Actions) {
switch action {
case .pop:
pop()
case .goBackToRoot:
goBackToRoot()
case .navigate(let destination):
navigate(to: destination)
}
}
*/
}


Expand All @@ -63,7 +49,7 @@ extension AppRouter {
case goBackToRoot(router: AppRouterType)
case navigate(router: AppRouterType, destination: any Destinations)

func execute() {
func callAsFunction() {
switch self {
case .pop(let router):
router.pop()
Expand All @@ -73,7 +59,7 @@ extension AppRouter {
router.navigate(to: destination)
}
}

static func == (lhs: AppRouter.Actions, rhs: AppRouter.Actions) -> Bool {
switch (lhs, rhs) {
case (.pop, .pop):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class RegionsContainerViewModel: ObservableObject {

func navigate(to route: RegionSelectionSideMenuItems) {
if route == .search {
onSearchSelectedAction.execute()
onSearchSelectedAction()
} else {
selectedSideMenuItem = route
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ class RegionsListViewModel: ObservableObject {

func didSelectRegionServer(_ server: ServerType) {
useCase.select(server: server)
onServerSelectedRouterAction.execute()
onServerSelectedRouterAction()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,18 @@ class RootContainerViewModel: ObservableObject {
self.bootstrap = bootstrap
self.userAuthenticationStatusMonitor = userAuthenticationStatusMonitor
self.appRouter = appRouter
updateState()

subscribeToAccountUpdates()
setup()
}

func phaseDidBecomeActive() {
private func setup() {
bootstrap()
isBootstrapped = true
updateState()
}

private func updateState() {
@objc private func updateState() {
guard isBootstrapped else {
return
}
Expand All @@ -54,14 +55,17 @@ class RootContainerViewModel: ObservableObject {
state = .activated
// logged in, vpn profile not installed
case (true, false):
appRouter.navigate(to: OnboardingDestinations.installVPNProfile)
state = .activatedNotOnboarded
appRouter.navigate(to: OnboardingDestinations.installVPNProfile)
// not logged in, any
case (false, _):
state = .notActivated
}
}


deinit {
notificationCenter.removeObserver(self)
}
}

// Combine subscriptions
Expand All @@ -71,5 +75,10 @@ extension RootContainerViewModel {
userAuthenticationStatusMonitor.getStatus().sink { status in
self.updateState()
}.store(in: &cancellables)

notificationCenter.addObserver(self,
selector: #selector(updateState),
name: .DidInstallVPNProfile,
object: nil)
}
}
2 changes: 0 additions & 2 deletions PIA VPN-tvOS/RootContainer/UI/RootContainerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ struct RootContainerView: View {
.withOnboardingRoutes()
case .activatedNotOnboarded, .activated:
UserActivatedContainerFactory.makeUSerActivatedContainerView()
.withOnboardingRoutes()
}
}.onChange(of: scenePhase) { _, newPhase in
if newPhase == .active {
NSLog(">>> Active")
viewModel.phaseDidBecomeActive()
} else if newPhase == .inactive {
NSLog(">>> Inactive")
} else if newPhase == .background {
Expand Down
4 changes: 4 additions & 0 deletions PIA VPN-tvOS/Shared/Utils/Foundation+Protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ protocol NotificationCenterType {
}

extension NotificationCenter: NotificationCenterType {}

extension Notification.Name {
public static let DidInstallVPNProfile = Notification.Name("DidInstallVPNProfile")
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ class VPNConfigurationInstallingFactory {
private static func makeVPNConfigurationInstallingViewModel() -> VPNConfigurationInstallingViewModel {
VPNConfigurationInstallingViewModel(installVPNConfiguration:
makeInstallVPNConfigurationUseCase(),
errorMapper: VPNConfigurationInstallingErrorMapper(),
appRouter: AppRouter.shared, onSuccessAction: .goBackToRoot)
errorMapper: VPNConfigurationInstallingErrorMapper()) {
AppRouter.Actions.goBackToRoot(router: AppRouter.shared)()
NotificationCenter.default.post(name: .DidInstallVPNProfile, object: nil)
}
}

private static func makeInstallVPNConfigurationUseCase() -> InstallVPNConfigurationUseCaseType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ class InstallVpnConfigurationProvider: InstallVPNConfigurationUseCaseType {
return
}

continuation.resume()
vpnConfigurationAvailability.set(value: true)

continuation.resume()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ import Foundation
class VPNConfigurationInstallingViewModel: ObservableObject {
private let installVPNConfiguration: InstallVPNConfigurationUseCaseType
private let errorMapper: VPNConfigurationInstallingErrorMapper
private let appRouter: AppRouterType
private let onSuccessAction: AppRouter.Actions
private let onSuccessAction: () -> Void

@Published var shouldShowErrorMessage = false
@Published var installingStatus: VPNConfigurationInstallingStatus = .none
var errorMessage: String?

init(installVPNConfiguration: InstallVPNConfigurationUseCaseType, errorMapper: VPNConfigurationInstallingErrorMapper, appRouter: AppRouterType, onSuccessAction: AppRouter.Actions) {
init(installVPNConfiguration: InstallVPNConfigurationUseCaseType, errorMapper: VPNConfigurationInstallingErrorMapper, onSuccessAction: @escaping () -> Void) {
self.installVPNConfiguration = installVPNConfiguration
self.errorMapper = errorMapper
self.appRouter = appRouter
self.onSuccessAction = onSuccessAction
}

Expand All @@ -37,7 +35,7 @@ class VPNConfigurationInstallingViewModel: ObservableObject {
try await installVPNConfiguration()
Task { @MainActor in
installingStatus = .succeeded
appRouter.execute(action: onSuccessAction)
onSuccessAction()
}
} catch {
errorMessage = errorMapper.map(error: error)
Expand Down
9 changes: 0 additions & 9 deletions PIA VPN-tvOSTests/Common/Mocks/AppRouterSpy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,4 @@ class AppRouterSpy: AppRouterType {
requests.append(.goBackToRoot)
didGetARequest?()
}

func execute(action: AppRouter.Actions) {
switch action {
case .pop: pop()
case .goBackToRoot: goBackToRoot()
case .navigate(let destination): navigate(to: destination)
}
}

}
2 changes: 1 addition & 1 deletion PIA VPN-tvOSTests/Dashboard/DashboardViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import SwiftUI
class DashboardViewModelTests: XCTestCase {
class Fixture {
let accountProviderMock = AccountProviderTypeMock()
let appRouter = AppRouter.shared
let appRouter = AppRouter(with: NavigationPath())
}

var fixture: Fixture!
Expand Down
8 changes: 3 additions & 5 deletions PIA VPN-tvOSTests/Login/LoginIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ final class LoginIntegrationTests: XCTestCase {
checkLoginAvailability: CheckLoginAvailability(),
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouter,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouter, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for didLoginSuccessfully property to be updated")
Expand Down Expand Up @@ -104,9 +103,8 @@ final class LoginIntegrationTests: XCTestCase {
let sut = LoginViewModel(loginWithCredentialsUseCase: loginWithCredentialsUseCase,
checkLoginAvailability: CheckLoginAvailability(),
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouter,
successDestination: OnboardingDestinations.installVPNProfile)
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
onSuccessAction: .navigate(router: appRouter, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for isAccountExpired property to be updated")
Expand Down
18 changes: 6 additions & 12 deletions PIA VPN-tvOSTests/Login/LoginViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for shouldShowErrorMessage property to be updated")
Expand Down Expand Up @@ -72,8 +71,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for shouldShowErrorMessage property to be updated")
Expand Down Expand Up @@ -117,8 +115,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for shouldShowErrorMessage property to be updated")
Expand Down Expand Up @@ -163,8 +160,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for didLoginSuccessfully property to be updated")
Expand Down Expand Up @@ -205,8 +201,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for isAccountExpired property to be updated")
Expand Down Expand Up @@ -249,8 +244,7 @@ final class LoginViewModelTests: XCTestCase {
checkLoginAvailability: checkLoginAvailabilityMock,
validateLoginCredentials: ValidateCredentialsFormat(),
errorHandler: LoginViewModelErrorHandler(errorMapper: LoginPresentableErrorMapper()),
appRouter: appRouterSpy,
successDestination: OnboardingDestinations.installVPNProfile)
onSuccessAction: .navigate(router: appRouterSpy, destination: OnboardingDestinations.installVPNProfile))

var cancellables = Set<AnyCancellable>()
let expectation = expectation(description: "Waiting for shouldShowErrorMessage property to be updated")
Expand Down
Loading

0 comments on commit 41acb50

Please sign in to comment.