mirror of https://github.com/BTCPrivate/copay.git
refactor(old): remove unused code
This commit is contained in:
parent
d1b2f6adb1
commit
aad5227542
82
old/go.js
82
old/go.js
|
@ -1,82 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('go', function($window, $ionicSideMenuDelegate, $rootScope, $location, $state, $timeout, $log, profileService, platformInfo, nodeWebkit) {
|
||||
var root = {};
|
||||
|
||||
root.openExternalLink = function(url, target) {
|
||||
if (platformInfo.isNW) {
|
||||
nodeWebkit.openExternalLink(url);
|
||||
} else {
|
||||
target = target || '_blank';
|
||||
var ref = window.open(url, target, 'location=no');
|
||||
}
|
||||
};
|
||||
|
||||
root.is = function(name) {
|
||||
return $state.is(name);
|
||||
};
|
||||
|
||||
root.path = function(path, cb) {
|
||||
$state.transitionTo(path)
|
||||
.then(function() {
|
||||
if (cb) return cb();
|
||||
}, function() {
|
||||
if (cb) return cb('animation in progress');
|
||||
});
|
||||
};
|
||||
|
||||
root.toggleLeftMenu = function() {
|
||||
$ionicSideMenuDelegate.toggleLeft();
|
||||
};
|
||||
|
||||
root.walletHome = function() {
|
||||
var wallet = profileService.getWallet($stateParams.walletId);
|
||||
if (wallet && !wallet.isComplete()) {
|
||||
$log.debug("Wallet not complete at startup... redirecting");
|
||||
$state.transitionTo('wallet.details', {
|
||||
walletId: wallet.credentials.walletId
|
||||
})
|
||||
} else {
|
||||
root.path('tabs.home');
|
||||
}
|
||||
};
|
||||
|
||||
root.confirm = function(params) {
|
||||
$state.transitionTo('send.confirm', params)
|
||||
};
|
||||
|
||||
root.send = function() {
|
||||
root.path('tabs.send');
|
||||
};
|
||||
|
||||
root.addWallet = function() {
|
||||
$state.transitionTo('add');
|
||||
};
|
||||
|
||||
root.preferences = function() {
|
||||
$state.transitionTo('preferences');
|
||||
};
|
||||
|
||||
root.preferencesGlobal = function() {
|
||||
$state.transitionTo('tabs.settings');
|
||||
};
|
||||
|
||||
root.reload = function() {
|
||||
$state.reload();
|
||||
};
|
||||
|
||||
|
||||
// Global go. This should be in a better place TODO
|
||||
// We don't do a 'go' directive, to use the benefits of ng-touch with ng-click
|
||||
$rootScope.go = function(path) {
|
||||
root.path(path);
|
||||
};
|
||||
|
||||
$rootScope.openExternalLink = function(url, target) {
|
||||
root.openExternalLink(url, target);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return root;
|
||||
});
|
1338
old/index.js
1338
old/index.js
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +0,0 @@
|
|||
<a ng-click="index.setTab(item, false, 0, true)"
|
||||
ng-style="{'color': index.tab == item.link ? index.backgroundColor : '#A5B2BF'}"
|
||||
id="menu-{{item.link}}">
|
||||
<i class="size-18 {{item.icon[index.tab == item.link]}} db"></i>
|
||||
<span class="size-10 tu">
|
||||
{{ item.title|translate }}
|
||||
<span class="label round"
|
||||
ng-style="{'background-color':index.backgroundColor}"
|
||||
ng-if="item.link=='walletHome' && index.pendingTxProposalsCountForUs > 0">
|
||||
{{ index.pendingTxProposalsCountForUs }}
|
||||
</span>
|
||||
</span>
|
||||
<div ng-if="item.link == 'walletHome'" class="menu-wallet-home"></div>
|
||||
</a>
|
|
@ -1,18 +0,0 @@
|
|||
<div class="dr-notification-wrapper" ng-repeat="noti in queue" ng-click="removeNotification(noti)">
|
||||
<div class="dr-notification animated bounceInDown">
|
||||
<div class="dr-notification-image" ng-switch on="noti.image">
|
||||
<i class="{{noti.icon}}" ng-switch-when="false"></i>
|
||||
<img ng-src="{{noti.image}}" ng-switch-default />
|
||||
</div>
|
||||
<div class="dr-notification-content">
|
||||
<h3 class="dr-notification-title">{{noti.title|translate}}</h3>
|
||||
<div class="dr-notification-text label radius" ng-show="noti.userData.color"
|
||||
ng-style="{'background-color':noti.userData.color}">{{noti.content|translate}}
|
||||
</div>
|
||||
<div class="dr-notification-text" ng-show="!noti.userData.color"
|
||||
>{{noti.content|translate}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').
|
||||
factory('notification', function($timeout, platformInfo) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var notifications = [];
|
||||
|
||||
/*
|
||||
ls.getItem('notifications', function(err, data) {
|
||||
if (data) {
|
||||
notifications = JSON.parse(data);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
var queue = [];
|
||||
var settings = {
|
||||
info: {
|
||||
duration: 6000,
|
||||
enabled: true
|
||||
},
|
||||
funds: {
|
||||
duration: 7000,
|
||||
enabled: true
|
||||
},
|
||||
version: {
|
||||
duration: 60000,
|
||||
enabled: true
|
||||
},
|
||||
warning: {
|
||||
duration: 7000,
|
||||
enabled: true
|
||||
},
|
||||
error: {
|
||||
duration: 7000,
|
||||
enabled: true
|
||||
},
|
||||
success: {
|
||||
duration: 5000,
|
||||
enabled: true
|
||||
},
|
||||
progress: {
|
||||
duration: 0,
|
||||
enabled: true
|
||||
},
|
||||
custom: {
|
||||
duration: 35000,
|
||||
enabled: true
|
||||
},
|
||||
details: true,
|
||||
localStorage: false,
|
||||
html5Mode: false,
|
||||
html5DefaultIcon: 'img/favicon.ico'
|
||||
};
|
||||
|
||||
function html5Notify(icon, title, content, ondisplay, onclose) {
|
||||
if (window.webkitNotifications && window.webkitNotifications.checkPermission() === 0) {
|
||||
if (!icon) {
|
||||
icon = 'img/favicon.ico';
|
||||
}
|
||||
var noti = window.webkitNotifications.createNotification(icon, title, content);
|
||||
if (typeof ondisplay === 'function') {
|
||||
noti.ondisplay = ondisplay;
|
||||
}
|
||||
if (typeof onclose === 'function') {
|
||||
noti.onclose = onclose;
|
||||
}
|
||||
noti.show();
|
||||
} else {
|
||||
settings.html5Mode = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
|
||||
/* ========== SETTINGS RELATED METHODS =============*/
|
||||
|
||||
disableHtml5Mode: function() {
|
||||
settings.html5Mode = false;
|
||||
},
|
||||
|
||||
disableType: function(notificationType) {
|
||||
settings[notificationType].enabled = false;
|
||||
},
|
||||
|
||||
enableHtml5Mode: function() {
|
||||
// settings.html5Mode = true;
|
||||
settings.html5Mode = this.requestHtml5ModePermissions();
|
||||
},
|
||||
|
||||
enableType: function(notificationType) {
|
||||
settings[notificationType].enabled = true;
|
||||
},
|
||||
|
||||
getSettings: function() {
|
||||
return settings;
|
||||
},
|
||||
|
||||
toggleType: function(notificationType) {
|
||||
settings[notificationType].enabled = !settings[notificationType].enabled;
|
||||
},
|
||||
|
||||
toggleHtml5Mode: function() {
|
||||
settings.html5Mode = !settings.html5Mode;
|
||||
},
|
||||
|
||||
requestHtml5ModePermissions: function() {
|
||||
if (window.webkitNotifications) {
|
||||
if (window.webkitNotifications.checkPermission() === 0) {
|
||||
return true;
|
||||
} else {
|
||||
window.webkitNotifications.requestPermission(function() {
|
||||
if (window.webkitNotifications.checkPermission() === 0) {
|
||||
settings.html5Mode = true;
|
||||
} else {
|
||||
settings.html5Mode = false;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/* ============ QUERYING RELATED METHODS ============*/
|
||||
|
||||
getAll: function() {
|
||||
// Returns all notifications that are currently stored
|
||||
return notifications;
|
||||
},
|
||||
|
||||
getQueue: function() {
|
||||
return queue;
|
||||
},
|
||||
|
||||
/* ============== NOTIFICATION METHODS ==============*/
|
||||
|
||||
info: function(title, content, userData) {
|
||||
return this.awesomeNotify('info', 'fi-info', title, content, userData);
|
||||
},
|
||||
|
||||
funds: function(title, content, userData) {
|
||||
return this.awesomeNotify('funds', 'icon-receive', title, content, userData);
|
||||
},
|
||||
|
||||
version: function(title, content, severe) {
|
||||
return this.awesomeNotify('version', severe ? 'fi-alert' : 'fi-flag', title, content);
|
||||
},
|
||||
|
||||
error: function(title, content, userData) {
|
||||
return this.awesomeNotify('error', 'fi-x', title, content, userData);
|
||||
},
|
||||
|
||||
success: function(title, content, userData) {
|
||||
return this.awesomeNotify('success', 'fi-check', title, content, userData);
|
||||
},
|
||||
|
||||
warning: function(title, content, userData) {
|
||||
return this.awesomeNotify('warning', 'fi-alert', title, content, userData);
|
||||
},
|
||||
|
||||
new: function(title, content, userData) {
|
||||
return this.awesomeNotify('warning', 'fi-plus', title, content, userData);
|
||||
},
|
||||
|
||||
sent: function(title, content, userData) {
|
||||
return this.awesomeNotify('warning', 'icon-paperplane', title, content, userData);
|
||||
},
|
||||
|
||||
awesomeNotify: function(type, icon, title, content, userData) {
|
||||
/**
|
||||
* Supposed to wrap the makeNotification method for drawing icons using font-awesome
|
||||
* rather than an image.
|
||||
*
|
||||
* Need to find out how I'm going to make the API take either an image
|
||||
* resource, or a font-awesome icon and then display either of them.
|
||||
* Also should probably provide some bits of color, could do the coloring
|
||||
* through classes.
|
||||
*/
|
||||
// image = '<i class="icon-' + image + '"></i>';
|
||||
return this.makeNotification(type, false, icon, title, content, userData);
|
||||
},
|
||||
|
||||
notify: function(image, title, content, userData) {
|
||||
// Wraps the makeNotification method for displaying notifications with images
|
||||
// rather than icons
|
||||
return this.makeNotification('custom', image, true, title, content, userData);
|
||||
},
|
||||
|
||||
makeNotification: function(type, image, icon, title, content, userData) {
|
||||
var notification = {
|
||||
'type': type,
|
||||
'image': image,
|
||||
'icon': icon,
|
||||
'title': title,
|
||||
'content': content,
|
||||
'timestamp': +new Date(),
|
||||
'userData': userData
|
||||
};
|
||||
|
||||
notifications.push(notification);
|
||||
|
||||
if (settings.html5Mode) {
|
||||
html5Notify(image, title, content, function() {
|
||||
// inner on display function
|
||||
}, function() {
|
||||
// inner on close function
|
||||
});
|
||||
}
|
||||
|
||||
//this is done because html5Notify() changes the variable settings.html5Mode
|
||||
if (!settings.html5Mode) {
|
||||
queue.push(notification);
|
||||
$timeout(function removeFromQueueTimeout() {
|
||||
queue.splice(queue.indexOf(notification), 1);
|
||||
}, settings[type].duration);
|
||||
}
|
||||
|
||||
// Mobile notification
|
||||
if (window && window.navigator && window.navigator.vibrate) {
|
||||
window.navigator.vibrate([200, 100, 200]);
|
||||
};
|
||||
|
||||
if (document.hidden && (type == 'info' || type == 'funds') && !isCordova) {
|
||||
new window.Notification(title, {
|
||||
body: content,
|
||||
icon: 'img/notification.png'
|
||||
});
|
||||
}
|
||||
|
||||
this.save();
|
||||
return notification;
|
||||
},
|
||||
|
||||
|
||||
/* ============ PERSISTENCE METHODS ============ */
|
||||
|
||||
save: function() {
|
||||
// Save all the notifications into localStorage
|
||||
if (settings.localStorage) {
|
||||
localStorage.setItem('notifications', JSON.stringify(notifications));
|
||||
}
|
||||
},
|
||||
|
||||
restore: function() {
|
||||
// Load all notifications from localStorage
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
notifications = [];
|
||||
this.save();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
);
|
|
@ -1,115 +0,0 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services')
|
||||
.factory('notificationService', function profileServiceFactory($filter, notification, lodash, configService, gettext) {
|
||||
|
||||
var root = {};
|
||||
|
||||
var groupingTime = 5000;
|
||||
var lastNotificationOnWallet = {};
|
||||
|
||||
root.getLast = function(walletId) {
|
||||
var last = lastNotificationOnWallet[walletId];
|
||||
if (!last) return null;
|
||||
|
||||
return Date.now() - last.ts < groupingTime ? last : null;
|
||||
};
|
||||
|
||||
root.storeLast = function(notificationData, walletId) {
|
||||
|
||||
if (notificationData.type == 'NewAddress')
|
||||
return;
|
||||
|
||||
lastNotificationOnWallet[walletId] = {
|
||||
creatorId: notificationData.creatorId,
|
||||
type: notificationData.type,
|
||||
ts: Date.now(),
|
||||
};
|
||||
};
|
||||
|
||||
root.shouldSkip = function(notificationData, last) {
|
||||
if (!last) return false;
|
||||
|
||||
// rules...
|
||||
if (last.type === 'NewTxProposal' &&
|
||||
notificationData.type === 'TxProposalAcceptedBy')
|
||||
return true;
|
||||
|
||||
if (last.type === 'TxProposalFinallyAccepted' &&
|
||||
notificationData.type === 'NewOutgoingTx')
|
||||
return true;
|
||||
|
||||
if (last.type === 'TxProposalRejectedBy' &&
|
||||
notificationData.type === 'TxProposalFinallyRejected')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
root.newBWCNotification = function(notificationData, walletId, walletName) {
|
||||
var last = root.getLast(walletId);
|
||||
root.storeLast(notificationData, walletId);
|
||||
|
||||
if (root.shouldSkip(notificationData, last))
|
||||
return;
|
||||
|
||||
var config = configService.getSync();
|
||||
config.colorFor = config.colorFor || {};
|
||||
var color = config.colorFor[walletId] || '#4A90E2';
|
||||
var name = config.aliasFor[walletId] || walletName;
|
||||
|
||||
switch (notificationData.type) {
|
||||
case 'NewTxProposal':
|
||||
notification.new(gettext('New Payment Proposal'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'TxProposalAcceptedBy':
|
||||
notification.success(gettext('Payment Proposal Signed by Copayer'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'TxProposalRejectedBy':
|
||||
notification.error(gettext('Payment Proposal Rejected by Copayer'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'TxProposalFinallyRejected':
|
||||
notification.error(gettext('Payment Proposal Rejected'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'NewOutgoingTx':
|
||||
notification.sent(gettext('Payment Sent'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'NewIncomingTx':
|
||||
notification.funds(gettext('Funds received'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
case 'ScanFinished':
|
||||
notification.success(gettext('Scan Finished'),
|
||||
name, {
|
||||
color: color
|
||||
});
|
||||
break;
|
||||
|
||||
case 'NewCopayer':
|
||||
// No UX notification
|
||||
break;
|
||||
case 'BalanceUpdated':
|
||||
// No UX notification
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
|
@ -1,86 +0,0 @@
|
|||
|
||||
<div class="topbar-container" ng-include="'views/includes/topbar.html'"
|
||||
ng-init="titleSection='Global preferences'; closeToHome = true; noColor = true">
|
||||
</div>
|
||||
|
||||
<div class="content preferences" ng-controller="preferencesGlobalController" ng-init="init()">
|
||||
<h4></h4>
|
||||
<ul>
|
||||
<li href ui-sref="preferencesLanguage">
|
||||
<div class="right text-gray">
|
||||
{{currentLanguageName|translate}}
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</div>
|
||||
<div translate>Language</div>
|
||||
</li>
|
||||
</ul>
|
||||
<h4></h4>
|
||||
|
||||
<ul class="no-bullet m0">
|
||||
<li href ui-sref="preferencesUnit">
|
||||
<div class="right text-gray">
|
||||
{{unitName}}
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</div>
|
||||
<div translate>Unit</div>
|
||||
</li>
|
||||
|
||||
<li href ui-sref="preferencesAltCurrency">
|
||||
<div class="right text-gray">
|
||||
{{selectedAlternative.name}}
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</div>
|
||||
<div translate>Alternative Currency</div>
|
||||
</li>
|
||||
</ul>
|
||||
<h4></h4>
|
||||
|
||||
<ul class="no-bullet m0">
|
||||
<li href ui-sref="preferencesFee">
|
||||
<div class="right text-gray">
|
||||
{{feeOpts[currentFeeLevel]|translate}}
|
||||
<i class="icon-arrow-right3 size-24 right"></i>
|
||||
</div>
|
||||
<div translate>Bitcoin Network Fee Policy</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ion-toggle ng-model="spendUnconfirmed" toggle-class="toggle-balanced" ng-change="spendUnconfirmedChange()">
|
||||
<span class="toggle-label" translate>Use Unconfirmed Funds</span>
|
||||
</ion-toggle>
|
||||
|
||||
<div ng-show="usePushNotifications && PNEnabledByUser">
|
||||
<h4></h4>
|
||||
<ion-toggle ng-model="pushNotifications" toggle-class="toggle-balanced" ng-change="pushNotificationsChange()">
|
||||
<span class="toggle-label" translate>Enable push notifications</span>
|
||||
</ion-toggle>
|
||||
</div>
|
||||
|
||||
<div class="m20t" ng-show="usePushNotifications && !PNEnabledByUser && isIOSApp">
|
||||
<div class="text-left text-gray size-12 m10" translate>Push notifications for Copay are currently disabled. Enable them in the Settings app.</div>
|
||||
<ul class="no-bullet m0" ng-click="openSettings()">
|
||||
<li ng-style="{'color':index.backgroundColor}" translate>Open Settings app</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h4></h4>
|
||||
|
||||
<ion-toggle ng-show="!index.isWindowsPhoneApp" ng-model="glideraEnabled" toggle-class="toggle-balanced" ng-change="glideraChange()">
|
||||
<span class="toggle-label" translate>Enable Glidera Service</span>
|
||||
</ion-toggle>
|
||||
<h4></h4>
|
||||
|
||||
<ion-toggle ng-show="!index.isWindowsPhoneApp" ng-model="coinbaseEnabled" toggle-class="toggle-balanced" ng-change="coinbaseChange()">
|
||||
<span class="toggle-label" translate>Enable Coinbase Service</span>
|
||||
</ion-toggle>
|
||||
<h4></h4>
|
||||
|
||||
<ul class="no-bullet m0">
|
||||
<li href ui-sref="about">
|
||||
<i class="icon-arrow-right3 size-24 right text-gray"></i>
|
||||
<div translate>About Copay</div>
|
||||
</li>
|
||||
</ul>
|
||||
<h4></h4>
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
|
@ -1,94 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesGlobalController',
|
||||
function($scope, $rootScope, $log, configService, uxLanguage, platformInfo, pushNotificationsService, profileService, feeService) {
|
||||
|
||||
$scope.init = function() {
|
||||
var config = configService.getSync();
|
||||
var isCordova = platformInfo.isCordova;
|
||||
|
||||
if (isCordova && StatusBar.isVisible) {
|
||||
StatusBar.backgroundColorByHexString("#4B6178");
|
||||
}
|
||||
|
||||
$scope.unitName = config.wallet.settings.unitName;
|
||||
$scope.currentLanguageName = uxLanguage.getCurrentLanguageName();
|
||||
$scope.selectedAlternative = {
|
||||
name: config.wallet.settings.alternativeName,
|
||||
isoCode: config.wallet.settings.alternativeIsoCode
|
||||
};
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.currentFeeLevel = feeService.getCurrentFeeLevel();
|
||||
$scope.usePushNotifications = isCordova && !platformInfo.isWP;
|
||||
$scope.PNEnabledByUser = true;
|
||||
$scope.isIOSApp = platformInfo.isIOS && isCordova;
|
||||
if ($scope.isIOSApp) {
|
||||
cordova.plugins.diagnostic.isRemoteNotificationsEnabled(function(isEnabled) {
|
||||
$scope.PNEnabledByUser = isEnabled;
|
||||
$scope.$digest();
|
||||
});
|
||||
}
|
||||
$scope.spendUnconfirmed = config.wallet.spendUnconfirmed;
|
||||
$scope.glideraEnabled = config.glidera.enabled;
|
||||
$scope.coinbaseEnabled = config.coinbase.enabled;
|
||||
$scope.pushNotifications = config.pushNotifications.enabled;
|
||||
};
|
||||
|
||||
$scope.openSettings = function() {
|
||||
cordova.plugins.diagnostic.switchToSettings(function() {
|
||||
$log.debug('switched to settings');
|
||||
}, function(err) {
|
||||
$log.debug(err);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.spendUnconfirmedChange = function() {
|
||||
var opts = {
|
||||
wallet: {
|
||||
spendUnconfirmed: $scope.spendUnconfirmed
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.pushNotificationsChange = function() {
|
||||
var opts = {
|
||||
pushNotifications: {
|
||||
enabled: $scope.pushNotifications
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (opts.pushNotifications.enabled)
|
||||
pushNotificationsService.enableNotifications(profileService.walletClients);
|
||||
else
|
||||
pushNotificationsService.disableNotifications(profileService.walletClients);
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.glideraChange = function() {
|
||||
var opts = {
|
||||
glidera: {
|
||||
enabled: $scope.glideraEnabled
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
$rootScope.$emit('Local/GlideraUpdated');
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.coinbaseChange = function() {
|
||||
var opts = {
|
||||
coinbase: {
|
||||
enabled: $scope.coinbaseEnabled
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
$rootScope.$emit('Local/CoinbaseUpdated');
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
});
|
|
@ -1,57 +0,0 @@
|
|||
<div class="sidebar" ng-controller="sidebarController as sidebar">
|
||||
<header>
|
||||
<img ng-if="sidebar.isWindowsPhoneApp" src="img/logo-negative.png" alt="Copay" width="80">
|
||||
<img ng-if="!sidebar.isWindowsPhoneApp" src="img/logo-negative.svg" alt="Copay" width="80">
|
||||
<div ng-include="'views/includes/version.html'"></div>
|
||||
</header>
|
||||
<ion-content>
|
||||
<ul class="pr">
|
||||
<li ng-show="sidebar.wallets[0]"
|
||||
ng-repeat="item in sidebar.wallets track by $index" ng-class="{'selected': item.id == index.walletId}" class="nav-item"
|
||||
menu-toggle href ui-sref="walletHome" on-tap="sidebar.switchWallet(item.id, index.walletId)">
|
||||
<div class="avatar-wallet" ng-style="{'background-color':item.color}">
|
||||
<i class="icon-wallet size-21"></i>
|
||||
</div>
|
||||
<div class="name-wallet" ng-class="{'m8t':item.n == 1}">{{item.name || item.id}}</div>
|
||||
<div class="size-12" ng-show="item.n > 1" translate>{{item.m}}-of-{{item.n}}</div>
|
||||
</li>
|
||||
<li menu-toggle href ui-sref="add">
|
||||
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
|
||||
<i class="fi-plus size-24 icon vm"></i>
|
||||
<div class="tu text-bold">
|
||||
<span class="size-12" translate>Add wallet</span>
|
||||
</div>
|
||||
<div translate>Create, join or import</div>
|
||||
</li>
|
||||
<li menu-toggle href ui-sref="bitpayCard" ng-show="index.isComplete && sidebar.bitpayCardEnabled">
|
||||
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
|
||||
<i class="fi-credit-card size-24 icon vm"></i>
|
||||
<div class="tu text-bold m10t">
|
||||
<span class="size-12" translate>BitPay Card</span>
|
||||
</div>
|
||||
</li>
|
||||
<li ng-show="!index.noFocusedWallet && !index.isWindowsPhoneApp && (index.glideraEnabled || index.coinbaseEnabled)" menu-toggle href ui-sref="buyandsell">
|
||||
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
|
||||
<i class="icon-bank size-24 icon vm"></i>
|
||||
<div class="tu text-bold m5t">
|
||||
<span class="size-12" translate>Buy and Sell</span>
|
||||
</div>
|
||||
</li>
|
||||
<li menu-toggle href ui-sref="amazon" ng-show="index.isComplete">
|
||||
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
|
||||
<i class="fi-shopping-bag size-24 icon vm"></i>
|
||||
<div class="tu text-bold m10t">
|
||||
<span class="size-12" translate>Gift Cards</span>
|
||||
</div>
|
||||
</li>
|
||||
<li ng-show="!index.noFocusedWallet" menu-toggle href ui-sref="preferencesGlobal">
|
||||
<i class="icon-arrow-right3 size-18 right m10t vm"></i>
|
||||
<i class="fi-widget size-24 icon vm"></i>
|
||||
<div class="tu text-bold">
|
||||
<span class="size-12" translate>Settings</span>
|
||||
</div>
|
||||
<div translate>Global preferences</div>
|
||||
</li>
|
||||
</ul>
|
||||
</ion-content>
|
||||
</div>
|
194
old/tab-scan.js
194
old/tab-scan.js
|
@ -1,194 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabScanController', function($scope, $timeout, $ionicModal, $log, $ionicPopup, configService, gettextCatalog, platformInfo, bitcore, lodash, $state, incomingData) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var isIOS = platformInfo.isIOS;
|
||||
|
||||
|
||||
|
||||
var _showAlert = function(title, msg, cb) {
|
||||
$log.warn(title + ":"+ msg);
|
||||
var alertPopup = $ionicPopup.alert({
|
||||
title: title,
|
||||
template: msg
|
||||
});
|
||||
|
||||
if (!cb) cb = function(res) {};
|
||||
|
||||
alertPopup.then(cb);
|
||||
};
|
||||
|
||||
var _dataScanned = function(data) {
|
||||
$log.debug('Scanned:' + data);
|
||||
if (!incomingData.redir(data)) {
|
||||
$log.warn('Fail to process scanned data');
|
||||
_showAlert('Bad bitcoin address', 'Could not recognize the bitcoin address', function(res) {
|
||||
$scope.init();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var onSuccess = function(result) {
|
||||
$timeout(function() {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
}, 100);
|
||||
if (isWP && result.cancelled) return;
|
||||
|
||||
$timeout(function() {
|
||||
var data = isIOS ? result : result.text;
|
||||
// Check if the current page is tabs.scan
|
||||
if ($state.is('tabs.scan')) {
|
||||
_dataScanned(data);
|
||||
return;
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
var onError = function(error) {
|
||||
$timeout(function() {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.cordovaOpenScanner = function() {
|
||||
window.plugins.spinnerDialog.show(null, gettextCatalog.getString('Preparing camera...'), true);
|
||||
$timeout(function() {
|
||||
if (isIOS) {
|
||||
cloudSky.zBar.scan({}, onSuccess, onError);
|
||||
} else {
|
||||
cordova.plugins.barcodeScanner.scan(onSuccess, onError);
|
||||
}
|
||||
if ($scope.beforeScan) {
|
||||
$scope.beforeScan();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.modalOpenScanner = function() {
|
||||
$ionicModal.fromTemplateUrl('views/modals/scanner.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.scannerModal = modal;
|
||||
$scope.scannerModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openScanner = function() {
|
||||
if (isCordova) {
|
||||
$scope.cordovaOpenScanner();
|
||||
} else {
|
||||
$scope.modalOpenScanner();
|
||||
}
|
||||
};
|
||||
|
||||
// QR code Scanner
|
||||
var video;
|
||||
var canvas;
|
||||
var $video;
|
||||
var context;
|
||||
var localMediaStream;
|
||||
var prevResult;
|
||||
var scanTimer;
|
||||
|
||||
var _scan = function(evt) {
|
||||
if (localMediaStream) {
|
||||
context.drawImage(video, 0, 0, 300, 225);
|
||||
try {
|
||||
qrcode.decode();
|
||||
} catch (e) {
|
||||
//qrcodeError(e);
|
||||
}
|
||||
}
|
||||
scanTimer = $timeout(_scan, 800);
|
||||
};
|
||||
|
||||
var _scanStop = function() {
|
||||
$timeout.cancel(scanTimer);
|
||||
if (localMediaStream && localMediaStream.active) {
|
||||
var localMediaStreamTrack = localMediaStream.getTracks();
|
||||
for (var i = 0; i < localMediaStreamTrack.length; i++) {
|
||||
localMediaStreamTrack[i].stop();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
localMediaStream.stop();
|
||||
} catch (e) {
|
||||
// Older Chromium not support the STOP function
|
||||
};
|
||||
}
|
||||
localMediaStream = null;
|
||||
if (video && video.src) video.src = '';
|
||||
};
|
||||
|
||||
qrcode.callback = function(data) {
|
||||
if (prevResult != data) {
|
||||
prevResult = data;
|
||||
return;
|
||||
}
|
||||
// Check if the current page is tabs.scan
|
||||
_scanStop();
|
||||
if ($state.is('tabs.scan')) {
|
||||
_dataScanned(data);
|
||||
return;
|
||||
}
|
||||
$scope.cancel();
|
||||
};
|
||||
|
||||
var _successCallback = function(stream) {
|
||||
video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
|
||||
localMediaStream = stream;
|
||||
video.play();
|
||||
$timeout(_scan, 1000);
|
||||
};
|
||||
|
||||
var _videoError = function(err) {
|
||||
$scope.cancel();
|
||||
};
|
||||
|
||||
var setScanner = function() {
|
||||
navigator.getUserMedia = navigator.getUserMedia ||
|
||||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
|
||||
navigator.msGetUserMedia;
|
||||
window.URL = window.URL || window.webkitURL ||
|
||||
window.mozURL || window.msURL;
|
||||
};
|
||||
|
||||
$scope.init = function() {
|
||||
if (isCordova) {
|
||||
$scope.cordovaOpenScanner();
|
||||
return;
|
||||
}
|
||||
setScanner();
|
||||
$timeout(function() {
|
||||
if ($scope.beforeScan) {
|
||||
$scope.beforeScan();
|
||||
}
|
||||
canvas = document.getElementById('qr-canvas');
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
video = document.getElementById('qrcode-scanner-video');
|
||||
$video = angular.element(video);
|
||||
canvas.width = 300;
|
||||
canvas.height = 225;
|
||||
context.clearRect(0, 0, 300, 225);
|
||||
|
||||
navigator.getUserMedia({
|
||||
video: true
|
||||
}, _successCallback, _videoError);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
_scanStop();
|
||||
$scope.scannerModal.hide();
|
||||
$scope.scannerModal.remove();
|
||||
};
|
||||
|
||||
$scope.$on("$destroy", function(){
|
||||
_scanStop();
|
||||
});
|
||||
|
||||
});
|
|
@ -1,28 +0,0 @@
|
|||
<nav ng-controller="topbarController as topbar"
|
||||
class="tab-bar" ng-style="{'background-color': noColor ? '#4B6178' : index.backgroundColor}">
|
||||
<section class="left-small">
|
||||
<a id="hamburger" class="p10" ng-show="!goBackToState && !closeToHome && !index.noFocusedWallet && index.physicalScreenWidth < 768"
|
||||
on-tap="index.toggleLeftMenu()"><i class="fi-list size-24"></i>
|
||||
</a>
|
||||
<a ng-show="goBackToState" ng-click="$root.go(goBackToState); goBackToState = null"><i class="icon-arrow-left3 icon-back"></i>
|
||||
<span class="text-back" translate>Back</span>
|
||||
</a>
|
||||
|
||||
<a ng-show="closeToHome" class="p10 "
|
||||
ng-click="topbar.goHome(); index.setCompactTxHistory(); closeToHome = null">
|
||||
<span class="text-close" translate>Close</span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="right-small" ng-show="showPreferences && !index.noFocusedWallet">
|
||||
<a class="p10" ng-click="topbar.goPreferences(); index.setCompactTxHistory()">
|
||||
<i class="fi-widget size-24"></i>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="middle tab-bar-section">
|
||||
<h1 class="title ellipsis">
|
||||
{{(titleSection|translate) || (index.alias || index.walletName)}}
|
||||
</h1>
|
||||
</section>
|
||||
</nav>
|
|
@ -1,13 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('topbarController', function(go) {
|
||||
|
||||
this.goHome = function() {
|
||||
go.walletHome();
|
||||
};
|
||||
|
||||
this.goPreferences = function() {
|
||||
go.preferences();
|
||||
};
|
||||
|
||||
});
|
11
old/uri.html
11
old/uri.html
|
@ -1,11 +0,0 @@
|
|||
|
||||
<div class="row columns p20" ng-controller="uriController">
|
||||
<div class="text-center">
|
||||
<logo width="146"></logo>
|
||||
<div class="text-white" ng-include="'views/includes/version.html'"></div>
|
||||
</div>
|
||||
<h3 class="text-center" translate>
|
||||
Please wait to be redirected...
|
||||
</h3>
|
||||
</div>
|
||||
|
12
old/uri.js
12
old/uri.js
|
@ -1,12 +0,0 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.controllers').controller('uriController',
|
||||
function($stateParams, $log, openURLService) {
|
||||
|
||||
|
||||
/* This is only for BROWSER links, it is not excecuted on mobile devices */
|
||||
|
||||
$log.info('DEEP LINK from Browser:' + $stateParams.url);
|
||||
openURLService.handleURL({
|
||||
url: $stateParams.url
|
||||
});
|
||||
});
|
|
@ -1,534 +0,0 @@
|
|||
|
||||
<div class="topbar-container"
|
||||
ng-include="'views/includes/topbar.html'"
|
||||
ng-init="showPreferences = true" ng-show="!index.noFocusedWallet">
|
||||
</div>
|
||||
|
||||
<div ng-controller="walletHomeController as home">
|
||||
<div class="row columns m30tp" ng-show="index.noFocusedWallet">
|
||||
<div class="text-center size-12 text-warning m20b">
|
||||
<i class="fi-alert"></i> <span translate>You do not have any wallet</span>
|
||||
</div>
|
||||
<button class="button black round expand" href ui-sref="add" translate>Create</button>
|
||||
</div>
|
||||
|
||||
<div class="onGoingProcess" ng-show="index.updating">
|
||||
<div class="onGoingProcess-content" ng-style="{'background-color':index.backgroundColor}">
|
||||
<div class="spinner">
|
||||
<div class="rect1"></div>
|
||||
<div class="rect2"></div>
|
||||
<div class="rect3"></div>
|
||||
<div class="rect4"></div>
|
||||
<div class="rect5"></div>
|
||||
</div>
|
||||
<span translate>Updating Wallet...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oh" ng-show="!index.noFocusedWallet">
|
||||
|
||||
<!--
|
||||
|
||||
WalletHome
|
||||
|
||||
-->
|
||||
|
||||
<div id="walletHome" class="walletHome tab-view tab-in">
|
||||
<ion-content on-release="index.allowPullToRefresh = true;"
|
||||
on-drag-right="index.allowRefresher()" delegate-handle="my-handle" overflow-scroll="true">
|
||||
<ion-refresher
|
||||
ng-if="index.allowPullToRefresh && index.isCordova"
|
||||
pulling-icon="ion-ios-refresh"
|
||||
spinner="ios-small"
|
||||
on-refresh="index.updateAll({triggerTxUpdate: true})">
|
||||
</ion-refresher>
|
||||
<div class="oh pr">
|
||||
<div ng-style="{'background-color':index.backgroundColor}" class="amount">
|
||||
<div ng-if="!index.notAuthorized && !index.updating">
|
||||
<div class="m15t" ng-show="index.updateError" ng-click='index.updateAll({triggerTxUpdate: true})'>
|
||||
<span class="size-12 db m10b">{{index.updateError|translate}}</span>
|
||||
<button class="outline white tiny round" translate>Tap to retry</button>
|
||||
</div>
|
||||
|
||||
<div ng-show="index.walletScanStatus == 'error'" ng-click='index.retryScan()'>
|
||||
<span translate>Scan status finished with error</span>
|
||||
<br><span translate>Tap to retry</span>
|
||||
</div>
|
||||
|
||||
<div ng-click='index.updateAll({triggerTxUpdate: true})' ng-show="!index.updateError && index.walletScanStatus != 'error' && !index.shouldHideBalance" on-hold="index.onHold()">
|
||||
<strong class="size-36">{{index.totalBalanceStr}}</strong>
|
||||
<div class="size-14" ng-if="index.totalBalanceAlternative">{{index.totalBalanceAlternative}} {{index.alternativeIsoCode}}</div>
|
||||
<div class="size-14" ng-if="index.pendingAmount">
|
||||
<span translate>Pending Confirmation</span>: {{index.pendingAmountStr}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="!index.updateError && index.walletScanStatus != 'error' && index.shouldHideBalance" on-hold="index.onHold()">
|
||||
<strong class="size-24" translate>[Balance Hidden]</strong>
|
||||
<div class="size-14" translate>
|
||||
Tap and hold to show
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="index.updating">
|
||||
<div class="size-36">
|
||||
<strong>...</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- amount -->
|
||||
|
||||
<div class="wallet-info">
|
||||
<span ng-include="'views/includes/walletInfo.html'"></span>
|
||||
</div>
|
||||
<div class="camera-icon" ng-show="index.isComplete">
|
||||
<qr-scanner on-scan="home.onQrCodeScanned(data)"></qr-scanner>
|
||||
</div>
|
||||
</div> <!-- oh -->
|
||||
|
||||
<div class="p60b">
|
||||
<div class="oh pr m20t" ng-show="index.incorrectDerivation">
|
||||
<div class="text-center text-warning">
|
||||
<i class="fi-alert"></i>
|
||||
<span translate>
|
||||
WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh pr m20t" ng-show="index.notAuthorized && !index.updating">
|
||||
<div class="text-center text-warning">
|
||||
<i class="fi-alert"></i>
|
||||
<span translate>
|
||||
WARNING: Wallet not registered
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-center text-gray m15r m15l" translate>
|
||||
This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.
|
||||
</div>
|
||||
<div class="text-center m10t ">
|
||||
<span class="button outline round dark-gray tiny"
|
||||
ng-click="index.recreate()">
|
||||
<span translate>Recreate</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="release size-12" ng-show="newRelease" ng-click="$root.openExternalLink('https://github.com/bitpay/copay/releases/latest')">
|
||||
<span>{{newRelease}}</span><i class="icon-arrow-right3 right size-18"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="index.txps[0]">
|
||||
<h4 ng-show="index.requiresMultipleSignatures" class="title m0" translate>Payment Proposals</h4>
|
||||
<h4 ng-show="!index.requiresMultipleSignatures" class="title m0" translate>Unsent transactions</h4>
|
||||
<div ng-repeat="tx in index.txps">
|
||||
<div ng-include="index.txTemplateUrl"></div>
|
||||
</div>
|
||||
|
||||
<div class="text-gray text-center size-12 p10t"
|
||||
ng-show="index.lockedBalanceSat">
|
||||
<span translate>Total Locked Balance</span>:
|
||||
<b>{{index.lockedBalanceStr}} </b>
|
||||
<span> {{index.lockedBalanceAlternative}}
|
||||
{{index.alternativeIsoCode}} </span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity -->
|
||||
|
||||
<h4 class="title" ng-click="index.startSearch(); openSearchModal()" ng-show="!index.notAuthorized">
|
||||
<span translate>Activity</span>
|
||||
<i class="dib m5l size-16 pointer fi-magnifying-glass"></i>
|
||||
</h4>
|
||||
|
||||
<div class="oh pr m20t text-gray size-12 text-center"
|
||||
ng-show="!index.loadingWallet && !index.txHistory[0] && !index.updatingTxHistory && !index.txHistoryError && !index.updateError && !index.notAuthorized"
|
||||
translate>No transactions yet
|
||||
</div>
|
||||
|
||||
<div class="oh pr" ng-show="(index.txHistory[0] || index.txProgress > 5) && !index.notAuthorized">
|
||||
|
||||
<div ng-show="index.updatingTxHistory && index.txProgress > 5">
|
||||
<div class="row p20 text-center">
|
||||
<div class="columns large-12 medium-12 small-12 m10b">
|
||||
<ion-spinner class="spinner-dark" icon="lines"></ion-spinner>
|
||||
</div>
|
||||
<div class="size-12 text-gray m20t">
|
||||
<div translate>{{index.txProgress}} transactions downloaded</div>
|
||||
<div translate>Updating transaction history. Please stand by.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="index.txHistory[0] && index.updatingTxHistory && index.newTx" class="row collapse last-transactions-content animated fadeInDown">
|
||||
<div class="large-6 medium-6 small-6 columns size-14">
|
||||
<div class="m10r left">
|
||||
<img src="img/icon-new.svg" width="40">
|
||||
</div>
|
||||
<div class="m10t" style="background:#eee; width: 8em; margin-left: 52px; line-height:0.6em">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div style="margin-top:5px; background:#eee; width: 6em; margin-left: 52px; line-height:0.6em">
|
||||
<span> </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="btx in index.txHistory track by btx.txid"
|
||||
ng-click="home.openTxModal(btx)"
|
||||
class="row collapse last-transactions-content">
|
||||
<div class="large-6 medium-6 small-6 columns size-14">
|
||||
<div class="m10r left">
|
||||
<img src="img/icon-receive-history.svg" alt="sync" width="40" ng-show="btx.action == 'received'">
|
||||
<img src="img/icon-sent-history.svg" alt="sync" width="40" ng-show="btx.action == 'sent'">
|
||||
<img src="img/icon-moved.svg" alt="sync" width="40" ng-show="btx.action == 'moved'">
|
||||
</div>
|
||||
<div class="m10t">
|
||||
<span ng-show="btx.action == 'received'">
|
||||
<span class="ellipsis">
|
||||
<span ng-if="btx.note.body">{{btx.note.body}}</span>
|
||||
<span ng-if="!btx.note.body" translate> Received</span>
|
||||
</span>
|
||||
</span>
|
||||
<span ng-show="btx.action == 'sent'">
|
||||
<span class="ellipsis">
|
||||
<span ng-if="btx.message">{{btx.message}}</span>
|
||||
<span ng-if="!btx.message && btx.note.body">{{btx.note.body}}</span>
|
||||
<span ng-if="!btx.message && !btx.note.body && index.addressbook[btx.addressTo]">{{index.addressbook[btx.addressTo]}}</span>
|
||||
<span ng-if="!btx.message && !btx.note.body && !index.addressbook[btx.addressTo]" translate> Sent</span>
|
||||
</span>
|
||||
</span>
|
||||
<span ng-show="btx.action == 'moved'">
|
||||
<span class="ellipsis">
|
||||
<span ng-if="btx.note.body">{{btx.note.body}}</span>
|
||||
<span ng-if="!btx.note.body" translate>Moved</span>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<span class="label tu warning radius" ng-show="btx.action == 'invalid'" translate>Invalid</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="large-5 medium-5 small-5 columns text-right" >
|
||||
<span class="size-16" ng-class="{'text-bold': btx.recent}">
|
||||
<span ng-if="btx.action == 'received'">+</span>
|
||||
<span ng-if="btx.action == 'sent'">-</span>
|
||||
<span class="size-12" ng-if="btx.action == 'invalid'" translate>
|
||||
(possible double spend)
|
||||
</span>
|
||||
<span ng-if="btx.action != 'invalid'">
|
||||
{{btx.amountStr}}
|
||||
</span>
|
||||
</span>
|
||||
<div class="size-12 text-gray">
|
||||
<time ng-if="btx.time">{{btx.time * 1000 | amTimeAgo}}</time>
|
||||
<span translate class="text-warning"
|
||||
ng-show="!btx.time && (!btx.confirmations || btx.confirmations == 0)">
|
||||
Unconfirmed
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="large-1 medium-1 small-1 columns text-right m10t">
|
||||
<i class="icon-arrow-right3 size-18"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m20t text-center" ng-show="index.historyRendering && !index.ching">
|
||||
<div class="columns large-12 medium-12 small-12">
|
||||
<ion-spinner class="spinner-stable" icon="lines"></ion-spinner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ion-infinite-scroll
|
||||
ng-if="index.historyShowMore"
|
||||
on-infinite="index.showMore()"
|
||||
distance="1%">
|
||||
</ion-infinite-scroll>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ion-content>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div> <!-- END WalletHome -->
|
||||
|
||||
<!--
|
||||
|
||||
receive
|
||||
|
||||
-->
|
||||
<div id="receive" class="receive tab-view">
|
||||
|
||||
<div ng-show="index.needsBackup" class="p60t columns text-center">
|
||||
<div class="circle-icon">
|
||||
<i class="fi-alert size-48"></i>
|
||||
</div>
|
||||
<h5 translate>Backup Needed</h5>
|
||||
<p class="text-gray m20b columns" translate>
|
||||
Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.
|
||||
</p>
|
||||
<button class="m20t button black expand round" href ui-sref="backup" ng-style="{'background-color':index.backgroundColor}" >
|
||||
<span translate>Backup now</span>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-show="!index.needsBackup">
|
||||
<div class="box-notification m20t" ng-show="home.addrError">
|
||||
<span class="text-warning">
|
||||
{{home.addrError|translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- Address-->
|
||||
<div class="large-12 columns">
|
||||
<h2 class="text-center m10t" translate>My Bitcoin address</h2>
|
||||
<div class="text-center" ng-click="home.copyToClipboard(home.addr, $event)" ng-show="home.addr || home.generatingAddress">
|
||||
<qrcode size="220" data="bitcoin:{{home.addr}}"></qrcode>
|
||||
<div ng-show="home.generatingAddress" style="position:relative; top:-226px; height:0px">
|
||||
<div style="height:220px; width:220px; margin:auto; background: white">
|
||||
<ion-spinner class="spinner-stable" icon="lines" style="margin-top: 85px"></ion-spinner>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m10t" >
|
||||
<h4 ng-class="{'enable_text_select': !index.isCordova}" class="size-12">
|
||||
{{home.generatingAddress ? '...' : home.addr}}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m20t">
|
||||
<div class="small-12 columns" ng-show="index.isCordova && home.addr">
|
||||
<button class="button outline light-gray small round expand"
|
||||
on-tap="home.shareAddress(home.addr)"
|
||||
ng-disabled="home.generatingAddress">
|
||||
<span translate>Share address</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="small-12 columns" ng-show="home.addr">
|
||||
<button class="button expand small round m10b" ng-click="openAmountModal(home.addr)"
|
||||
ng-style="{'background-color':index.backgroundColor}"
|
||||
ng-disabled="home.generatingAddress">
|
||||
<span translate>Request a specific amount</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m10t" ng-show="home.addr">
|
||||
<div class="large-12 columns">
|
||||
<div class="line-t size-10 text-gray m10b p10t" ng-show="!index.isSingleAddress">
|
||||
<span translate> Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.</span>
|
||||
<a ng-show="!home.generatingAddress" ng-click="home.setAddress(true)" translate>Generate new address</a>
|
||||
</div>
|
||||
<div class="line-t size-10 text-gray m10b p10t" ng-show="index.isSingleAddress">
|
||||
<span translate> Share this wallet address to receive payments</span>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div> <!-- END Receive -->
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
send
|
||||
|
||||
-->
|
||||
<div id="send" class="send tab-view">
|
||||
<div class="pr p25b">
|
||||
<h4 class="title m0" ng-show="!index.updating">
|
||||
<available-balance ng-show="!index.shouldHideBalance"></available-balance>
|
||||
<span
|
||||
ng-show="home.lockedCurrentFeePerKb || home.lockAmount"
|
||||
class="text-gray" translate>Send Max</span>
|
||||
<a
|
||||
ng-show="index.availableBalanceSat > 0 && !home.lockedCurrentFeePerKb && !home.lockAmount"
|
||||
ng-click="home.sendMax(index.availableBalanceSat)"
|
||||
translate>Send Max
|
||||
</a>
|
||||
<div ng-show="!home.paymentExpired && home._paypro">
|
||||
<span translate>Payment expires</span>
|
||||
<time> {{home.remainingTimeStr}}</time>
|
||||
</div>
|
||||
</h4>
|
||||
<div class="camera-icon" ng-show="index.isComplete">
|
||||
<qr-scanner on-scan="home.onQrCodeScanned(data)"></qr-scanner>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-notification m20t" ng-show="home.error" ng-click="home.resetError()">
|
||||
<span class="text-warning">
|
||||
{{home.error|translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="row m20t">
|
||||
<div class="large-12 large-centered columns">
|
||||
<form name="sendForm" novalidate>
|
||||
|
||||
<div ng-hide="home._paypro">
|
||||
<div class="row collapse">
|
||||
<label for="address" class="left" >
|
||||
<span translate>To</span>
|
||||
</label>
|
||||
<span ng-hide="sendForm.address.$pristine">
|
||||
<span class="has-error right size-12" ng-show="sendForm.address.$invalid && _address">
|
||||
<i class="icon-close-circle size-14"></i>
|
||||
<span class="vm" translate>Not valid</span>
|
||||
</span>
|
||||
<small class="right text-primary" ng-show="!sendForm.address.$invalid">
|
||||
<i class="icon-checkmark-circle size-14"></i>
|
||||
</small>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<input ng-show="sendForm.address.$invalid" class="m0" type="text" id="address" name="address" ng-disabled=" home.lockAddress" ng-attr-placeholder="{{'Bitcoin address'|translate}}" ng-model="_address" valid-address required ng-focus="home.formFocus('address')" ng-blur="home.formFocus(false)">
|
||||
<div class="addressbook-input" ng-show="!sendForm.address.$invalid && _address">
|
||||
{{index.addressbook[_address] || _address}}
|
||||
</div>
|
||||
<a class="postfix size-12 m0 text-gray"
|
||||
ng-style="{'color':index.backgroundColor}"
|
||||
ng-click="home.openAddressbookModal(index.otherWallets, _address)">
|
||||
<i class="icon-wallet text-bold size-18"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="home._paypro">
|
||||
<div class="row collapse" ng-click="home.openPPModal(home._paypro)">
|
||||
|
||||
<label for="domain">
|
||||
<span translate>Payment to</span>
|
||||
</label>
|
||||
|
||||
<div class="input block">
|
||||
<input class="p45li" type="text" id="domain" name="domain" ng-model="home._paypro.domain" ng-disabled="1">
|
||||
<i ng-show="home._paypro.verified && home._paypro.caTrusted" class="fi-lock color-greeni"></i>
|
||||
<i ng-show="!home._paypro.caTrusted" class="fi-unlock color-yellowi"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-12 medium-12 columns">
|
||||
<div class="right" ng-hide="sendForm.amount.$pristine && !sendForm.amount.$modelValue ">
|
||||
<span class="has-error right size-12" ng-show="sendForm.amount.$invalid">
|
||||
<i class="icon-close-circle size-14"></i>
|
||||
<span clas="vm" translate>Not valid</span>
|
||||
</span>
|
||||
<small class="text-primary right" ng-show="!sendForm.amount.$invalid && !sendForm.alternative.$invalid">
|
||||
<i class="icon-checkmark-circle size-14"></i>
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<label for="amount">
|
||||
<span translate>Amount</span><span ng-show="showAlternative"> [{{home.alternativeIsoCode}}]</span>
|
||||
</label>
|
||||
<div class="input">
|
||||
<div ng-if="index.isCordova">
|
||||
<input
|
||||
type="number"
|
||||
ng-readonly="!home.lockAmount"
|
||||
ng-show="!showAlternative"
|
||||
id="amount"
|
||||
ng-disabled="home.lockAmount"
|
||||
name="amount"
|
||||
ng-attr-placeholder="{{'Amount in'|translate}} {{home.unitName}}"
|
||||
ng-model="_amount"
|
||||
valid-amount
|
||||
required
|
||||
autocomplete="off"
|
||||
ng-click="openInputAmountModal()"
|
||||
ignore-mouse-wheel>
|
||||
<input
|
||||
type="number"
|
||||
ng-readonly="!home.lockAmount"
|
||||
ng-show="showAlternative"
|
||||
id="alternative"
|
||||
ng-disabled="!home.isRateAvailable || home.lockAmount"
|
||||
name="alternative"
|
||||
ng-attr-placeholder="{{'Amount in'|translate}} {{ home.alternativeName }}"
|
||||
ng-model="_alternative"
|
||||
required
|
||||
autocomplete="off"
|
||||
ng-click="openInputAmountModal()"
|
||||
ignore-mouse-wheel>
|
||||
</div>
|
||||
<div ng-if="!index.isCordova">
|
||||
<input
|
||||
type="number"
|
||||
ng-show="!showAlternative"
|
||||
id="amount"
|
||||
ng-disabled="home.lockAmount"
|
||||
name="amount"
|
||||
ng-attr-placeholder="{{'Amount in'|translate}} {{home.unitName}}"
|
||||
ng-model="_amount"
|
||||
valid-amount
|
||||
required
|
||||
autocomplete="off"
|
||||
ignore-mouse-wheel>
|
||||
<input
|
||||
type="number"
|
||||
ng-show="showAlternative"
|
||||
id="alternative"
|
||||
ng-disabled="!home.isRateAvailable || home.lockAmount"
|
||||
name="alternative"
|
||||
ng-attr-placeholder="{{'Amount in'|translate}} {{ home.alternativeName }}"
|
||||
ng-model="_alternative"
|
||||
required
|
||||
autocomplete="off"
|
||||
ignore-mouse-wheel>
|
||||
</div>
|
||||
<a class="postfix button" ng-show="!showAlternative" ng-style="{'background-color':index.backgroundColor}" ng-click="showAlternative = !showAlternative">{{home.unitName}}</a>
|
||||
<a class="postfix button black" ng-show="showAlternative" ng-click="showAlternative = !showAlternative">{{home.alternativeIsoCode}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" ng-hide="home.hideNote">
|
||||
<div class="large-12 columns">
|
||||
<label for="comment"><span translate>Description</span>
|
||||
<small translate ng-hide="!sendForm.comment.$pristine">optional</small>
|
||||
<small translate class="has-error" ng-show="sendForm.comment.$invalid && !sendForm.comment.$pristine">too long!</small>
|
||||
</label>
|
||||
<div class="input">
|
||||
<textarea id="comment" name="comment"
|
||||
ng-maxlength="500" ng-model="_comment" ng-focus="home.formFocus('msg')"
|
||||
ng-blur="home.formFocus(false)"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="large-6 medium-6 small-6 columns" ng-show="(home._paypro || home.lockAddress ||
|
||||
home.lockAmount || !sendForm.amount.$pristine)">
|
||||
<a ng-click="home.resetForm(sendForm)" class="button expand outline dark-gray round" translate>Cancel</a>
|
||||
</div>
|
||||
<div class="columns" ng-class="{'small-6 medium-6 large-6':(home._paypro || home.lockAddress ||
|
||||
home.lockAmount || !sendForm.amount.$pristine)}">
|
||||
<button class="button black round expand" ng-disabled="sendForm.$invalid || home.paymentExpired || index.updating"
|
||||
ng-style="{'background-color':index.backgroundColor}" ng-click="home.submitForm()" translate>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
</div> <!-- END Send -->
|
||||
|
||||
<div id="{{view.id}}" class="{{view.class}} tab-view" ng-repeat="view in index.addonViews" ng-include="view.template">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra-margin-bottom"></div>
|
||||
<div class="bottom-bar row collapse p0i">
|
||||
<div>
|
||||
<div class="row collapse p0i">
|
||||
<div class="medium-4 small-4 columns text-center bottombar-item">
|
||||
<a href="#/tabs/home" >
|
||||
<span class="size-10 tu">
|
||||
tabs
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,944 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, notification, txStatus, profileService, lodash, configService, rateService, storageService, bitcore, gettext, gettextCatalog, platformInfo, addressService, ledger, bwcError, confirmDialog, txFormatService, addressbookService, go, feeService, walletService, fingerprintService, nodeWebkit, ongoingProcess) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var isAndroid = platformInfo.isAndroid;
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
|
||||
var self = this;
|
||||
$rootScope.shouldHideMenuBar = false;
|
||||
$rootScope.wpInputFocused = false;
|
||||
var config = configService.getSync();
|
||||
var configWallet = config.wallet;
|
||||
var walletSettings = configWallet.settings;
|
||||
var ret = {};
|
||||
|
||||
// INIT. Global value
|
||||
ret.unitToSatoshi = walletSettings.unitToSatoshi;
|
||||
ret.satToUnit = 1 / ret.unitToSatoshi;
|
||||
ret.unitName = walletSettings.unitName;
|
||||
ret.alternativeIsoCode = walletSettings.alternativeIsoCode;
|
||||
ret.alternativeName = walletSettings.alternativeName;
|
||||
ret.alternativeAmount = 0;
|
||||
ret.unitDecimals = walletSettings.unitDecimals;
|
||||
ret.isCordova = isCordova;
|
||||
ret.addresses = [];
|
||||
ret.isMobile = platformInfo.isMobile;
|
||||
ret.isWindowsPhoneApp = platformInfo.isWP;
|
||||
ret.countDown = null;
|
||||
ret.sendMaxInfo = {};
|
||||
ret.showAlternative = false;
|
||||
ret.fromInputAmount = null;
|
||||
var vanillaScope = ret;
|
||||
|
||||
var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) {
|
||||
if (!data) return;
|
||||
|
||||
self.setForm(data);
|
||||
$rootScope.$emit('Local/SetTab', 'send');
|
||||
var form = $scope.sendForm;
|
||||
if (form.address.$invalid && !ongoingProcess.get('fetchingPayPro')) {
|
||||
self.resetForm();
|
||||
self.error = gettext('Could not recognize a valid Bitcoin QR Code');
|
||||
}
|
||||
});
|
||||
|
||||
var disablePaymentUriListener = $rootScope.$on('paymentUri', function(event, uri) {
|
||||
$rootScope.$emit('Local/SetTab', 'send');
|
||||
$timeout(function() {
|
||||
self.setForm(uri);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
var disableAddrListener = $rootScope.$on('Local/AddressIsUsed', function() {
|
||||
self.setAddress(true);
|
||||
});
|
||||
|
||||
var disableFocusListener = $rootScope.$on('Local/NewFocusedWalletReady', function() {
|
||||
self.addr = null;
|
||||
self.resetForm();
|
||||
$scope.search = '';
|
||||
|
||||
if (profileService.focusedClient && profileService.focusedClient.isComplete()) {
|
||||
self.setAddress();
|
||||
self.setSendFormInputs();
|
||||
}
|
||||
|
||||
$log.debug('Cleaning WalletHome Instance');
|
||||
lodash.each(self, function(v, k) {
|
||||
if (lodash.isFunction(v)) return;
|
||||
if (!lodash.isUndefined(vanillaScope[k])) {
|
||||
self[k] = vanillaScope[k];
|
||||
return;
|
||||
}
|
||||
if (k == 'isRateAvailable') return;
|
||||
|
||||
delete self[k];
|
||||
});
|
||||
});
|
||||
|
||||
var disableResumeListener = $rootScope.$on('Local/Resume', function() {
|
||||
// This is needed then the apps go to sleep
|
||||
self.bindTouchDown();
|
||||
});
|
||||
|
||||
var disableTabListener = $rootScope.$on('Local/TabChanged', function(e, tab) {
|
||||
// This will slow down switch, do not add things here!
|
||||
switch (tab) {
|
||||
case 'receive':
|
||||
// just to be sure we have an address
|
||||
self.setAddress();
|
||||
break;
|
||||
case 'send':
|
||||
self.resetError();
|
||||
};
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
disableAddrListener();
|
||||
disableScannerListener();
|
||||
disablePaymentUriListener();
|
||||
disableTabListener();
|
||||
disableFocusListener();
|
||||
disableResumeListener();
|
||||
$rootScope.shouldHideMenuBar = false;
|
||||
});
|
||||
|
||||
if (isCordova && StatusBar.isVisible) {
|
||||
var backgroundColor = profileService.focusedClient ? profileService.focusedClient.backgroundColor : "#4B6178";
|
||||
StatusBar.backgroundColorByHexString(backgroundColor);
|
||||
}
|
||||
|
||||
this.onQrCodeScanned = function(data) {
|
||||
if (data) go.send();
|
||||
$rootScope.$emit('dataScanned', data);
|
||||
};
|
||||
|
||||
rateService.whenAvailable(function() {
|
||||
self.isRateAvailable = true;
|
||||
$rootScope.$digest();
|
||||
});
|
||||
|
||||
var getClipboard = function(cb) {
|
||||
if (!isCordova || platformInfo.isWP) return cb();
|
||||
|
||||
window.cordova.plugins.clipboard.paste(function(value) {
|
||||
var fc = profileService.focusedClient;
|
||||
var Address = bitcore.Address;
|
||||
var networkName = fc.credentials.network;
|
||||
if (Address.isValid(value, networkName) && !$scope.newAddress) {
|
||||
return cb(value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var handleEncryptedWallet = function(client, cb) {
|
||||
if (!walletService.isEncrypted(client)) return cb();
|
||||
$rootScope.$emit('Local/NeedsPassword', false, function(err, password) {
|
||||
if (err) return cb(err);
|
||||
return cb(walletService.unlock(client, password));
|
||||
});
|
||||
};
|
||||
|
||||
var accept_msg = gettextCatalog.getString('Accept');
|
||||
var cancel_msg = gettextCatalog.getString('Cancel');
|
||||
var confirm_msg = gettextCatalog.getString('Confirm');
|
||||
|
||||
this.openAddressbookModal = function(wallets, address) {
|
||||
$scope.wallets = wallets;
|
||||
$scope.address = address;
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/addressbook.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.addressbookModal = modal;
|
||||
$scope.addressbookModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
var GLIDERA_LOCK_TIME = 6 * 60 * 60;
|
||||
// isGlidera flag is a security measure so glidera status is not
|
||||
// only determined by the tx.message
|
||||
this.openTxpModal = function(tx, copayers, isGlidera) {
|
||||
$scope.self = self;
|
||||
$scope.tx = tx;
|
||||
$scope.copayers = copayers;
|
||||
$scope.isGlidera = isGlidera;
|
||||
$scope.error = null;
|
||||
$scope.loading = null;
|
||||
$scope.paymentExpired = null;
|
||||
$scope.currentSpendUnconfirmed = configWallet.spendUnconfirmed;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/txp-details.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.txpDetailsModal = modal;
|
||||
$scope.txpDetailsModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
this.setAddress = function(forceNew) {
|
||||
self.addrError = null;
|
||||
var client = profileService.focusedClient;
|
||||
if (!client || !client.isComplete()) return;
|
||||
|
||||
// Address already set?
|
||||
if (!forceNew && self.addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.generatingAddress = true;
|
||||
$timeout(function() {
|
||||
addressService.getAddress(client.credentials.walletId, forceNew, function(err, addr) {
|
||||
self.generatingAddress = false;
|
||||
|
||||
if (err) {
|
||||
self.addrError = err;
|
||||
} else {
|
||||
if (addr)
|
||||
self.addr = addr;
|
||||
}
|
||||
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.copyToClipboard = function(addr, $event) {
|
||||
|
||||
var showPopover = function() {
|
||||
|
||||
$ionicPopover.fromTemplateUrl('views/includes/copyToClipboard.html', {
|
||||
scope: $scope
|
||||
}).then(function(popover) {
|
||||
$scope.popover = popover;
|
||||
$scope.popover.show($event);
|
||||
});
|
||||
|
||||
$scope.close = function() {
|
||||
$scope.popover.hide();
|
||||
}
|
||||
|
||||
$timeout(function() {
|
||||
$scope.popover.hide(); //close the popover after 0.7 seconds
|
||||
}, 700);
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
$scope.popover.remove();
|
||||
});
|
||||
};
|
||||
|
||||
if (isCordova) {
|
||||
window.cordova.plugins.clipboard.copy(addr);
|
||||
window.plugins.toast.showShortCenter(gettextCatalog.getString('Copied to clipboard'));
|
||||
} else if (platformInfo.isNW) {
|
||||
nodeWebkit.writeToClipboard(addr);
|
||||
showPopover($event);
|
||||
}
|
||||
};
|
||||
|
||||
this.shareAddress = function(addr) {
|
||||
if (isCordova) {
|
||||
window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null);
|
||||
}
|
||||
};
|
||||
|
||||
// Send
|
||||
|
||||
this.resetError = function() {
|
||||
this.error = this.success = null;
|
||||
};
|
||||
|
||||
this.bindTouchDown = function(tries) {
|
||||
var self = this;
|
||||
tries = tries || 0;
|
||||
if (tries > 5) return;
|
||||
var e = document.getElementById('menu-walletHome');
|
||||
if (!e) return $timeout(function() {
|
||||
self.bindTouchDown(++tries);
|
||||
}, 500);
|
||||
|
||||
// on touchdown elements
|
||||
$log.debug('Binding touchstart elements...');
|
||||
['hamburger', 'menu-walletHome', 'menu-send', 'menu-receive'].forEach(function(id) {
|
||||
var e = document.getElementById(id);
|
||||
if (e) e.addEventListener('touchstart', function() {
|
||||
try {
|
||||
event.preventDefault();
|
||||
} catch (e) {};
|
||||
angular.element(e).triggerHandler('click');
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
this.hideMenuBar = lodash.debounce(function(hide) {
|
||||
if (hide) {
|
||||
$rootScope.shouldHideMenuBar = true;
|
||||
} else {
|
||||
$rootScope.shouldHideMenuBar = false;
|
||||
}
|
||||
$rootScope.$digest();
|
||||
}, 100);
|
||||
|
||||
this.formFocus = function(what) {
|
||||
if (isCordova && this.isWindowsPhoneApp) {
|
||||
this.hideMenuBar(what);
|
||||
}
|
||||
var self = this;
|
||||
if (isCordova && !this.isWindowsPhoneApp && what == 'address') {
|
||||
getClipboard(function(value) {
|
||||
if (value) {
|
||||
document.getElementById("amount").focus();
|
||||
$timeout(function() {
|
||||
window.plugins.toast.showShortCenter(gettextCatalog.getString('Pasted from clipboard'));
|
||||
self.setForm(value);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.setSendFormInputs = function() {
|
||||
var unitToSat = this.unitToSatoshi;
|
||||
var satToUnit = 1 / unitToSat;
|
||||
/**
|
||||
* Setting the two related amounts as properties prevents an infinite
|
||||
* recursion for watches while preserving the original angular updates
|
||||
*
|
||||
*/
|
||||
Object.defineProperty($scope,
|
||||
"_alternative", {
|
||||
get: function() {
|
||||
return $scope.__alternative;
|
||||
},
|
||||
set: function(newValue) {
|
||||
$scope.__alternative = newValue;
|
||||
if (self.isRateAvailable) {
|
||||
$scope._amount = parseFloat((rateService.fromFiat(newValue, self.alternativeIsoCode) * satToUnit).toFixed(self.unitDecimals), 10);
|
||||
} else {
|
||||
$scope.__amount = null;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty($scope,
|
||||
"_amount", {
|
||||
get: function() {
|
||||
return $scope.__amount;
|
||||
},
|
||||
set: function(newValue) {
|
||||
$scope.__amount = newValue;
|
||||
if (self.isRateAvailable) {
|
||||
$scope.__alternative = parseFloat((rateService.toFiat(newValue * self.unitToSatoshi, self.alternativeIsoCode)).toFixed(2), 10);
|
||||
} else {
|
||||
$scope.__alternative = null;
|
||||
}
|
||||
self.alternativeAmount = $scope.__alternative;
|
||||
self.resetError();
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
Object.defineProperty($scope,
|
||||
"_address", {
|
||||
get: function() {
|
||||
return $scope.__address;
|
||||
},
|
||||
set: function(newValue) {
|
||||
$scope.__address = self.onAddressChange(newValue);
|
||||
if ($scope.sendForm && $scope.sendForm.address.$valid) {
|
||||
self.lockAddress = true;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
var fc = profileService.focusedClient;
|
||||
// ToDo: use a credential's (or fc's) function for this
|
||||
this.hideNote = !fc.credentials.sharedEncryptingKey;
|
||||
};
|
||||
|
||||
this.setSendError = function(err) {
|
||||
var fc = profileService.focusedClient;
|
||||
var prefix =
|
||||
fc.credentials.m > 1 ? gettextCatalog.getString('Could not create payment proposal') : gettextCatalog.getString('Could not send payment');
|
||||
|
||||
this.error = bwcError.msg(err, prefix);
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
this.setAmount = function(amount, useAlternativeAmount) {
|
||||
$scope.showAlternative = useAlternativeAmount;
|
||||
|
||||
self.fromInputAmount = true;
|
||||
self.setForm(null, amount, null);
|
||||
};
|
||||
|
||||
this.submitForm = function() {
|
||||
if (!$scope._amount || !$scope._address) return;
|
||||
var client = profileService.focusedClient;
|
||||
var unitToSat = this.unitToSatoshi;
|
||||
var currentSpendUnconfirmed = configWallet.spendUnconfirmed;
|
||||
|
||||
var outputs = [];
|
||||
|
||||
this.resetError();
|
||||
|
||||
if (isCordova && this.isWindowsPhoneApp)
|
||||
$rootScope.shouldHideMenuBar = true;
|
||||
|
||||
var form = $scope.sendForm;
|
||||
var comment = form.comment.$modelValue;
|
||||
|
||||
// ToDo: use a credential's (or fc's) function for this
|
||||
if (comment && !client.credentials.sharedEncryptingKey) {
|
||||
var msg = 'Could not add message to imported wallet without shared encrypting key';
|
||||
$log.warn(msg);
|
||||
return self.setSendError(gettext(msg));
|
||||
}
|
||||
|
||||
if (form.amount.$modelValue * unitToSat > Number.MAX_SAFE_INTEGER) {
|
||||
var msg = 'Amount too big';
|
||||
$log.warn(msg);
|
||||
return self.setSendError(gettext(msg));
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
var paypro = self._paypro;
|
||||
var address, amount;
|
||||
|
||||
address = form.address.$modelValue;
|
||||
amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0));
|
||||
|
||||
outputs.push({
|
||||
'toAddress': address,
|
||||
'amount': amount,
|
||||
'message': comment
|
||||
});
|
||||
|
||||
var txp = {};
|
||||
|
||||
if (!lodash.isEmpty(self.sendMaxInfo)) {
|
||||
txp.sendMax = true;
|
||||
txp.inputs = self.sendMaxInfo.inputs;
|
||||
txp.fee = self.sendMaxInfo.fee;
|
||||
} else {
|
||||
txp.amount = amount;
|
||||
}
|
||||
|
||||
txp.toAddress = address;
|
||||
txp.outputs = outputs;
|
||||
txp.message = comment;
|
||||
txp.payProUrl = paypro ? paypro.url : null;
|
||||
txp.excludeUnconfirmedUtxos = configWallet.spendUnconfirmed ? false : true;
|
||||
txp.feeLevel = walletSettings.feeLevel || 'normal';
|
||||
|
||||
ongoingProcess.set('creatingTx', true);
|
||||
walletService.createTx(client, txp, function(err, createdTxp) {
|
||||
ongoingProcess.set('creatingTx', false);
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
|
||||
if (!client.canSign() && !client.isPrivKeyExternal()) {
|
||||
$log.info('No signing proposal: No private key');
|
||||
ongoingProcess.set('sendingTx', true);
|
||||
walletService.publishTx(client, createdTxp, function(err, publishedTxp) {
|
||||
ongoingProcess.set('sendingTx', false);
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
self.resetForm();
|
||||
go.walletHome();
|
||||
var type = txStatus.notify(createdTxp);
|
||||
$scope.openStatusModal(type, createdTxp, function() {
|
||||
return $scope.$emit('Local/TxProposalAction');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$rootScope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) {
|
||||
if (accept) self.confirmTx(createdTxp);
|
||||
else self.resetForm();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}, 100);
|
||||
};
|
||||
|
||||
this.confirmTx = function(txp) {
|
||||
var client = profileService.focusedClient;
|
||||
var self = this;
|
||||
|
||||
fingerprintService.check(client, function(err) {
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
|
||||
handleEncryptedWallet(client, function(err) {
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
|
||||
ongoingProcess.set('sendingTx', true);
|
||||
walletService.publishTx(client, txp, function(err, publishedTxp) {
|
||||
ongoingProcess.set('sendingTx', false);
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
|
||||
ongoingProcess.set('signingTx', true);
|
||||
walletService.signTx(client, publishedTxp, function(err, signedTxp) {
|
||||
ongoingProcess.set('signingTx', false);
|
||||
walletService.lock(client);
|
||||
if (err) {
|
||||
$scope.$emit('Local/TxProposalAction');
|
||||
return self.setSendError(
|
||||
err.message ?
|
||||
err.message :
|
||||
gettext('The payment was created but could not be completed. Please try again from home screen'));
|
||||
}
|
||||
|
||||
if (signedTxp.status == 'accepted') {
|
||||
ongoingProcess.set('broadcastingTx', true);
|
||||
walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) {
|
||||
ongoingProcess.set('broadcastingTx', false);
|
||||
if (err) {
|
||||
return self.setSendError(err);
|
||||
}
|
||||
self.resetForm();
|
||||
go.walletHome();
|
||||
var type = txStatus.notify(broadcastedTxp);
|
||||
$scope.openStatusModal(type, broadcastedTxp, function() {
|
||||
$scope.$emit('Local/TxProposalAction', broadcastedTxp.status == 'broadcasted');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
self.resetForm();
|
||||
go.walletHome();
|
||||
var type = txStatus.notify(signedTxp);
|
||||
$scope.openStatusModal(type, signedTxp, function() {
|
||||
$scope.$emit('Local/TxProposalAction');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openStatusModal = function(type, txp, cb) {
|
||||
var fc = profileService.focusedClient;
|
||||
$scope.type = type;
|
||||
$scope.tx = txFormatService.processTx(txp);
|
||||
$scope.color = fc.backgroundColor;
|
||||
$scope.cb = cb;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/tx-status.html', {
|
||||
scope: $scope,
|
||||
animation: 'slide-in-up'
|
||||
}).then(function(modal) {
|
||||
$scope.txStatusModal = modal;
|
||||
$scope.txStatusModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openSearchModal = function() {
|
||||
var fc = profileService.focusedClient;
|
||||
$scope.color = fc.backgroundColor;
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/search.html', {
|
||||
scope: $scope,
|
||||
focusFirstInput: true
|
||||
}).then(function(modal) {
|
||||
$scope.searchModal = modal;
|
||||
$scope.searchModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openCustomInputAmountModal = function(addr) {
|
||||
var fc = profileService.focusedClient;
|
||||
$scope.color = fc.backgroundColor;
|
||||
$scope.self = self;
|
||||
$scope.addr = addr;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/customAmount.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.customAmountModal = modal;
|
||||
$scope.customAmountModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openAmountModal = function(addr) {
|
||||
if (isCordova)
|
||||
$scope.openInputAmountModal(addr);
|
||||
else
|
||||
$scope.openCustomInputAmountModal(addr);
|
||||
};
|
||||
|
||||
$scope.openInputAmountModal = function(addr) {
|
||||
var fc = profileService.focusedClient;
|
||||
$scope.color = fc.backgroundColor;
|
||||
$scope.showAlternativeAmount = $scope.showAlternative || null;
|
||||
if ($scope.showAlternativeAmount) {
|
||||
$scope.amount = $scope.sendForm.alternative.$viewValue || null;
|
||||
} else {
|
||||
$scope.amount = $scope.sendForm.amount.$viewValue || null;
|
||||
}
|
||||
$scope.self = self;
|
||||
$scope.addr = addr;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/inputAmount.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.inputAmountModal = modal;
|
||||
$scope.inputAmountModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
this.setForm = function(to, amount, comment) {
|
||||
var form = $scope.sendForm;
|
||||
if (to) {
|
||||
form.address.$setViewValue(to);
|
||||
form.address.$isValid = true;
|
||||
form.address.$render();
|
||||
this.lockAddress = true;
|
||||
}
|
||||
|
||||
if (amount) {
|
||||
form.amount.$setViewValue("" + amount);
|
||||
form.amount.$isValid = true;
|
||||
form.amount.$render();
|
||||
if (!this.fromInputAmount)
|
||||
this.lockAmount = true;
|
||||
this.fromInputAmount = false;
|
||||
}
|
||||
|
||||
if (comment) {
|
||||
form.comment.$setViewValue(comment);
|
||||
form.comment.$isValid = true;
|
||||
form.comment.$render();
|
||||
}
|
||||
};
|
||||
|
||||
this.resetForm = function() {
|
||||
this.resetError();
|
||||
this.sendMaxInfo = {};
|
||||
if (this.countDown) $interval.cancel(this.countDown);
|
||||
this._paypro = null;
|
||||
|
||||
this.lockAddress = false;
|
||||
this.lockAmount = false;
|
||||
|
||||
this._amount = this._address = null;
|
||||
|
||||
var form = $scope.sendForm;
|
||||
|
||||
if (form && form.amount) {
|
||||
form.amount.$pristine = true;
|
||||
form.amount.$setViewValue('');
|
||||
form.amount.$render();
|
||||
|
||||
form.comment.$setViewValue('');
|
||||
form.comment.$render();
|
||||
form.$setPristine();
|
||||
|
||||
if (form.address) {
|
||||
form.address.$pristine = true;
|
||||
form.address.$setViewValue('');
|
||||
form.address.$render();
|
||||
}
|
||||
}
|
||||
$timeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
this.setFromPayPro = function(uri, cb) {
|
||||
if (!cb) cb = function() {};
|
||||
|
||||
var fc = profileService.focusedClient;
|
||||
if (isChromeApp) {
|
||||
this.error = gettext('Payment Protocol not supported on Chrome App');
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
var satToUnit = 1 / this.unitToSatoshi;
|
||||
var self = this;
|
||||
/// Get information of payment if using Payment Protocol
|
||||
ongoingProcess.set('fetchingPayPro', true);
|
||||
|
||||
$log.debug('Fetch PayPro Request...', uri);
|
||||
$timeout(function() {
|
||||
fc.fetchPayPro({
|
||||
payProUrl: uri,
|
||||
}, function(err, paypro) {
|
||||
ongoingProcess.set('fetchingPayPro', false);
|
||||
|
||||
if (err) {
|
||||
$log.warn('Could not fetch payment request:', err);
|
||||
self.resetForm();
|
||||
var msg = err.toString();
|
||||
if (msg.match('HTTP')) {
|
||||
msg = gettext('Could not fetch payment information');
|
||||
}
|
||||
self.error = msg;
|
||||
$timeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
if (!paypro.verified) {
|
||||
self.resetForm();
|
||||
$log.warn('Failed to verify payment protocol signatures');
|
||||
self.error = gettext('Payment Protocol Invalid');
|
||||
$timeout(function() {
|
||||
$rootScope.$digest();
|
||||
}, 1);
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
self._paypro = paypro;
|
||||
self.setForm(paypro.toAddress, (paypro.amount * satToUnit).toFixed(self.unitDecimals), paypro.memo);
|
||||
_paymentTimeControl(paypro.expires);
|
||||
return cb();
|
||||
});
|
||||
}, 1);
|
||||
};
|
||||
|
||||
function _paymentTimeControl(expirationTime) {
|
||||
self.paymentExpired = false;
|
||||
setExpirationTime();
|
||||
|
||||
self.countDown = $interval(function() {
|
||||
setExpirationTime();
|
||||
}, 1000);
|
||||
|
||||
function setExpirationTime() {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now > expirationTime) {
|
||||
setExpiredValues();
|
||||
return;
|
||||
}
|
||||
|
||||
var totalSecs = expirationTime - now;
|
||||
var m = Math.floor(totalSecs / 60);
|
||||
var s = totalSecs % 60;
|
||||
self.remainingTimeStr = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
|
||||
};
|
||||
|
||||
function setExpiredValues() {
|
||||
self.paymentExpired = true;
|
||||
self.remainingTimeStr = null;
|
||||
self._paypro = null;
|
||||
self.error = gettext('Cannot sign: The payment request has expired');
|
||||
if (self.countDown) $interval.cancel(self.countDown);
|
||||
};
|
||||
};
|
||||
|
||||
this.setFromUri = function(uri) {
|
||||
var self = this;
|
||||
|
||||
function sanitizeUri(uri) {
|
||||
// Fixes when a region uses comma to separate decimals
|
||||
var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i;
|
||||
var match = regex.exec(uri);
|
||||
if (!match || match.length === 0) {
|
||||
return uri;
|
||||
}
|
||||
var value = match[0].replace(',', '.');
|
||||
var newUri = uri.replace(regex, value);
|
||||
return newUri;
|
||||
};
|
||||
|
||||
var satToUnit = 1 / this.unitToSatoshi;
|
||||
|
||||
// URI extensions for Payment Protocol with non-backwards-compatible request
|
||||
if ((/^bitcoin:\?r=[\w+]/).exec(uri)) {
|
||||
uri = decodeURIComponent(uri.replace('bitcoin:?r=', ''));
|
||||
this.setFromPayPro(uri, function(err) {
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uri = sanitizeUri(uri);
|
||||
|
||||
if (!bitcore.URI.isValid(uri)) {
|
||||
return uri;
|
||||
}
|
||||
var parsed = new bitcore.URI(uri);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ?
|
||||
(parsed.amount.toFixed(0) * satToUnit).toFixed(this.unitDecimals) : 0;
|
||||
|
||||
|
||||
if (parsed.r) {
|
||||
this.setFromPayPro(parsed.r, function(err) {
|
||||
if (err && addr && amount) {
|
||||
self.setForm(addr, amount, message);
|
||||
return addr;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setForm(addr, amount, message);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.onAddressChange = function(value) {
|
||||
this.resetError();
|
||||
if (!value) return '';
|
||||
|
||||
if (this._paypro)
|
||||
return value;
|
||||
|
||||
if (value.indexOf('bitcoin:') === 0) {
|
||||
return this.setFromUri(value);
|
||||
} else if (/^https?:\/\//.test(value)) {
|
||||
return this.setFromPayPro(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
// History
|
||||
|
||||
function strip(number) {
|
||||
return (parseFloat(number.toPrecision(12)));
|
||||
}
|
||||
|
||||
this.getUnitName = function() {
|
||||
return this.unitName;
|
||||
};
|
||||
|
||||
this.getAlternativeIsoCode = function() {
|
||||
return this.alternativeIsoCode;
|
||||
};
|
||||
|
||||
this.openTxModal = function(btx) {
|
||||
var self = this;
|
||||
|
||||
$scope.btx = lodash.cloneDeep(btx);
|
||||
$scope.self = self;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/tx-details.html', {
|
||||
scope: $scope,
|
||||
hideDelay: 500
|
||||
}).then(function(modal) {
|
||||
$scope.txDetailsModal = modal;
|
||||
$scope.txDetailsModal.show();
|
||||
});
|
||||
};
|
||||
|
||||
this.hasAction = function(actions, action) {
|
||||
return actions.hasOwnProperty('create');
|
||||
};
|
||||
|
||||
this.sendMax = function(availableBalanceSat) {
|
||||
if (availableBalanceSat == 0) {
|
||||
this.error = gettext("Cannot create transaction. Insufficient funds");
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var fc = profileService.focusedClient;
|
||||
this.error = null;
|
||||
ongoingProcess.set('calculatingFee', true);
|
||||
|
||||
$timeout(function() {
|
||||
|
||||
feeService.getCurrentFeeValue(function(err, feePerKb) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
if (err || !lodash.isNumber(feePerKb)) {
|
||||
self.error = gettext('Could not get fee value');
|
||||
return;
|
||||
}
|
||||
|
||||
var opts = {};
|
||||
opts.feePerKb = feePerKb;
|
||||
opts.returnInputs = true;
|
||||
var config = configService.getSync();
|
||||
opts.excludeUnconfirmedUtxos = !config.wallet.spendUnconfirmed;
|
||||
ongoingProcess.set('retrivingInputs', true);
|
||||
|
||||
fc.getSendMaxInfo(opts, function(err, resp) {
|
||||
ongoingProcess.set('retrivingInputs', false);
|
||||
|
||||
if (err) {
|
||||
self.error = err;
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp.amount == 0) {
|
||||
self.error = gettext("Not enough funds for fee");
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees", {
|
||||
fee: profileService.formatAmount(resp.fee) + ' ' + self.unitName
|
||||
});
|
||||
|
||||
var warningMsg = verifyExcludedUtxos();
|
||||
|
||||
if (!lodash.isEmpty(warningMsg))
|
||||
msg += '. \n' + warningMsg;
|
||||
|
||||
confirmDialog.show(msg, function(confirmed) {
|
||||
if (confirmed) {
|
||||
self.sendMaxInfo = resp;
|
||||
var amount = parseFloat((resp.amount * self.satToUnit).toFixed(self.unitDecimals));
|
||||
self.setForm(null, amount, null);
|
||||
} else {
|
||||
self.resetForm();
|
||||
}
|
||||
});
|
||||
|
||||
function verifyExcludedUtxos() {
|
||||
var warningMsg = [];
|
||||
if (resp.utxosBelowFee > 0) {
|
||||
warningMsg.push(gettextCatalog.getString("Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", {
|
||||
amountBelowFeeStr: profileService.formatAmount(resp.amountBelowFee) + ' ' + self.unitName
|
||||
}));
|
||||
}
|
||||
if (resp.utxosAboveMaxSize > 0) {
|
||||
warningMsg.push(gettextCatalog.getString("Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded", {
|
||||
amountAboveMaxSizeStr: profileService.formatAmount(resp.amountAboveMaxSize) + ' ' + self.unitName
|
||||
}));
|
||||
}
|
||||
return warningMsg.join('\n');
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 10);
|
||||
};
|
||||
|
||||
/* Start setup */
|
||||
lodash.assign(self, vanillaScope);
|
||||
|
||||
this.bindTouchDown();
|
||||
if (profileService.focusedClient) {
|
||||
this.setAddress();
|
||||
this.setSendFormInputs();
|
||||
}
|
||||
|
||||
});
|
Loading…
Reference in New Issue