Last active
August 31, 2019 22:49
-
-
Save LukeSmith16/8453cd253234628a1084815c4c5a4ad2 to your computer and use it in GitHub Desktop.
LoginViewModel - An example of how a LoginViewModel might look like for a login module, including: validation, talking to a repository, coordinator and view (via delegation).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
protocol LoginViewModelInterface { | |
var viewDelegate: LoginViewModelDelegate? {get set} | |
func handleLogin(username: String, password: String) | |
} | |
/// You're coordinator implements this | |
protocol LoginViewModelCoordinatorDelegate: class { | |
func goToLoginSuccessful() | |
func goToSignup() | |
} | |
/// You're view module implements this | |
protocol LoginViewModelDelegate: class { | |
func showAlert(title: String?, message: String?) | |
} | |
enum LoginEntryValidation: Error { | |
case UsernameEmpty | |
case UsernameTooShort | |
case PasswordEmpty | |
case PasswordTooShort | |
var localizedDescription: String { | |
switch self { | |
case .UsernameEmpty: | |
return "Please enter a username" | |
case .UsernameTooShort: | |
return "Your username must be greater than 5 characters" | |
case .PasswordEmpty: | |
return "Please enter a password" | |
case .PasswordTooShort: | |
return "Your password must be greater than 5 characters" | |
} | |
} | |
} | |
class LoginViewModel: LoginViewModelInterface { | |
weak var coordinatorDelegate: LoginViewModelCoordinatorDelegate? | |
weak var viewDelegate: LoginViewModelDelegate? | |
private let repository: LoginRepositoryInterface! | |
init(repository: LoginRepositoryInterface = RemoteLoginRepository()) { | |
self.repository = repository | |
} | |
func handleLogin(username: String, password: String) { | |
guard isUserCredentialsValid(username: username, password: password) else { return } | |
repository.authenticate(username: username, password: password) { [weak self] (result) in | |
guard let `self` = self else { return } | |
switch result { | |
case .success(let authToken): | |
self.repository.saveAuthToken(authToken) | |
case .failure(let error): | |
self.viewDelegate?.showAlert(title: "Login Error", message: error.localizedDescription) | |
} | |
} | |
} | |
} | |
private extension LoginViewModel { | |
func isUserCredentialsValid(username: String, password: String) -> Bool { | |
do { | |
try validateUsername(username) | |
try validatePassword(password) | |
return true | |
} catch (let error as LoginEntryValidation) { | |
viewDelegate?.showAlert(title: "Login Error", message: error.localizedDescription) | |
} catch { | |
fatalError("Unknown error occurred") | |
} | |
return false | |
} | |
func validateUsername(_ username: String) throws { | |
guard username != "" else { | |
throw LoginEntryValidation.UsernameEmpty | |
} | |
guard username.count >= 5 else { | |
throw LoginEntryValidation.UsernameTooShort | |
} | |
} | |
func validatePassword(_ password: String) throws { | |
guard password != "" else { | |
throw LoginEntryValidation.PasswordEmpty | |
} | |
guard password.count >= 5 else { | |
throw LoginEntryValidation.PasswordTooShort | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment