import AppCore import Shared import Combine import Defaults import XXClient import InputField import Foundation import CombineSchedulers import XXMessengerClient import ComposableArchitecture final class OnboardingCodeViewModel { struct ViewState: Equatable { var input: String = "" var status: InputField.ValidationStatus = .unknown(nil) var resendDebouncer: Int = 0 var didConfirm: Bool = false } var statePublisher: AnyPublisher<ViewState, Never> { stateSubject.eraseToAnyPublisher() } @Dependency(\.app.bgQueue) var bgQueue @Dependency(\.app.messenger) var messenger @Dependency(\.app.hudManager) var hudManager @KeyObject(.email, defaultValue: nil) var email: String? @KeyObject(.phone, defaultValue: nil) var phone: String? private var timer: Timer? private let isEmail: Bool private let content: String private let confirmationId: String private let stateSubject = CurrentValueSubject<ViewState, Never>(.init()) init( isEmail: Bool, content: String, confirmationId: String ) { self.isEmail = isEmail self.content = content self.confirmationId = confirmationId didTapResend() } func didInput(_ string: String) { stateSubject.value.input = string validate() } func didTapResend() { guard stateSubject.value.resendDebouncer == 0 else { return } stateSubject.value.resendDebouncer = 60 timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] in guard let self, self.stateSubject.value.resendDebouncer > 0 else { $0.invalidate() return } self.stateSubject.value.resendDebouncer -= 1 } } func didTapNext() { hudManager.show() bgQueue.schedule { [weak self] in guard let self else { return } do { try self.messenger.ud.get()!.confirmFact( confirmationId: self.confirmationId, code: self.stateSubject.value.input ) if self.isEmail { self.email = self.content } else { self.phone = self.content } self.timer?.invalidate() self.hudManager.hide() self.stateSubject.value.didConfirm = true } catch { self.hudManager.hide() let xxError = CreateUserFriendlyErrorMessage.live(error.localizedDescription) self.stateSubject.value.status = .invalid(xxError) } } } private func validate() { switch Validator.code.validate(stateSubject.value.input) { case .success: stateSubject.value.status = .valid(nil) case .failure(let error): stateSubject.value.status = .invalid(error) } } }