I have an input that accept string, and store it in local data. My use case is when I enter an email, the user must wait for 2 minute for requesting send email verification. But when I enter a different email name, I can't make the timer reset when the last email I enter is still countdown. I'm using RxSwift for timer, I don't know how to invalidate the timer in RxSwift.
This is what I came so far to reset the timer when user enters new email
// function that accept email from uitextfield.text
func resendEmailCountdown(with email: String) {
if email != getLoggedEmail() {
startCountdown(countdown: 0)
startCountdown(countdown: 120)
} else {
startCountdown(countdown: 120)
}
}
private func startCountdown(countdown: Int) {
let counter = countdown
if counter == 0 {
_ = Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance)
.take(0)
.subscribe(onNext: { [weak self] countdown in
guard let self = self else { return }
}).disposed(by: disposeBag)
} else {
_ = Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance)
.take(counter 1)
.subscribe(onNext: { [weak self] countdown in
guard let self = self else { return }
let count = counter - countdown
if count != 0 {
self.eventResendEmailCountdown.onNext(count)
self.eventShowHideResendEmailButton.onNext(false)
} else {
self.eventShowHideResendEmailButton.onNext(true)
self.eventDismissCountdownBottomSheet.onNext(())
}
}).disposed(by: disposeBag)
}
}
CodePudding user response:
The key is using flatMapLatest
to cancel the previous timer and start up a new one.
Based on your description, here is what you need:
struct Output {
let eventResendEmailCountdown: Observable<Int>
let eventShowHideResendEmailButton: Observable<Bool>
let eventDismissCountdownBottomSheet: Observable<Void>
}
func example(text: Observable<String?>) -> Output {
let trigger = text.share()
let eventResendEmailCountdown = trigger
.flatMapLatest { _ in
Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
.map { 120 - $0 }
.take(until: { $0 == -1 })
}
let eventShowHideResendEmailButton = Observable.merge(
trigger.map { _ in false },
eventResendEmailCountdown.filter { $0 == 0 }.map { _ in true }
)
let eventDismissCountdownBottomSheet = eventResendEmailCountdown
.filter { $0 == 0 }
.map { _ in }
return Output(
eventResendEmailCountdown: eventResendEmailCountdown,
eventShowHideResendEmailButton: eventShowHideResendEmailButton,
eventDismissCountdownBottomSheet: eventDismissCountdownBottomSheet
)
}
Call it something like this:
let output = example(text: textField.rx.text.asObservable())
output.eventResendEmailCountdown
.debug("eventResendEmailCountdown")
.subscribe()
output.eventShowHideResendEmailButton
.debug("eventShowHideResendEmailButton")
.subscribe()
output.eventDismissCountdownBottomSheet
.debug("eventDismissCountdownBottomSheet")
.subscribe()