Search code examples
androidbufferrx-javarx-android

Catch number of user clicks in timespan using RxJava


I have application, which have hidden debug menu. I need to enable this secret menu, if (Build.DEBUG and) user clicks on a view for example 4x times in one second. I would like to use for this RxJava.

I tried DebouncedBuffer by Kaushik Gopal on weddingpartyapp, but this counts clicks, and returns value if there were no click over a specified period of time.

I have achieved the desired effect by using simple buffer(), but it starts buffering and keeps emitting empty lists, if there is no clicks. I can add filter(), but I would like to achieve same result different way.

I would like to start buffer after first click, and collect all clicks (bufer()?) with provided period of time (debounce()?), then stop buffering. I found buffer(bufferOpenings, bufferClosingSelector) enter image description here

which do what I need, and I found example of use, in Intro-To-RxJava but it depends in interval(). How to change, this, that first observable will be first value in group, and than function will triggered after one second from first value?

Moreover, I found this answer, which adds checking number of items (which would be helpful too, cause I can stop Observable after receiving 4 clicks), but can I achieve same effect without creating new Operator?


Solution

  • The buffer you found is a good start but you also need publish to split the stream into two: one will be buffered to see if there is 4 clicks and the other will act as the trigger for for opening buffers with a time limit:

    PublishSubject<Integer> source = PublishSubject.create();
    TestScheduler ts = Schedulers.test();
    
    source.publish(p -> 
        p.buffer(p, o -> Observable.timer(1, TimeUnit.SECONDS, ts))
    )
    .filter(v -> v.size() == 4)
    .subscribe(v -> System.out.println("Secret menu"));
    
    System.out.println("Should open secret menu:");
    
    source.onNext(1);
    ts.advanceTimeBy(100, TimeUnit.MILLISECONDS);
    source.onNext(1);
    ts.advanceTimeBy(100, TimeUnit.MILLISECONDS);
    source.onNext(1);
    ts.advanceTimeBy(100, TimeUnit.MILLISECONDS);
    source.onNext(1);
    ts.advanceTimeBy(1000, TimeUnit.MILLISECONDS);
    
    
    System.out.println("Should not open anything:");
    
    source.onNext(1);
    ts.advanceTimeBy(100, TimeUnit.MILLISECONDS);
    source.onNext(1);
    source.onNext(1);
    ts.advanceTimeBy(1000, TimeUnit.MILLISECONDS);
    source.onNext(1);