Wallet/src/js/directives/slideToAccept.js

256 lines
7.6 KiB
JavaScript

'use strict';
angular.module('copayApp.directives')
.directive('slideToAccept', function($timeout, $window, $q) {
return {
restrict: 'E',
templateUrl: 'views/includes/slideToAccept.html',
transclude: true,
scope: {
sendStatus: '=slideSendStatus',
onConfirm: '&slideOnConfirm',
isDisabled: '=isDisabled'
},
link: function(scope, element, attrs) {
var KNOB_WIDTH = 71;
var MAX_SLIDE_START_PERCENTAGE = 50;
var FULLY_SLID_PERCENTAGE = 72;
var PERCENTAGE_BUMP = 5;
var JIGGLE_EASING = linear;
var JIGGLE_DURATION = 100;
var RECEDE_DURATION = 250;
var INITIAL_TAP_EASE_DURATION = 75;
var elm = element[0];
var isSliding = false;
var curSliderPct = getKnobWidthPercentage();
var curBitcoinPct = 0;
var curTextPct = 0;
var currentEaseStartTime;
var bezier = $window.BezierEasing(0.175, 0.885, 0.320, 1.275);
scope.isSlidFully = false;
scope.displaySendStatus = '';
scope.$watch('sendStatus', function() {
if (!scope.sendStatus) {
reset();
} else if (scope.sendStatus === 'success') {
scope.displaySendStatus = '';
$timeout(function() {
reset();
}, 500);
} else {
scope.displaySendStatus = scope.sendStatus;
}
});
function easePosition(fromPct, pct, duration, easeFx, animateFx) {
var deferred = $q.defer();
currentEaseStartTime = Date.now();
var startTime = currentEaseStartTime;
var initialPct = fromPct;
var distance = pct - fromPct;
function ease() {
if (startTime !== currentEaseStartTime) {
return;
}
$window.requestAnimationFrame(function() {
var now = Date.now();
var elapsed = now - startTime;
var normalizedElapsedTime = elapsed / duration;
var newVal = easeFx(normalizedElapsedTime);
var newPct = newVal * distance + initialPct;
animateFx(newPct);
scope.$digest();
if (elapsed < duration) {
ease();
} else {
deferred.resolve();
}
});
}
ease();
return deferred.promise;
}
function linear(t) {
return t;
}
function easeInOutBack(t) {
return bezier(t);
}
function reset() {
scope.isSlidFully = false;
isSliding = false;
setNewSliderStyle(getKnobWidthPercentage());
setNewBitcoinStyle(0);
setNewTextStyle(0);
}
function setNewSliderStyle(pct) {
var knobWidthPct = getKnobWidthPercentage();
var translatePct = pct - knobWidthPct;
if (isSliding) {
translatePct += 0.35 * pct;
}
scope.sliderStyle = getTransformStyle(translatePct);
curSliderPct = pct;
}
function setNewBitcoinStyle(pct) {
var translatePct = -2.25 * pct;
scope.bitcoinStyle = getTransformStyle(translatePct);
curBitcoinPct = pct;
}
function setNewTextStyle(pct) {
var translatePct = -0.1 * pct;
scope.textStyle = getTransformStyle(translatePct);
curTextPct = pct;
}
function getTransformStyle(translatePct) {
return {
'transform': 'translateX(' + translatePct + '%)',
'-webkit-transform': 'translateX(' + translatePct + '%)'
};
}
function getKnobWidthPercentage() {
var knobWidthPct = (KNOB_WIDTH / elm.clientWidth) * 100;
return knobWidthPct;
}
function setSliderPosition(pct) {
setNewSliderStyle(pct);
setNewBitcoinStyle(pct);
setNewTextStyle(pct);
}
function easeSliderPosition(pct) {
var duration = INITIAL_TAP_EASE_DURATION;
easePosition(curSliderPct, pct, duration, JIGGLE_EASING, function(pct) {
setNewSliderStyle(pct);
});
easePosition(curBitcoinPct, pct, duration, JIGGLE_EASING, function(pct) {
setNewBitcoinStyle(pct);
});
easePosition(curTextPct, pct, duration, JIGGLE_EASING, function(pct) {
setNewTextStyle(pct);
});
}
function jiggleSlider() {
var pct = getKnobWidthPercentage() + PERCENTAGE_BUMP;
var duration = JIGGLE_DURATION;
var p1 = easePosition(curSliderPct, pct, duration, JIGGLE_EASING, function(pct) {
setNewSliderStyle(pct);
});
var p2 = easePosition(curBitcoinPct, pct, duration, JIGGLE_EASING, function(pct) {
setNewBitcoinStyle(pct);
});
$q.all([p1, p2]).then(function() {
recede();
});
}
function recede() {
var duration = RECEDE_DURATION;
easePosition(curSliderPct, getKnobWidthPercentage(), duration, easeInOutBack, function(pct) {
setNewSliderStyle(pct);
});
easePosition(curBitcoinPct, 0, duration, easeInOutBack, function(pct) {
setNewBitcoinStyle(pct);
});
easePosition(curTextPct, 0, duration, easeInOutBack, function(pct) {
setNewTextStyle(pct);
});
}
function alertSlidFully() {
scope.isSlidFully = true;
scope.onConfirm();
}
function getTouchXPosition($event) {
var x;
if ($event.touches || $event.changedTouches) {
if ($event.touches.length) {
x = $event.touches[0].clientX;
} else {
x = $event.changedTouches[0].clientX;
}
} else {
x = $event.clientX;
}
return x;
}
function getSlidPercentage($event) {
var x = getTouchXPosition($event);
var width = elm.clientWidth;
var pct = (x / width) * 100;
if (x >= width) {
pct = 100;
}
return pct;
}
scope.onTouchstart = function($event) {
if (scope.isSlidFully) {
return;
}
if (!isSliding) {
var pct = getSlidPercentage($event);
if (pct > MAX_SLIDE_START_PERCENTAGE) {
jiggleSlider();
return;
} else {
isSliding = true;
var knobWidthPct = getKnobWidthPercentage();
if (pct < knobWidthPct) {
pct = knobWidthPct;
}
pct += PERCENTAGE_BUMP;
easeSliderPosition(pct);
}
}
};
scope.onTouchmove = function($event) {
if (!isSliding || scope.isSlidFully) {
return;
}
var pct = getSlidPercentage($event);
var knobWidthPct = getKnobWidthPercentage();
if (pct < knobWidthPct) {
pct = knobWidthPct;
}
pct += PERCENTAGE_BUMP;
currentEaseStartTime = null;
setSliderPosition(pct);
};
scope.onTouchend = function($event) {
if (scope.isSlidFully) {
return;
}
var pct = getSlidPercentage($event);
if (isSliding && pct > FULLY_SLID_PERCENTAGE) {
pct = 100;
setSliderPosition(pct);
alertSlidFully();
} else {
recede();
}
isSliding = false;
};
}
};
});