How to Disable the button tap in 5 seconds by using rxSwift? - rx-swift

rxSwift version:
pod 'RxSwift', '6.2.0'
pod 'RxCocoa', '6.2.0'
TrueBtn.rx.tap.throttle(.seconds(5), scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] in
print("TrueBtn-true")
}).disposed(by: bag)
How to Disable the button tap in 5 seconds by using rxSwift?
There is a false button in the same view.
FalseBtn.rx.tap.throttle(.seconds(5), scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] in
print("FalseBtn-false")
}).disposed(by: bag)
I click the true button and after 1 second click the true button again. Then I click the false button.
Now the result is :
TrueBtn-true
wait for 1 second
FalseBtn-false
wait 4 seconds
TrueBtn-true
I want this:
TrueBtn-true
wait for 1 second
FalseBtn-false
wait more than 5 seconds
print nothing
parameter latest: Should latest element received in a due time wide time window since last element emission is emitted.
Can I write some code to set the latest
value to false without changing the rx-swift api?

The use case is a bit confusing to me. I'm going to assume it's something like.
When the user taps either the true or false button, they have 5 seconds to change their mind and tap the other button. Once the grace period is up, the app will print their choice and disable further taps.
Some marble diagrams to demonstrate:
User makes a selection and doesn't change their mind.
true: --T-----
false: --------
result: -------T|
User makes a selection and changes their mind before the 5 seconds are up.
true: --T---------
false: ------F-----
result: -----------F|
User makes a selection and tries to change their mind after 5 seconds.
true: --T-----------
false: --------F-----
result: -------T|
Here is the code that will do the above:
func useCase(trueButton: Observable<Void>, falseButton: Observable<Void>, scheduler: SchedulerType) -> Observable<Bool> {
Observable.merge(
trueButton.map { true },
falseButton.map { false }
)
.debounce(.seconds(5), scheduler: scheduler)
.take(1)
}

Related

macOS Key Event Slow Repeat

I'm trying to create a small WASD demo game in macOS. I'm using NSEvent for handling the key events. To detect the key presses, I'm searching for keyDown events. Here's what I have:
NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
(keyEvent) -> NSEvent? in
if self.keyDown(with: keyEvent) {
return nil
} else {
return keyEvent
}
}
func keyDown(with event: NSEvent) -> Bool {
userInt.keyDown(key: event.characters)
return true
}
So here, I'm holding the keys down (as you'd expect in a game), and I'm getting some very slow movement. Like, when I'm holding it down, it's very janky. Upon further inspection, I saw that the key repeat interval was 0.1s, which was set in my system preferences. This means that it's skipping frames. However, in a game, I don't want this setting to affect the movement. So how can I detect a key holding event without being held up by the key repeat interval?
You should ignore key-repeat events (with isARepeat true). Instead, when you get a key-down event, start a timer that fires however often you want to advance your game state. Advance the game state in that timer's firing code. When you get a key-up event, stop the timer.

Is there a way to clear/refresh the accessibility hierarchy cache

I have a UI test that checks the value of static text element, waits a few seconds and checks again to confirm a change. At first it wasn't working because the hierarchy was not updating. I noticed this in the log;
Use cached accessibility hierarchy for
I've put in a workaround for this by simply adding a tap to a menu and opening/closing it so that an event is synthesized and the hierarchy is updated.
It would be better, however, if there was a way to clear the cache directly or force and update. I haven't found one in the API. Am I missing something?
Any ideas?
this is what I am doing;
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 1")
sleep(20)
menu.tap()
sleep(1)
menu.tap()
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 2")
What I'd like to be able to do it
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 1")
sleep(20)
app.elements.refresh()
XCTAssertEqual(app.staticTexts["myText"].label, "Expected 2")
In order to force an update of the accessibility hierarchy, request the count property for any XCUIElementQuery:
// refresh
_ = XCUIApplication().navigationBars.count
// examine
print(XCUIApplication().debugDescription)
The above results in: "Get number of matches for: Descendants matching type NavigationBar" and "Snapshot accessibility hierarchy for com.myapp".
The following works for me in Xcode 10.2 (10E125):
import XCTest
extension XCUIApplication {
// WORKAROUND:
// Force XCTest to update its accessibility cache. When accessibility data
// like NSObject.accessibility{Label|Identifier} changes, it takes a while
// for XCTest to catch up. Calling this method causes XCTest to update its
// accessibility cache immediately.
func updateAccessibilityCache() {
_ = try? snapshot()
}
}
You should use expectationForPredicate, along the lines of...
let myText = app.staticTexts["myText"]
let waitFor = NSPredicate(format: "label = 'Expected 2'")
label.tap()
self.expectationForPredicate(waitFor, evaluatedWithObject: myText, handler: nil)
self.waitForExpectationsWithTimeout(2.0, handler: nil)
This will wait until either myText's label is 'Expected 2', or the timeout of 2 seconds is reached.
In my case, it is a problem because I'm trying to test for Facebook login, which uses Safari controller. It looks like Facebook has updated the UI after cache.
So you need to wait a bit, use the wait function here https://stackoverflow.com/a/42222302/1418457
wait(for: 2)
let _ = app.staticTexts.count
But the above is just workaround and very flaky. A more correct approach would be to wait for a certain element to appear, see https://stackoverflow.com/a/44279203/1418457

Graphically showing remaining time

Let's consider a user has t milliseconds to make a click, 0 < t < 5000. We'd like to show graphically how much time is left. Let's assume that the user has to click the button once again within t.
property int startTime
property int fps: 40
property int t: 1000 // for example
Button
{
id: btn
text: "Click me!"
onClicked:
{
text = "Click again!"
startTime = new Date().getTime()
timer.restart()
}
}
Timer
{
id: timer
interval: 1000 / fps
onTriggered:
{
var progress = (new Date().getTime() - startTime) / t
if (progress < 1)
{
pb.value = progress
restart()
}
else
{
pb.value = 1
btn.text = "Try again"
}
}
}
ProgressBar
{
id: pb
value: 0
}
I'm only worried about the performance impact. The UI should always remain accesible and react quickly to the tap, since t can be low. If it weren't, the user could click the button within the set time but "lose", since the application wouldn't respond to the click.
Should I worry about the performance hit? Is there any option to avoid it? I expect my application to be run on low-end devices too.
I'm using Qt on Android
If fps is reasonable, then I think that performance won't be an issue and the UI will remain responsive.
Anyway I think it is much more elegant to achieve the same result using an animation... You can use a NumberAnimation to continuously update the value of the progress bar, and then start the animation when you want to start counting the time left...

OS X agent app with NSTimer in the background is not working after deep sleep

I have a OS X agent app (which only runs from the icon in the menu bar). My app creates a NSTimer with random intervals to play a sound.
func setNewTimer(timeInterval: NSTimeInterval) {
self.timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: "playSound", userInfo: nil, repeats: false)
NSRunLoop.currentRunLoop().addTimer(self.timer!, forMode: NSRunLoopCommonModes)
NSLog("Timer created for interval: \(timeInterval)")
}
The app works all fine after I start it and keep doing other work in other apps. It plays the sound at random times as expected.
If the computer goes to sleep for a short period and comes back the app will keep playing sounds at random times as expected.
However, if my computer goes to sleep for a long time (e.g. throughout the night), the app will not play sounds anymore.
It may be possible that the problem is that the timer may be disabled if the computer goes to deep sleep? or (preferably) Is there a way to detect that the computer awoke from sleep so I can reset my timer?
Note: Every time I call this function I first self.timer.invalidate() and recalculate the timeInterval. At sleep time (e.g. 23:00 to 08:00 ) the timer will not run, but instead will create an interval from 23:00 to 08:00 so that it 'fires' the next day in the morning.
I've came up with a solution myself after I found that there was no reply for some time. The solution was pretty simple as I only needed to register for sleep and wake notifications (I added the code updated to Swift 3):
// App should get notifified when it goes to sleep
func receiveSleepNotification(_ notification: Notification) {
NSLog("Sleep nottification received: \(notification.name)")
// do invalidation work
}
/// App should get notified when the PC wakes up from sleep
func receiveWakeNotification(_ notification: Notification) {
NSLog("Wake nottification received: \(notification.name)")
// Reset/Restart tasks
}
func registerForNotitications() {
//These notifications are filed on NSWorkspace's notification center, not the default
// notification center. You will not receive sleep/wake notifications if you file
//with the default notification center.
NSWorkspace.shared().notificationCenter.addObserver(self, selector: #selector(AppDelegate.receiveSleepNotification(_:)), name: NSNotification.Name.NSWorkspaceWillSleep, object: nil)
NSWorkspace.shared().notificationCenter.addObserver(self, selector: #selector(AppDelegate.receiveWakeNotification(_:)), name: NSNotification.Name.NSWorkspaceDidWake, object: nil)
}
func deRegisterFromNotifications() {
NSWorkspace.shared().notificationCenter.removeObserver(self)
}

Double tap recognition takes too long? (Hammer.js 2.0)

I am programming a highly responsive web application and came across the issue that most time is used to recognize double taps.
I am using this code from the website:
var singleTap = new Hammer.Tap({ event: 'singletap' });
var doubleTap = new Hammer.Tap({event: 'doubletap', taps: 2 });
hammer.add([doubleTap, singleTap]);
doubleTap.recognizeWith(singleTap);
singleTap.requireFailure(doubleTap);
This basically works quite fine. However, due to the timeouts/intervals the recognition of a double tap takes quite "long". I guess its about 2 times the interval - one for each tap.
The waiting for the last interval (waiting for a third tap) is senseless in my scenario.
Is there any "ok tapCount == 2, we fire now and don't wait any longer"-TapRecognizer option?
Update, I have done some logging:
First column: passed ms since first event
0 input: mousedown
74ms input: mouseup
145ms input: mousedown
218ms input: mouseup
520ms double tap
-
0 input: mousedown
64ms input: mouseup
366ms single tap
This confirms my theory that double tap is waiting for a third click but I don't think there's an option to disable this.
I share my solution to the problem:
I copied the TapRecognizer and named it DblTapRecognizer. The interesting source code lines are:
if (tapCount === 0) {
// no failing requirements, immediately trigger the tap event
// or wait as long as the multitap interval to trigger
if (!this.hasRequireFailures()) {
return STATE_RECOGNIZED;
} else {
this._timer = setTimeoutContext(function() {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.interval, this);
return STATE_BEGAN;
}
}
"if (!this.hasRequireFailures())" seems to misbehave in my situation, since the comment hints at immediate firing... So just "return STATE_RECOGNIZED;" and delete the rest for the DblTapRecognizer.
We ran into similar slowness issues. Apparently there is an inherent lag on tap action on touch devices.
We ended up using FastClick
All you need to do is FastClick.attach(document.body);
This improved the "tap performance" for us.

Resources