0

because of a requirement to auto remove Text after its appearance in 2 seconds, I want to write this operator but still cannot figure out the best way to implement.

enter image description here

We can put a timespan parameter and get a new stream, here are two interfaces need to implement

extension Publisher {
    func reset<T, S: Scheduler>(
        after: S.SchedulerTimeType.Stride,
        on scheduler: S
    ) -> AnyPublisher<T, Failure> where Output == Optional<T> {
        // implementation
    }
    
    func autoToggle<S: Scheduler>(
        after: S.SchedulerTimeType.Stride,
        on scheduler: S
    ) -> AnyPublisher<Bool, Failure> {
        // implementation
    }
}

Really appreciate your help.

Quang Hà
  • 4,613
  • 3
  • 24
  • 40

1 Answers1

2

I assume you want something that doesn't turn on for more than 2 minutes.

The key operator will be something like this

$autoToggle
    .filter { $0 } // only take True signal
    .debounce(for: .seconds(2), scheduler: RunLoop.main) // for 2 second delay
    .map { !$0 } // turn it to False

I've created a sample so you can test and play with it

class ToggleTestViewMoel: ObservableObject {
    private var resetSubject = PassthroughSubject<Bool, Never>()
    @Published var autoToggle: Bool = false
    
    init() {
        let autoTurnOff = $autoToggle
            .filter { $0 }
            .debounce(for: .seconds(2), scheduler: RunLoop.main)
            .map { !$0 }
        
        resetSubject.merge(with: autoTurnOff)
            .assign(to: &$autoToggle)
    }
    
    func setReset(value: Bool) { resetSubject.send(value) }
}

struct ToggleTestView: View {
    @StateObject var viewModel = ToggleTestViewMoel()
    var body: some View {
        List {
            Button("Turn On") { viewModel.setReset(value: true) }
            Button("Turn Off") { viewModel.setReset(value: false) }
            Toggle("Auto Toggle", isOn: $viewModel.autoToggle)
        }
    }
}

struct TestOtherTestViews_Previews: PreviewProvider {
    static var previews: some View {
        ToggleTestView()
    }
}

enter image description here

UPDATE

If time interval between 2 signals from resetSubject always more than 2 seconds, you can replace

.debounce(for: .seconds(2), scheduler: RunLoop.main)

with

.delay(for: .seconds(2), scheduler: RunLoop.main, options: .none)
meomeomeo
  • 764
  • 4
  • 7
  • Thank you a lot for your careful reply, using `debounce` like yours is better i think. I just want to make publisher extensions, like converting this stream `true-false` to new stream `true-false-false`, because i use those streams in many places. – Quang Hà Mar 09 '22 at 00:17