import HUD import Shared import Models import Combine import Defaults import XXClient import Foundation import InputField import BackupFeature import CombineSchedulers import XXMessengerClient import DependencyInjection struct ProfileCodeViewState: Equatable { var input: String = "" var status: InputField.ValidationStatus = .unknown(nil) var resendDebouncer: Int = 0 } final class ProfileCodeViewModel { @Dependency var messenger: Messenger @Dependency var backupService: BackupService @KeyObject(.email, defaultValue: nil) var email: String? @KeyObject(.phone, defaultValue: nil) var phone: String? let confirmation: AttributeConfirmation var timer: Timer? var completionPublisher: AnyPublisher<AttributeConfirmation, Never> { completionRelay.eraseToAnyPublisher() } private let completionRelay = PassthroughSubject<AttributeConfirmation, Never>() var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() } private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none) var state: AnyPublisher<ProfileCodeViewState, Never> { stateRelay.eraseToAnyPublisher() } private let stateRelay = CurrentValueSubject<ProfileCodeViewState, Never>(.init()) var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler() init(_ confirmation: AttributeConfirmation) { self.confirmation = confirmation didTapResend() } func didInput(_ string: String) { stateRelay.value.input = string validate() } func didTapResend() { guard stateRelay.value.resendDebouncer == 0 else { return } stateRelay.value.resendDebouncer = 60 timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] in guard let self = self, self.stateRelay.value.resendDebouncer > 0 else { $0.invalidate() return } self.stateRelay.value.resendDebouncer -= 1 } } func didTapNext() { hudRelay.send(.on) backgroundScheduler.schedule { [weak self] in guard let self = self else { return } do { try self.messenger.ud.get()!.confirmFact( confirmationId: self.confirmation.confirmationId!, code: self.stateRelay.value.input ) if self.confirmation.isEmail { self.email = self.confirmation.content } else { self.phone = self.confirmation.content } self.timer?.invalidate() self.hudRelay.send(.none) self.completionRelay.send(self.confirmation) self.backupService.performBackup() } catch { self.hudRelay.send(.error(.init(with: error))) } } } private func validate() { switch Validator.code.validate(stateRelay.value.input) { case .success: stateRelay.value.status = .valid(nil) case .failure(let error): stateRelay.value.status = .invalid(error) } } }