Skip to content

Instantly share code, notes, and snippets.

@xmhafiz
Created October 16, 2022 13:10
Show Gist options
  • Save xmhafiz/36abdf0643af98bf4026cf4e8cc1520b to your computer and use it in GitHub Desktop.
Save xmhafiz/36abdf0643af98bf4026cf4e8cc1520b to your computer and use it in GitHub Desktop.
//
// LoginViewModel.swift
//
import Combine
import Foundation
// 1
class LoginViewModel: ObservableObject {
// 2
enum ViewState {
case loading
case success
case failed
case none
}
// 3
@Published var email = ""
@Published var password = ""
@Published var state: ViewState = .none
// 4
var isValidUsernamePublisher: AnyPublisher<Bool, Never> {
$email
.map { $0.isValidEmail }
.eraseToAnyPublisher()
}
var isValidPasswordPublisher: AnyPublisher<Bool, Never> {
$password
.map { !$0.isEmpty }
.eraseToAnyPublisher()
}
// 5
var isSubmitEnabled: AnyPublisher<Bool, Never> {
Publishers.CombineLatest(isValidUsernamePublisher, isValidPasswordPublisher)
.map { $0 && $1 }
.eraseToAnyPublisher()
}
// 6
func submitLogin() {
state = .loading
// hardcoded 2 seconds delay, to simulate request
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in
guard let self = self else { return }
// 7
if self.isCorrectLogin() {
self.state = .success
} else {
self.state = .failed
}
}
}
func isCorrectLogin() -> Bool {
// hardcoded example
return email == "[email protected]" && password == "12345"
}
}
extension String {
// 8
var isValidEmail: Bool {
return NSPredicate(
format: "SELF MATCHES %@", "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
)
.evaluate(with: self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment