LeadKitAdditions/LeadKitAdditions/Sources/Services/ValidationService/ValidationItem.swift

97 lines
2.3 KiB
Swift

import SwiftValidator
import RxSwift
import RxCocoa
enum ValidationItemState {
case initial
case correction(ValidationError)
case error(ValidationError)
case valid
}
extension ValidationItemState {
var isInitial: Bool {
switch self {
case .initial:
return true
default:
return false
}
}
var isValid: Bool {
switch self {
case .valid:
return true
default:
return false
}
}
}
class ValidationItem {
private let disposeBag = DisposeBag()
private let validationStateHolder = Variable<ValidationItemState>(.initial)
var validationState: ValidationItemState {
return validationStateHolder.value
}
var validationStateObservable: Observable<ValidationItemState> {
return validationStateHolder.asObservable()
}
let text = Variable<String?>(nil)
private(set) var rules: [Rule] = []
init(rules: [Rule]) {
self.rules = rules
bindText()
}
private func bindText() {
text.asObservable()
.filter { [weak self] _ in !(self?.validationState.isInitial ?? true)}
.subscribe(onNext: { [weak self] value in
self?.validate(text: value)
})
.addDisposableTo(disposeBag)
}
@discardableResult
func manualValidate() -> Bool {
return validate(text: text.value, isManual: true)
}
@discardableResult
private func validate(text: String?, isManual: Bool = false) -> Bool {
let error = rules.filter {
return !$0.validate(text ?? "")
}
.map { rule -> ValidationError in
return ValidationError(failedRule: rule, errorMessage: rule.errorMessage())
}
.first
if let validationError = error {
switch validationStateHolder.value {
case .error where !isManual,
.correction where !isManual,
.valid where !isManual:
validationStateHolder.value = .correction(validationError)
default:
validationStateHolder.value = .error(validationError)
}
} else {
validationStateHolder.value = .valid
}
return validationStateHolder.value.isValid
}
}