From b3994f932eec734c2d2127be670b5e47cbbd30f8 Mon Sep 17 00:00:00 2001 From: Ivan Babkin Date: Mon, 17 Jun 2019 19:32:23 +0300 Subject: [PATCH] Added possibility to observe loading state changing --- ReCaptcha/Classes/ReCaptcha.swift | 8 ++++++++ .../Classes/ReCaptchaWebViewManager.swift | 8 ++++++++ ReCaptcha/Classes/Rx/ReCaptcha+Rx.swift | 20 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/ReCaptcha/Classes/ReCaptcha.swift b/ReCaptcha/Classes/ReCaptcha.swift index c7a3a91..18f888e 100644 --- a/ReCaptcha/Classes/ReCaptcha.swift +++ b/ReCaptcha/Classes/ReCaptcha.swift @@ -13,6 +13,8 @@ import WebKit /** */ public class ReCaptcha { + public typealias BoolParameterClosure = (Bool) -> () + fileprivate struct Constants { struct InfoDictKeys { static let APIKey = "ReCaptchaKey" @@ -101,6 +103,12 @@ public class ReCaptcha { } } + /// Callback for WebView loading state changing + public var onLoadingChanged: BoolParameterClosure? { + get { return manager.onLoadingChanged } + set { manager.onLoadingChanged = newValue } + } + /// The worker that handles webview events and communication let manager: ReCaptchaWebViewManager diff --git a/ReCaptcha/Classes/ReCaptchaWebViewManager.swift b/ReCaptcha/Classes/ReCaptchaWebViewManager.swift index 720c730..f7149d5 100644 --- a/ReCaptcha/Classes/ReCaptchaWebViewManager.swift +++ b/ReCaptcha/Classes/ReCaptchaWebViewManager.swift @@ -44,6 +44,9 @@ internal class ReCaptchaWebViewManager { public var shouldSkipForTests = false #endif + /// Callback for loading state changing + var onLoadingChanged: ReCaptcha.BoolParameterClosure? + /// Sends the result message var completion: ((ReCaptchaResult) -> Void)? @@ -106,6 +109,7 @@ internal class ReCaptchaWebViewManager { */ init(html: String, apiKey: String, baseURL: URL, endpoint: String) { self.endpoint = endpoint + self.decoder = ReCaptchaDecoder { [weak self] result in self?.handle(result: result) } @@ -133,6 +137,7 @@ internal class ReCaptchaWebViewManager { Starts the challenge validation */ func validate(on view: UIView) { + onLoadingChanged?(true) #if DEBUG guard !shouldSkipForTests else { completion?(.token("")) @@ -194,6 +199,7 @@ fileprivate extension ReCaptchaWebViewManager { webView.evaluateJavaScript(Constants.NumberOfDivsCommand) { [weak self] (result, error) -> Void in if let error = error { self?.decoder.send(error: .unexpected(error)) + self?.onLoadingChanged?(false) } else { self?.handleNumberOfDivs(result: result, count: count) } @@ -227,6 +233,7 @@ fileprivate extension ReCaptchaWebViewManager { } } else { decoder.send(error: .htmlLoadError) + onLoadingChanged?(false) } } @@ -238,6 +245,7 @@ fileprivate extension ReCaptchaWebViewManager { if let error = error { self?.decoder.send(error: .unexpected(error)) } + self?.onLoadingChanged?(false) } } diff --git a/ReCaptcha/Classes/Rx/ReCaptcha+Rx.swift b/ReCaptcha/Classes/Rx/ReCaptcha+Rx.swift index 824367c..516cca3 100644 --- a/ReCaptcha/Classes/Rx/ReCaptcha+Rx.swift +++ b/ReCaptcha/Classes/Rx/ReCaptcha+Rx.swift @@ -9,6 +9,10 @@ import RxSwift import UIKit +public enum ReCaptchaRxError: Error { + case baseWasReleased +} + /// Makes ReCaptcha compatible with RxSwift extensions extension ReCaptcha: ReactiveCompatible {} @@ -64,4 +68,20 @@ public extension Reactive where Base: ReCaptcha { base?.reset() } } + + /** + Observable of loading state + (will not work if someone changes onLoadingChanged variable; current onLodinglChanged will not work after subscription) + */ + var loadingObservable: Observable { + return .create { [weak base] observer -> Disposable in + guard let base = base else { + observer.onError(ReCaptchaRxError.baseWasReleased) + return Disposables.create() + } + + base.onLoadingChanged = { observer.onNext($0) } + return Disposables.create { [weak base] in base?.onLoadingChanged = nil } + } + } }