Sencha Touch: Prevent multiple concurrent transitions - sencha-touch

QA just filed a real doozy of a bug, and I'm scratching my head how to fix it.
If two buttons, e.g. back, and search are pressed at the same time, each will invoke Ext.dispatch, causing two simultaneous opposing transitions! This totally !##$s up the layout, rendering the app unusable.
This is really a general problem with touch-enabled apps... with multiple fingers hovering over the screen, the user can easily trigger weird and totally incompatible action combinations, and the app needs to accept only one at a time. Is there any way to handle this situation gracefully in Sencha Touch?

I fixed it by listening to the before-dispatch event, and canceling it if there is a dispatch already in progress.
Ext.regApplication(...
this._isDispatching = false,
launch: function() {
Ext.Dispatcher.on('before-dispatch', function () {
var me;
if (this._isDispatching)
return false;
else {
this._isDispatching = true;
me = this;
setTimeout(function () {
me._isDispatching = false;
}, 500);
return true;
}
}, this);
}
Yes, the 500ms delay is definitely hacky, but I couldn't think of a more robust way of detecting when the transition has completed. There is no after-dispatch event, and the dispatch event fires before the transition has completed.
Hope this helps someone.

Related

How to stop autoplay immediately when hover in Swiper

I made custom feature to stop auto play when user hover on swiper. It is working but there is a problem. It won't stop immediately, instead of it has delay time = swiper's speed. How to stop it immediately. Please help me.
swiper.hover( function() {
swiper.autoplay.stop();
}, function() {
swiper.autoplay.start();
} );

Push Notifications. How to know if the app was in foreground or background

When a notification arrives the app executes the callback configured for receiving the notifications.
In case the notification arrives with the app in background I want the application to move to a specific view. But if the notification arrives with the app in foreground I just want to print an alert.
How can I know in the callback function the status of the application when the notification arrived?
Thank you.
I don't know how dependable this is, but it seems to work when the app is running, but just in the background:
var sleeping = false;
document.addEventListener("pause", function() {sleeping = true;}, false);
document.addEventListener("resume", function() {sleeping = false;}, false);
and then:
function pushNotificationReceived(props, payload) {
if (sleeping) {
alert("caught me napping");
} else {
alert("I've been waiting for you.");
}
}
The tricky case is when the application is completely stopped. You need to log in before the notification callback gets called, and the resume event is fired long before this. If you want to handle that case, you will probably need something like the following in your WL.Client.Push.onReadyToSubscribe function:
sleeping = true;
setTimeout(function(){sleeping = false;}, 1000);
(anything that arrives within 1 second of being ready to subscribe, probably arrived when we were asleep, and is just getting delivered now)
It is a bit of a haCk, and I'm sure there are all sorts of odd timing cases but it seems to cover many of the cases.

Double click on buttons inside the app could provide UI corruptions

Double clicking fast on a button in Sencha Touch 2 when having a navigation view will on some Android device push the new view twice on the view stack, how to solve it? Doesnt happen on iPhone
If you're having problems with the single click, then wrap the event function in a delayed task... for instance:
tap: function(button, e, eOpts) {
if(this.delayedTask == null){
this.delayedTask = Ext.create('Ext.util.DelayedTask', function() {
this.myFunctionToCall();
this.delayedTask = null;
}, this);
this.delayedTask.delay(500);
}
}
So in the example above, if another tap is registered and this.delayedTask has yet to be null, then it will not create the new delayed task which ultimately calls whatever function you need after 500 miliseconds... hope this makes sense, it's also a way to create double tap events on buttons...
This issue is a bit old but I was facing the same issue in the app I'm working on in my company. This is especially frustrating when buttons are bound to an Ajax call.
I took back Jeff Wooden's solution to override every button in my app :
Ext.define('MyApp.override.CustomButton', {
override : 'Ext.Button',
doTap: function(me, e) {
if(this.delayedTask == null){
this.callOverridden(arguments);
this.delayedTask = Ext.create('Ext.util.DelayedTask', function() {
this.delayedTask = null;
}, this);
this.delayedTask.delay(500);
} else {
console.log("Preventing double tap");
}
}
});
How does it works?
Each button action will trigger a delayedTask which will intercept button action for 500 ms, therefore preventing doubletap
This will work for 'tap' and 'handler:', which both pass through 'doTap' method
this is linked to the current button so it won't reverberate on other buttons
To use it simply add it in your app.js 'requires' block
Ext.application({
requires: [
...
'MyApp.override.CustomButton',
...
],
Helpfull Sources :
https://www.sencha.com/forum/showthread.php?173374-Ext-override()-on-Ext-components-in-ExtJS-4-x
Best practice for overriding classes / properties in ExtJS?
this post

.queue() and .proxy(), animation timing in jQuery

I'm working on a pseudo plugin (just really an namespaced initializer on the jQuery object) and I'm having a bit of trouble with .proxy() and .queue() (seemingly two of the most misunderstood methods around)
Anyways, I thought I had the logic sorted out; the function $.cb() takes a map of functions as such:
$.cb({
'show': function(){ },
'hide': function(){ },
'open': function(){ },
'close': function(){ },
'beforeUpdate': function(){ },
'afterUpdate': function(){ }
});
These functions (should) contain animation sequences applied to $(this), the context of which has internally, via .proxy(), been changed to the respective element(s). They are stored in a settings variable, available to all methods of the "plugin".
Internally, some namespaced event handlers, attached via .live({ }):
// ...
'cb.hide': function(event){
if(event.isPropagationStopped()){
return false;
}
event.stopPropagation();
$.proxy(settings.hide, this)();
$(this).hide();
},
'cb.update': function(event, html){
if(event.isPropagationStopped()){
return false;
}
event.stopPropagation();
$.proxy(settings.beforeUpdate, this)();
$(this).html(html);
$.proxy(settings.afterUpdate, this)();
},
// ...
Anyways, the purpose is that there in inherent functionality brought to the table using this "plugin", but the implementer can pass the function map to opt for different transitional animations.
The problem, is that I can't seem to get these functions to queue properly; different ones taking precedence, etc. I've tried mocking around with .queue() but I can't seem to get anything right with it:
// in cb.update
var $this = $(this);
$(this).queue(function(next){
$.proxy(settings.beforeUpdate, $this)();
next();
}).queue(function(next){
$this.html(html);
next();
}).queue(function(next){
$.proxy(settings.afterUpdate, $this)();
}).dequeue();
The problem is especially prevalent with the 'cb.update' event, as the order should be:
beforeUpdate is called (animation sequence occurs and completes)
The element's contents are updated via .html()
afterUpdate is called (animation sequence occurs and completes)
Whats actually happening is:
The element's contents are updated via .html()
beforeUpdate is called (animation sequence occurs and completes)
afterUpdate is called (animation sequence occurs and completes)
So given the supplied animation is simply .fadeOut() and fadeIn() for beforeUpdate and afterUpdate respectively, it's updating the contents, then fading out and in.
So, any suggestions on this sort of implementation? How can I ensure the proper ordering of the events/animations? Have I gone a wildly stupid route in terms of trying to implement such a feature?

how to detect doubletap without triggering silgeltap in sencha touch

is there a smart and simple way to detect a doubletap without triggering a silgeltap in sencha touch?
thnx!
I don't think there is a 'clean' way to do it. It will delay the single tap option by 300ms which may be unacceptable. You may want to simplify your UI interactions if you can. Maybe a tap and hold?
I found this code in the Sencha Touch forums.
setupEventHandlers: function(){
this.mon(this.el, {
tap: function(e){
if(this.delayedTask == null){
//setup a delayed task that is called IF double click is not later detected
this.delayedTask = new Ext.util.DelayedTask(
function(){
this.doSomethingInteresting();
this.delayedTask = null;
}, this);
//invoke (with reasonable time to cancel)
this.delayedTask.delay(300);
}
},
doubletap: function(e){
//cancel and clear the queued single click tasks if it's there
if(this.delayedTask != null){
this.delayedTask.cancel();
this.delayedTask = null;
}
//handle the double click
this.doSomethingReallyInteresting();
},
scope: this
});
},