Home > Mobile >  How to reset and start new timer when enter new email
How to reset and start new timer when enter new email

Time:04-02

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()
  • Related