Merge pull request #4360 from matiu/bug/webintents

Bug/webintents
This commit is contained in:
Gustavo Maximiliano Cortez 2016-06-13 10:48:18 -03:00 committed by GitHub
commit 88b25370ff
39 changed files with 616 additions and 1041 deletions

View file

@ -9,21 +9,21 @@
<div class="content">
<ul class="no-bullet manage size-12">
<li>
<a title="Create new wallet" ng-click="$root.go('create')">
<a title="Create new wallet" href ui-sref="create">
<i class="fi-plus circle plus-fixed"></i>
<i class="icon-arrow-right3 size-18 right m20t"></i>
<span translate>Create new wallet</span>
</a>
</li>
<li>
<a title="Join shared wallet" ng-click="$root.go('join')">
<a title="Join shared wallet" href ui-sref="join">
<i class="icon-people circle"></i>
<i class="icon-arrow-right3 size-18 right m20t"></i>
<span translate>Join shared wallet</span>
</a>
</li>
<li>
<a title="Import wallet" ng-click="$root.go('import')">
<a title="Import wallet" href ui-sref="import">
<i class="icon-download circle"></i>
<i class="icon-arrow-right3 size-18 right m20t"></i>
<span translate>Import wallet </span>

View file

@ -7,12 +7,12 @@
<div class="content">
<ul class="no-bullet manage text-center">
<li class="white m20t" ng-show="index.glideraEnabled">
<a ng-click="$root.go('glidera')">
<a href ui-sref="glidera">
<img src="img/glidera-logo.png" width="150">
</a>
</li>
<li class="white m20t" ng-show="index.coinbaseEnabled">
<a ng-click="$root.go('coinbase')">
<a href ui-sref="coinbase">
<img src="img/coinbase-logo.png" width="150">
</a>
</li>

View file

@ -84,7 +84,7 @@
<div
ng-if="index.coinbaseToken"
ng-init="buy.init(index.coinbaseTestnet)"
ng-click="openWalletsModal(buy.otherWallets)">
ng-click="openWalletsModal(buy.allWallets)">
<label>Copay Wallet</label>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="buy.selectedWalletId"

View file

@ -42,7 +42,7 @@
<div ng-if="index.glideraToken"
ng-init="buy.init(index.glideraTestnet)"
ng-click="openWalletsModal(buy.otherWallets)">
ng-click="openWalletsModal(buy.allWallets)">
<label>Wallet</label>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="buy.selectedWalletId"

View file

@ -21,7 +21,7 @@
<div class="create-tab pr small-only-text-center" ng-hide="create.hideTabs">
<div class="row">
<div class="tab-container small-4 medium-4 large-4" ng-class="{'selected': type =='12'}">
<a href ng-click="import.setType('12')" translate>Wallet Recovery Phrase</a>
<a href ng-click="import.setType('12')" translate>Recovery Phrase</a>
</div>
<div class="tab-container small-4 medium-4 large-4" ng-class="{'selected': type=='file'}">
<a href ng-click="import.setType('file')" translate>File/Text Backup</a>
@ -161,14 +161,6 @@
Import backup
</button>
</form>
<div class="text-center text-gray p20v" ng-click="$root.go('importLegacy')">
<p class="text-gray m5b size-14" translate> Have a Backup from Copay v0.9?</p>
<button class=" outline dark-gray tiny round"> <span translate>Import here</span>
<i class="icon-arrow-right3 size-14"></i>
</button>
</div>
</div>
</div>

View file

@ -1,68 +0,0 @@
<div
class="topbar-container"
ng-include="'views/includes/topbar.html'"
ng-init="titleSection='Import legacy wallet'; goBackToState = 'import'; noColor = true">
</div>
<div class="content p20v" ng-controller="importLegacyController as importLegacy">
<div class="row m20t">
<div class="large-12 columns">
<div ng-show="importLegacy.importing">
<h1 class="m20b animated infinite flash" translate>Importing...</h1>
<ul>
<li ng-repeat="m in importLegacy.messages">
<span ng-style="{'opacity':m.opacity}">{{m.message|translate}}</span>
</ul>
</div>
<div class="box-notification" ng-show="importLegacy.error">
<span class="text-warning size-14">
{{importLegacy.error|translate}}
</span>
</div>
<div ng-show="!importLegacy.importing">
<form name="importForm" ng-submit="importLegacy.import(importForm)" novalidate>
<label for="fromCloud" class="line-b oh m20b">
<span translate>Import from the Cloud?</span>
<switch id="fromCloud" name="fromCloud" ng-model="importLegacy.fromCloud" class="green right m5t m10b"></switch>
</label>
<label for="username">
<span ng-show="importLegacy.fromCloud" translate>Email</span>
<span ng-show="!importLegacy.fromCloud" translate>Username</span>
<input type="text" class="form-control"
placeholder="{{importLegacy.fromCloud ? ('Email'|translate): ('Username'|translate)}}"
name="username" ng-model="importLegacy.username" autocapitalize="off" required>
</label>
<label for="password">
<span translate>Password</span>
<input type="password" class="form-control" placeholder="{{'Your profile password'|translate}}"
name="password" ng-model="importLegacy.password" required>
</label>
<label for="server" ng-show="importLegacy.fromCloud">
<span translate>Server</span>
<input type="text" class="form-control" placeholder="{{'Server URL'}}"
name="server" ng-model="importLegacy.server" required>
</label>
<button translate type="submit"
class="button black round expand m0"
ng-disabled="importForm.$invalid">
Import
</button>
</form>
<div class="text-center p20v">
<a class="m20t tiny button outline round light-gray " ng-click="$root.openExternalLink('https://github.com/bitpay/copay/releases/tag/v0.10.0')" translate>
Learn more about Wallet Migration
</a>
</div>
</div>
</div>
</div>
</div>

View file

@ -9,44 +9,37 @@
<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">
<a menu-toggle ng-click="$root.go('walletHome'); sidebar.switchWallet(item.id, index.walletId)" class="oh">
class="nav-item"
menu-toggle on-touch="$root.go('walletHome'); 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>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('add')" class="oh">
<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>
</a>
</li>
<li ng-show="!index.isWindowsPhoneApp && index.isComplete && (index.glideraEnabled || index.coinbaseEnabled)">
<a menu-toggle ng-click="$root.go('buyandsell')" class="oh">
<li ng-show="!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 &amp; Sell</span>
</div>
</a>
</li>
<li>
<a menu-toggle ng-click="$root.go('preferencesGlobal')" class="oh">
<li 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>
</a>
</li>
</ul>
</ion-content>

View file

@ -5,7 +5,7 @@
</div>
<div class="content p20v row payment-uri" ng-controller="paymentUriController as payment">
<div class="large-12 columns" ng-init="payment.checkBitcoinUri()">
<div class="large-12 columns" ng-init="payment.init()">
<div class="panel text-center" ng-if="!payment.uri">
<h1 translate>Bitcoin URI is NOT valid!</h1>
</div>

View file

@ -38,7 +38,7 @@
<div
ng-if="index.coinbaseToken"
ng-init="sell.init(index.coinbaseTestnet)"
ng-click="openWalletsModal(sell.otherWallets)">
ng-click="openWalletsModal(sell.allWallets)">
<label>Copay Wallet</label>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="sell.selectedWalletId"

View file

@ -41,7 +41,7 @@
<div ng-if="index.glideraToken"
ng-init="sell.init(index.glideraTestnet)"
ng-click="openWalletsModal(sell.otherWallets)">
ng-click="openWalletsModal(sell.allWallets)">
<label>Wallet</label>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="sell.selectedWalletId"

11
public/views/uri.html Normal file
View file

@ -0,0 +1,11 @@
<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>

View file

@ -2,36 +2,19 @@
angular.module('copayApp.controllers').controller('buyCoinbaseController',
function($scope, $modal, $log, $ionicModal, $timeout, lodash, profileService, coinbaseService, bwsError, addressService) {
window.ignoreMobilePause = true;
var self = this;
var fc;
var otherWallets = function(testnet) {
var network = testnet ? 'testnet' : 'livenet';
return lodash.filter(profileService.getWallets(network), function(w) {
return w.network == network;
});
};
this.init = function(testnet) {
self.otherWallets = otherWallets(testnet);
// Choose focused wallet
try {
var currentWalletId = profileService.focusedClient.credentials.walletId;
lodash.find(self.otherWallets, function(w) {
if (w.id == currentWalletId) {
$timeout(function() {
self.selectedWalletId = w.id;
self.selectedWalletName = w.name;
fc = profileService.getClient(w.id);
$scope.$apply();
}, 100);
}
});
} catch (e) {
$log.debug(e);
};
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1)
var client = profileService.focusedClient;
if (client) {
$timeout(function() {
self.selectedWalletId = client.credentials.walletId;
self.selectedWalletName = client.credentials.walletName;
$scope.$apply();
}, 100);
}
};
this.getPaymentMethods = function(token) {

View file

@ -9,32 +9,17 @@ angular.module('copayApp.controllers').controller('buyGlideraController',
this.success = null;
this.loading = null;
window.ignoreMobilePause = true;
var otherWallets = function(testnet) {
var network = testnet ? 'testnet' : 'livenet';
return lodash.filter(profileService.getWallets(network), function(w) {
return w.network == network;
});
};
this.init = function(testnet) {
self.otherWallets = otherWallets(testnet);
// Choose focused wallet
try {
var currentWalletId = profileService.focusedClient.credentials.walletId;
lodash.find(self.otherWallets, function(w) {
if (w.id == currentWalletId) {
$timeout(function() {
self.selectedWalletId = w.id;
self.selectedWalletName = w.name;
$scope.$apply();
}, 100);
}
});
} catch (e) {
$log.debug(e);
};
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1)
var client = profileService.focusedClient;
if (client) {
$timeout(function() {
self.selectedWalletId = client.credentials.walletId;
self.selectedWalletName = client.credentials.walletName;
$scope.$apply();
}, 100);
}
};
$scope.openWalletsModal = function(wallets) {

View file

@ -4,7 +4,6 @@ angular.module('copayApp.controllers').controller('coinbaseController',
function($rootScope, $scope, $timeout, $modal, $ionicModal, profileService, configService, storageService, coinbaseService, lodash, platformInfo) {
var isNW = platformInfo.isNW;
window.ignoreMobilePause = true;
this.openAuthenticateWindow = function() {
var oauthUrl = this.getAuthenticateUrl();

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('coinbaseUriController',
function($scope, $stateParams, $timeout, profileService, configService, coinbaseService, storageService, go) {
function($scope, $stateParams, $timeout, profileService, configService, coinbaseService, storageService, go) {
this.submitOauthCode = function(code) {
var self = this;
@ -14,10 +14,9 @@ angular.module('copayApp.controllers').controller('coinbaseUriController',
if (err) {
self.error = err;
$timeout(function() {
$scope.$apply();
}, 100);
}
else if (data && data.access_token && data.refresh_token) {
$scope.$apply();
}, 100);
} else if (data && data.access_token && data.refresh_token) {
storageService.setCoinbaseToken(network, data.access_token, function() {
storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() {
$scope.$emit('Local/CoinbaseUpdated', data.access_token);
@ -33,8 +32,13 @@ angular.module('copayApp.controllers').controller('coinbaseUriController',
};
this.checkCode = function() {
this.code = $stateParams.code;
this.submitOauthCode(this.code);
};
if ($stateParams.url) {
var match = $stateParams.url.match(/code=(.+)&/);
if (match && match[1]) {
this.code = match[1];
return this.submitOauthCode(this.code);
}
}
$log.error('Bad state: ' + JSON.stringify($stateParams));
}
});

View file

@ -92,9 +92,6 @@ angular.module('copayApp.controllers').controller('copayersController',
self.shareSecret = function(secret) {
if (isCordova) {
if (isAndroid || isWP) {
window.ignoreMobilePause = true;
}
var message = gettextCatalog.getString('Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io', {
secret: secret
});

View file

@ -126,9 +126,6 @@ angular.module('copayApp.controllers').controller('exportController',
self.sendWalletBackup = function() {
var fc = profileService.focusedClient;
if (isAndroid || isWP) {
window.ignoreMobilePause = true;
}
window.plugins.toast.showShortCenter(gettextCatalog.getString('Preparing backup...'));
var name = (fc.credentials.walletName || fc.credentials.walletId);
if (fc.alias) {

View file

@ -1,8 +1,9 @@
'use strict';
angular.module('copayApp.controllers').controller('glideraUriController',
function($scope, $stateParams, $timeout, profileService, configService, glideraService, storageService, go) {
function($scope, $log, $stateParams, $timeout, profileService, configService, glideraService, storageService, go) {
this.submitOauthCode = function(code) {
$log.debug('Glidera Oauth Code:' + code);
var self = this;
var glideraTestnet = configService.getSync().glidera.testnet;
var network = glideraTestnet ? 'testnet' : 'livenet';
@ -14,10 +15,9 @@ angular.module('copayApp.controllers').controller('glideraUriController',
if (err) {
self.error = err;
$timeout(function() {
$scope.$apply();
}, 100);
}
else if (data && data.access_token) {
$scope.$apply();
}, 100);
} else if (data && data.access_token) {
storageService.setGlideraToken(network, data.access_token, function() {
$scope.$emit('Local/GlideraUpdated', data.access_token);
$timeout(function() {
@ -31,8 +31,13 @@ angular.module('copayApp.controllers').controller('glideraUriController',
};
this.checkCode = function() {
this.code = $stateParams.code;
this.submitOauthCode(this.code);
};
if ($stateParams.url) {
var match = $stateParams.url.match(/code=(.+)/);
if (match && match[1]) {
this.code = match[1];
return this.submitOauthCode(this.code);
}
}
$log.error('Bad state: ' + JSON.stringify($stateParams));
}
});

View file

@ -15,14 +15,6 @@ angular.module('copayApp.controllers').controller('importController',
$scope.account = 1;
self.importErr = false;
window.ignoreMobilePause = true;
$scope.$on('$destroy', function() {
$timeout(function() {
window.ignoreMobilePause = false;
}, 100);
});
var updateSeedSourceSelect = function() {
self.seedOptions = [];

View file

@ -1,63 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('importLegacyController',
function($rootScope, $scope, $log, $timeout, notification, legacyImportService, profileService, go, lodash, bitcore, gettext, gettextCatalog) {
var self = this;
self.messages = [];
self.fromCloud = true;
self.server = "https://insight.bitpay.com:443/api/email";
$rootScope.$on('Local/ImportStatusUpdate', function(event, status) {
$timeout(function() {
$log.debug(status);
self.messages.unshift({
message: status,
});
var op = 1;
lodash.each(self.messages, function(m) {
if (op < 0.1) op = 0.1;
m.opacity = op;
op = op - 0.15;
});
}, 100);
});
self.scan = function(ids) {
$log.debug('### Scanning: ' + ids)
var i = 0;
lodash.each(ids, function(id) {
$rootScope.$emit('Local/WalletImported', id);
if (++i == ids.length) {
go.walletHome();
};
});
};
self.import = function(form) {
var username = form.username.$modelValue;
var password = form.password.$modelValue;
var serverURL = form.server.$modelValue;
var fromCloud = form.fromCloud.$modelValue;
self.error = null;
self.importing = true;
$timeout(function() {
legacyImportService.import(username, password, serverURL, fromCloud, function(err, ids, toScanIds) {
if (err || !ids || !ids.length) {
self.importing = false;
self.error = err || gettext('Failed to import wallets');
return;
}
notification.success( gettextCatalog.getString('{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance', {len: ids.length}));
self.scan(toScanIds);
});
}, 100);
};
// TODO destroy event...
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, $ionicScrollDelegate, $ionicPopup, latestReleaseService, feeService, bwcService, pushNotificationsService, lodash, go, profileService, configService, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, addonManager, bwsError, txFormatService, uxLanguage, glideraService, coinbaseService, platformInfo, addressbookService) {
angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, $ionicScrollDelegate, $ionicPopup, latestReleaseService, feeService, bwcService, pushNotificationsService, lodash, go, profileService, configService, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, addonManager, bwsError, txFormatService, uxLanguage, glideraService, coinbaseService, platformInfo, addressbookService, openURLService) {
var self = this;
var SOFT_CONFIRMATION_LIMIT = 12;
var errors = bwcService.getErrors();
@ -289,6 +289,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
initStatusHash = _walletStatusHash();
$log.debug('Updating status until it changes. initStatusHash:' + initStatusHash)
}
var get = function(cb) {
if (opts.walletStatus)
return cb(null, opts.walletStatus);
@ -351,6 +352,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.setPendingTxps(walletStatus.pendingTxps);
// Status Shortcuts
self.lastUpdate = Date.now();
self.walletName = walletStatus.wallet.name;
self.walletSecret = walletStatus.wallet.secret;
self.walletStatus = walletStatus.wallet.status;
@ -1425,6 +1427,19 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.tab = 'walletHome';
});
$rootScope.$on('Local/ValidatingWallet', function() {
if (isCordova) {
window.plugins.spinnerDialog.hide();
window.plugins.spinnerDialog.show(null, gettext('Validating wallet integrity...'), true);
}
});
$rootScope.$on('Local/ProfileBound', function() {
if (isCordova) {
window.plugins.spinnerDialog.hide();
}
});
$rootScope.$on('Local/ClearHistory', function(event) {
$log.debug('The wallet transaction history has been deleted');
self.txHistory = self.completeHistory = self.txHistorySearchResults = [];
@ -1492,59 +1507,105 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}
});
self.debouncedUpdate = lodash.throttle(function() {
self.updateAll({
quiet: true
});
self.debounceUpdateHistory();
}, 2000, {
leading: false,
trailing: true
});
self.debouncedUpdate = function() {
var now = Date.now();
var oneHr = 1000 * 60 * 60;
$rootScope.$on('Local/Resume', function(event) {
$log.debug('### Resume event');
profileService.isDisclaimerAccepted(function(v) {
if (!v) {
$log.debug('Disclaimer not accepted, resume to home');
go.path('disclaimer');
}
});
self.debouncedUpdate();
});
$rootScope.$on('Local/BackupDone', function(event, walletId) {
self.needsBackup = false;
$log.debug('Backup done');
storageService.setBackupFlag(walletId || self.walletId, function(err) {
$log.debug('Backup stored');
});
});
$rootScope.$on('Local/DeviceError', function(event, err) {
self.showErrorPopup(err, function() {
if (isCordova && navigator && navigator.app) {
navigator.app.exitApp();
}
});
});
$rootScope.$on('Local/WalletImported', function(event, walletId) {
self.needsBackup = false;
storageService.setBackupFlag(walletId, function() {
$log.debug('Backup done stored');
addressService.expireAddress(walletId, function(err) {
$timeout(function() {
self.txHistory = self.completeHistory = self.txHistorySearchResults = [];
storageService.removeTxHistory(walletId, function() {
self.startScan(walletId);
});
}, 500);
if (!self.lastUpdate || (now - self.lastUpdate) > oneHr) {
self.updateAll({
quiet: true,
triggerTxUpdate: true
});
}
};
$rootScope.$on('Local/Resume', function(event) {
$log.debug('### Resume event');
profileService.isDisclaimerAccepted(function(v) {
if (!v) {
$log.debug('Disclaimer not accepted, resume to home');
go.path('disclaimer');
}
});
self.debouncedUpdate();
});
$rootScope.$on('Local/BackupDone', function(event, walletId) {
self.needsBackup = false;
$log.debug('Backup done');
storageService.setBackupFlag(walletId || self.walletId, function(err) {
$log.debug('Backup stored');
});
});
$rootScope.$on('Local/DeviceError', function(event, err) {
self.showErrorPopup(err, function() {
if (isCordova && navigator && navigator.app) {
navigator.app.exitApp();
}
});
});
$rootScope.$on('Local/WalletImported', function(event, walletId) {
self.needsBackup = false;
storageService.setBackupFlag(walletId, function() {
$log.debug('Backup done stored');
addressService.expireAddress(walletId, function(err) {
$timeout(function() {
self.txHistory = self.completeHistory = self.txHistorySearchResults = [];
storageService.removeTxHistory(walletId, function() {
self.startScan(walletId);
});
}, 500);
});
});
});
$rootScope.$on('NewIncomingTx', function() {
$rootScope.$on('NewIncomingTx', function() {
self.newTx = true;
self.updateAll({
walletStatus: null,
untilItChanges: true,
triggerTxUpdate: true,
});
});
$rootScope.$on('NewBlock', function() {
if (self.glideraEnabled) {
$timeout(function() {
self.updateGlidera();
});
}
if (self.coinbaseEnabled) {
$timeout(function() {
self.updateCoinbase();
});
}
if (self.pendingAmount) {
self.updateAll({
walletStatus: null,
untilItChanges: null,
triggerTxUpdate: true,
});
} else if (self.hasUnsafeConfirmed) {
$log.debug('Wallet has transactions with few confirmations. Updating.')
if (self.network == 'testnet') {
self.throttledUpdateHistory();
} else {
self.debounceUpdateHistory();
}
}
});
$rootScope.$on('BalanceUpdated', function(e, n) {
self.setBalance(n.data);
});
//untilItChange TRUE
lodash.each(['NewOutgoingTx', 'NewOutgoingTxByThirdParty'], function(eventName) {
$rootScope.$on(eventName, function(event) {
self.newTx = true;
self.updateAll({
walletStatus: null,
@ -1552,244 +1613,200 @@ angular.module('copayApp.controllers').controller('indexController', function($r
triggerTxUpdate: true,
});
});
});
$rootScope.$on('NewBlock', function() {
if (self.glideraEnabled) {
$timeout(function() {
self.updateGlidera();
});
}
if (self.coinbaseEnabled) {
$timeout(function() {
self.updateCoinbase();
});
}
if (self.pendingAmount) {
self.updateAll({
walletStatus: null,
untilItChanges: null,
triggerTxUpdate: true,
});
} else if (self.hasUnsafeConfirmed) {
$log.debug('Wallet has transactions with few confirmations. Updating.')
if (self.network == 'testnet') {
self.throttledUpdateHistory();
} else {
self.debounceUpdateHistory();
}
}
});
$rootScope.$on('BalanceUpdated', function(e, n) {
self.setBalance(n.data);
});
//untilItChange TRUE
lodash.each(['NewOutgoingTx', 'NewOutgoingTxByThirdParty'], function(eventName) {
$rootScope.$on(eventName, function(event) {
self.newTx = true;
self.updateAll({
walletStatus: null,
untilItChanges: true,
triggerTxUpdate: true,
});
});
});
//untilItChange FALSE
lodash.each(['NewTxProposal', 'TxProposalFinallyRejected', 'TxProposalRemoved', 'NewOutgoingTxByThirdParty',
'Local/GlideraTx'
], function(eventName) {
$rootScope.$on(eventName, function(event) {
self.updateAll({
walletStatus: null,
untilItChanges: null,
triggerTxUpdate: true,
});
});
});
//untilItChange Maybe
$rootScope.$on('Local/TxProposalAction', function(event, untilItChanges) {
self.newTx = untilItChanges;
//untilItChange FALSE
lodash.each(['NewTxProposal', 'TxProposalFinallyRejected', 'TxProposalRemoved', 'NewOutgoingTxByThirdParty',
'Local/GlideraTx'
], function(eventName) {
$rootScope.$on(eventName, function(event) {
self.updateAll({
walletStatus: null,
untilItChanges: untilItChanges,
untilItChanges: null,
triggerTxUpdate: true,
});
});
});
$rootScope.$on('ScanFinished', function() {
$log.debug('Scan Finished. Updating history');
storageService.removeTxHistory(self.walletId, function() {
self.updateAll({
walletStatus: null,
triggerTxUpdate: true,
});
//untilItChange Maybe
$rootScope.$on('Local/TxProposalAction', function(event, untilItChanges) {
self.newTx = untilItChanges;
self.updateAll({
walletStatus: null,
untilItChanges: untilItChanges,
triggerTxUpdate: true,
});
});
$rootScope.$on('ScanFinished', function() {
$log.debug('Scan Finished. Updating history');
storageService.removeTxHistory(self.walletId, function() {
self.updateAll({
walletStatus: null,
triggerTxUpdate: true,
});
});
});
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy'], function(eventName) {
$rootScope.$on(eventName, function() {
var f = function() {
if (self.updatingStatus) {
return $timeout(f, 200);
};
self.updatePendingTxps();
lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy'], function(eventName) {
$rootScope.$on(eventName, function() {
var f = function() {
if (self.updatingStatus) {
return $timeout(f, 200);
};
f();
});
self.updatePendingTxps();
};
f();
});
});
$rootScope.$on('Local/NoWallets', function(event) {
$timeout(function() {
self.hasProfile = true;
self.noFocusedWallet = true;
self.isComplete = null;
self.walletName = null;
uxLanguage.update();
profileService.isDisclaimerAccepted(function(v) {
if (v) {
go.path('import');
}
});
});
});
$rootScope.$on('Local/NewFocusedWallet', function() {
$rootScope.$on('Local/NoWallets', function(event) {
$timeout(function() {
self.hasProfile = true;
self.noFocusedWallet = true;
self.isComplete = null;
self.walletName = null;
uxLanguage.update();
self.setFocusedWallet();
self.updateHistory();
storageService.getCleanAndScanAddresses(function(err, walletId) {
if (walletId && profileService.walletClients[walletId]) {
$log.debug('Clear last address cache and Scan ', walletId);
addressService.expireAddress(walletId, function(err) {
self.startScan(walletId);
});
storageService.removeCleanAndScanAddresses(function() {
$rootScope.$emit('Local/NewFocusedWalletReady');
});
} else {
$rootScope.$emit('Local/NewFocusedWalletReady');
profileService.isDisclaimerAccepted(function(v) {
if (v) {
go.path('import');
}
});
});
});
$rootScope.$on('Local/SetTab', function(event, tab, reset) {
self.setTab(tab, reset);
});
$rootScope.$on('Local/NewFocusedWallet', function() {
uxLanguage.update();
self.setFocusedWallet();
self.updateHistory();
storageService.getCleanAndScanAddresses(function(err, walletId) {
$rootScope.$on('Local/NeedsConfirmation', function(event, txp, cb) {
function openConfirmationPopup(txp, cb) {
$scope.tx = txFormatService.processTx(txp);
self.confirmationPopup = $ionicPopup.show({
templateUrl: 'views/includes/confirm-tx.html',
scope: $scope,
if (walletId && profileService.walletClients[walletId]) {
$log.debug('Clear last address cache and Scan ', walletId);
addressService.expireAddress(walletId, function(err) {
self.startScan(walletId);
});
$scope.processFee = function(amount, fee) {
var walletSettings = configService.getSync().wallet.settings;
var feeAlternativeIsoCode = walletSettings.alternativeIsoCode;
$scope.feeLevel = feeService.feeOpts[feeService.getCurrentFeeLevel()];
$scope.feeAlternativeStr = parseFloat((rateService.toFiat(fee, feeAlternativeIsoCode)).toFixed(2), 10) + ' ' + feeAlternativeIsoCode;
$scope.feeRateStr = (fee / (amount + fee) * 100).toFixed(2) + '%';
};
$scope.cancel = function() {
return cb();
};
$scope.accept = function() {
return cb(true);
};
storageService.removeCleanAndScanAddresses(function() {
$rootScope.$emit('Local/NewFocusedWalletReady');
});
} else {
$rootScope.$emit('Local/NewFocusedWalletReady');
}
openConfirmationPopup(txp, function(accept) {
self.confirmationPopup.close();
return cb(accept);
});
});
});
$rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) {
$rootScope.$on('Local/SetTab', function(event, tab, reset) {
self.setTab(tab, reset);
});
function openPasswordPopup(isSetup, cb) {
$scope.data = {};
$scope.data.password = null;
$scope.isSetup = isSetup;
$scope.isVerification = false;
$scope.loading = false;
var pass = null;
$rootScope.$on('Local/NeedsConfirmation', function(event, txp, cb) {
self.passwordPopup = $ionicPopup.show({
templateUrl: 'views/includes/password.html',
scope: $scope,
});
function openConfirmationPopup(txp, cb) {
$scope.cancel = function() {
return cb('No spending password given');
};
$scope.tx = txFormatService.processTx(txp);
$scope.set = function() {
$scope.loading = true;
$scope.error = null;
self.confirmationPopup = $ionicPopup.show({
templateUrl: 'views/includes/confirm-tx.html',
scope: $scope,
});
$timeout(function() {
if (isSetup && !$scope.isVerification) {
$scope.loading = false;
$scope.isVerification = true;
pass = $scope.data.password;
$scope.data.password = null;
return;
}
if (isSetup && pass != $scope.data.password) {
$scope.loading = false;
$scope.error = gettext('Spending Passwords do not match');
$scope.isVerification = false;
$scope.data.password = null;
pass = null;
return;
}
return cb(null, $scope.data.password);
}, 100);
};
$scope.processFee = function(amount, fee) {
var walletSettings = configService.getSync().wallet.settings;
var feeAlternativeIsoCode = walletSettings.alternativeIsoCode;
$scope.feeLevel = feeService.feeOpts[feeService.getCurrentFeeLevel()];
$scope.feeAlternativeStr = parseFloat((rateService.toFiat(fee, feeAlternativeIsoCode)).toFixed(2), 10) + ' ' + feeAlternativeIsoCode;
$scope.feeRateStr = (fee / (amount + fee) * 100).toFixed(2) + '%';
};
openPasswordPopup(isSetup, function(err, pass) {
self.passwordPopup.close();
return cb(err, pass);
});
$scope.cancel = function() {
return cb();
};
$scope.accept = function() {
return cb(true);
};
}
openConfirmationPopup(txp, function(accept) {
self.confirmationPopup.close();
return cb(accept);
});
$rootScope.$on('Local/EmailUpdated', function(event, email) {
self.preferences.email = email;
});
lodash.each(['NewCopayer', 'CopayerUpdated'], function(eventName) {
$rootScope.$on(eventName, function() {
// Re try to open wallet (will triggers)
self.setFocusedWallet();
});
});
$rootScope.$on('Local/NewEncryptionSetting', function() {
var fc = profileService.focusedClient;
self.isPrivKeyEncrypted = fc.isPrivKeyEncrypted();
$timeout(function() {
$rootScope.$apply();
});
});
/* Start setup */
lodash.assign(self, vanillaScope);
});
$rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) {
function openPasswordPopup(isSetup, cb) {
$scope.data = {};
$scope.data.password = null;
$scope.isSetup = isSetup;
$scope.isVerification = false;
$scope.loading = false;
var pass = null;
self.passwordPopup = $ionicPopup.show({
templateUrl: 'views/includes/password.html',
scope: $scope,
});
$scope.cancel = function() {
return cb('No spending password given');
};
$scope.set = function() {
$scope.loading = true;
$scope.error = null;
$timeout(function() {
if (isSetup && !$scope.isVerification) {
$scope.loading = false;
$scope.isVerification = true;
pass = $scope.data.password;
$scope.data.password = null;
return;
}
if (isSetup && pass != $scope.data.password) {
$scope.loading = false;
$scope.error = gettext('Spending Passwords do not match');
$scope.isVerification = false;
$scope.data.password = null;
pass = null;
return;
}
return cb(null, $scope.data.password);
}, 100);
};
};
openPasswordPopup(isSetup, function(err, pass) {
self.passwordPopup.close();
return cb(err, pass);
});
});
$rootScope.$on('Local/EmailUpdated', function(event, email) {
self.preferences.email = email;
});
lodash.each(['NewCopayer', 'CopayerUpdated'], function(eventName) {
$rootScope.$on(eventName, function() {
// Re try to open wallet (will triggers)
self.setFocusedWallet();
});
});
$rootScope.$on('Local/NewEncryptionSetting', function() {
var fc = profileService.focusedClient;
self.isPrivKeyEncrypted = fc.isPrivKeyEncrypted();
$timeout(function() {
$rootScope.$apply();
});
});
/* Start setup */
lodash.assign(self, vanillaScope); openURLService.init();
});

View file

@ -69,9 +69,6 @@ angular.module('copayApp.controllers').controller('customAmountController', func
$scope.shareAddress = function(uri) {
if (platformInfo.isCordova) {
if (platformInfo.isAndroid || platformInfo.isWP) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share(uri, null, null, null);
}
};

View file

@ -1,20 +1,14 @@
'use strict';
angular.module('copayApp.controllers').controller('paymentUriController',
function($rootScope, $stateParams, $location, $timeout, profileService, configService, lodash, bitcore, go) {
window.ignoreMobilePause = true;
function strip(number) {
return (parseFloat(number.toPrecision(12)));
};
// Build bitcoinURI with querystring
this.checkBitcoinUri = function() {
this.init = function() {
var query = [];
angular.forEach($location.search(), function(value, key) {
query.push(key + "=" + value);
});
var queryString = query ? query.join("&") : null;
this.bitcoinURI = $stateParams.data + (queryString ? '?' + queryString : '');
this.bitcoinURI = $stateParams.url;
var URI = bitcore.URI;
var isUriValid = URI.isValid(this.bitcoinURI);

View file

@ -46,10 +46,6 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
this.sendAddrs = function() {
var self = this;
if (platformInfo.isAndroid || platformInfo.isWP) {
window.ignoreMobilePause = true;
}
self.loading = true;
function formatDate(ts) {

View file

@ -3,9 +3,8 @@
angular.module('copayApp.controllers').controller('sellCoinbaseController',
function($rootScope, $scope, $modal, $log, $timeout, $ionicModal, lodash, profileService, coinbaseService, bwsError, configService, walletService, fingerprintService) {
window.ignoreMobilePause = true;
var self = this;
var fc;
var client;
$scope.priceSensitivity = [
{
@ -31,13 +30,6 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
];
$scope.selectedPriceSensitivity = $scope.priceSensitivity[1];
var otherWallets = function(testnet) {
var network = testnet ? 'testnet' : 'livenet';
return lodash.filter(profileService.getWallets(network), function(w) {
return w.network == network && w.m == 1;
});
};
var handleEncryptedWallet = function(client, cb) {
if (!walletService.isEncrypted(client)) return cb();
$rootScope.$emit('Local/NeedsPassword', false, function(err, password) {
@ -47,23 +39,16 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
};
this.init = function(testnet) {
self.otherWallets = otherWallets(testnet);
// Choose focused wallet
try {
var currentWalletId = profileService.focusedClient.credentials.walletId;
lodash.find(self.otherWallets, function(w) {
if (w.id == currentWalletId) {
$timeout(function() {
self.selectedWalletId = w.id;
self.selectedWalletName = w.name;
fc = profileService.getClient(w.id);
$scope.$apply();
}, 100);
}
});
} catch (e) {
$log.debug(e);
};
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1);
client = profileService.focusedClient;
if (client) {
$timeout(function() {
self.selectedWalletId = client.credentials.walletId;
self.selectedWalletName = client.credentials.walletName;
$scope.$apply();
}, 100);
}
};
this.getPaymentMethods = function(token) {
@ -157,6 +142,11 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
this.createTx = function(token, account, amount) {
self.error = null;
if (!client) {
self.error = 'No wallet selected';
return;
}
var accountId = account.id;
var dataSrc = {
name: 'Received from Copay: ' + self.selectedWalletName
@ -199,7 +189,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
feeLevel: walletSettings.feeLevel || 'normal'
};
walletService.createTx(fc, txp, function(err, createdTxp) {
walletService.createTx(client, txp, function(err, createdTxp) {
if (err) {
$log.debug(err);
self.loading = null;
@ -239,7 +229,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity;
ctx['sell_price_amount'] = self.sellPrice.amount;
ctx['sell_price_currency'] = self.sellPrice.currency;
ctx['description'] = 'Copay Wallet: ' + fc.credentials.walletName;
ctx['description'] = 'Copay Wallet: ' + client.credentials.walletName;
coinbaseService.savePendingTransaction(ctx, null, function(err) {
if (err) $log.debug(err);
self.sendInfo = ctx;
@ -262,20 +252,20 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
this.confirmTx = function(txp, cb) {
fingerprintService.check(fc, function(err) {
fingerprintService.check(client, function(err) {
if (err) {
$log.debug(err);
return cb(err);
}
handleEncryptedWallet(fc, function(err) {
handleEncryptedWallet(client, function(err) {
if (err) {
$log.debug(err);
return cb(err);
}
self.loading = 'Sending bitcoin to Coinbase...';
walletService.publishTx(fc, txp, function(err, publishedTxp) {
walletService.publishTx(client, txp, function(err, publishedTxp) {
if (err) {
self.loading = null;
$log.debug(err);
@ -286,12 +276,12 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
});
}
walletService.signTx(fc, publishedTxp, function(err, signedTxp) {
walletService.lock(fc);
walletService.signTx(client, publishedTxp, function(err, signedTxp) {
walletService.lock(client);
if (err) {
self.loading = null;
$log.debug(err);
walletService.removeTx(fc, signedTxp, function(err) {
walletService.removeTx(client, signedTxp, function(err) {
if (err) $log.debug(err);
});
return cb({
@ -301,11 +291,11 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController',
});
}
walletService.broadcastTx(fc, signedTxp, function(err, broadcastedTxp) {
walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) {
if (err) {
self.loading = null;
$log.debug(err);
walletService.removeTx(fc, broadcastedTxp, function(err) {
walletService.removeTx(client, broadcastedTxp, function(err) {
if (err) $log.debug(err);
});
return cb({

View file

@ -10,16 +10,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
this.success = null;
this.error = null;
this.loading = null;
var fc;
window.ignoreMobilePause = true;
var otherWallets = function(testnet) {
var network = testnet ? 'testnet' : 'livenet';
return lodash.filter(profileService.getWallets(network), function(w) {
return w.network == network && w.m == 1;
});
};
var client;
var handleEncryptedWallet = function(client, cb) {
if (!walletService.isEncrypted(client)) return cb();
@ -30,25 +21,20 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
};
this.init = function(testnet) {
self.otherWallets = otherWallets(testnet);
// Choose focused wallet
try {
var currentWalletId = profileService.focusedClient.credentials.walletId;
lodash.find(self.otherWallets, function(w) {
if (w.id == currentWalletId) {
$timeout(function() {
self.selectedWalletId = w.id;
self.selectedWalletName = w.name;
fc = profileService.getClient(w.id);
$scope.$apply();
}, 100);
}
});
} catch (e) {
$log.debug(e);
};
self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1)
client = profileService.focusedClient;
if (client) {
$timeout(function() {
self.selectedWalletId = client.credentials.walletId;
self.selectedWalletName = client.credentials.walletName;
$scope.$apply();
}, 100);
}
};
$scope.openWalletsModal = function(wallets) {
self.error = null;
self.selectedWalletId = null;
@ -108,7 +94,12 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
var configWallet = config.wallet;
var walletSettings = configWallet.settings;
addressService.getAddress(fc.credentials.walletId, null, function(err, refundAddress) {
if (!client) {
self.error = 'No wallet selected';
return;
}
addressService.getAddress(client.credentials.walletId, null, function(err, refundAddress) {
if (!refundAddress) {
self.loading = null;
self.error = bwsError.msg(err, 'Could not create address');
@ -143,7 +134,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
};
self.loading = 'Creating transaction...';
walletService.createTx(fc, txp, function(err, createdTxp) {
walletService.createTx(client, txp, function(err, createdTxp) {
self.loading = null;
if (err) {
self.error = err.message ||  bwsError.msg(err);
@ -151,13 +142,13 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
}
$scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) {
if (accept) {
fingerprintService.check(fc, function(err) {
fingerprintService.check(client, function(err) {
if (err) {
self.error = err.message ||  bwsError.msg(err);
return;
}
handleEncryptedWallet(fc, function(err) {
handleEncryptedWallet(client, function(err) {
if (err) {
self.error = err.message ||  bwsError.msg(err);
return;
@ -165,15 +156,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
self.loading = 'Signing transaction...';
walletService.publishTx(fc, createdTxp, function(err, publishedTxp) {
walletService.publishTx(client, createdTxp, function(err, publishedTxp) {
if (err) {
self.loading = null;
self.error = err.message ||  bwsError.msg(err);
}
walletService.signTx(fc, publishedTxp, function(err, signedTxp) {
walletService.lock(fc);
walletService.removeTx(fc, signedTxp, function(err) {
walletService.signTx(client, publishedTxp, function(err, signedTxp) {
walletService.lock(client);
walletService.removeTx(client, signedTxp, function(err) {
if (err) $log.debug(err);
});
if (err) {

12
src/js/controllers/uri.js Normal file
View file

@ -0,0 +1,12 @@
'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
});
});

View file

@ -8,7 +8,6 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
var isChromeApp = platformInfo.isChromeApp;
var self = this;
window.ignoreMobilePause = false;
$rootScope.shouldHideMenuBar = false;
$rootScope.wpInputFocused = false;
var config = configService.getSync();
@ -217,9 +216,6 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
this.shareAddress = function(addr) {
if (isCordova) {
if (isAndroid || isWP) {
window.ignoreMobilePause = true;
}
window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null);
}
};

View file

@ -12,7 +12,6 @@ angular.module('copayApp.directives')
var onSuccess = function(result) {
$timeout(function() {
window.plugins.spinnerDialog.hide();
window.ignoreMobilePause = false;
}, 100);
if (isWP && result.cancelled) return;
@ -26,13 +25,11 @@ angular.module('copayApp.directives')
var onError = function(error) {
$timeout(function() {
window.ignoreMobilePause = false;
window.plugins.spinnerDialog.hide();
}, 100);
};
$scope.cordovaOpenScanner = function() {
window.ignoreMobilePause = true;
window.plugins.spinnerDialog.show(null, gettextCatalog.getString('Preparing camera...'), true);
$timeout(function() {
if (isIOS) {

View file

@ -7,42 +7,32 @@ angular.element(document).ready(function() {
angular.bootstrap(document, ['copayApp']);
};
var handleBitcoinURI = function(url) {
if (!url) return;
console.log('Custom URL:' + url); //TODO
var glidera = 'copay://glidera';
var coinbase = 'copay://coinbase';
if (url.indexOf('bitcoin:') == 0) {
url = '#/uri-payment/' + url;
} else if (url.indexOf(glidera) != -1) {
url = '#/uri-glidera' + url.replace(glidera, '');
} else if (url.indexOf(coinbase) != -1) {
url = '#/uri-coinbase' + url.replace(coinbase, '');
function handleOpenURL(url) {
if ('cordova' in window) {
console.log('DEEP LINK:' + url);
cordova.fireDocumentEvent('handleopenurl', {
url: url
});
} else {
console.log('Unknown URL!')
};
setTimeout(function() {
window.location = url;
}, 1000);
console.log("ERROR: Cannont handle open URL in non-cordova apps")
}
};
/* Cordova specific Init */
if (window.cordova !== undefined) {
if ('cordova' in window) {
window.handleOpenURL = handleOpenURL;
document.addEventListener('deviceready', function() {
window.handleOpenURL = handleBitcoinURI;
// Create a sticky event for handling the app being opened via a custom URL
cordova.addStickyDocumentEventHandler('handleopenurl');
startAngular();
}, false);
} else {
try {
window.handleOpenURL = handleBitcoinURI;
} catch (e) {}
startAngular();
}

View file

@ -112,8 +112,17 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
}
})
.state('payment', {
url: '/uri-payment/:data',
.state('uri', {
url: '/uri/:url',
needProfile: true,
views: {
'main': {
templateUrl: 'views/uri.html'
}
}
})
.state('uripayment', {
url: '/uri-payment/:url',
templateUrl: 'views/paymentUri.html',
views: {
'main': {
@ -122,11 +131,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
},
needProfile: true
})
.state('selectWalletForPayment', {
url: '/selectWalletForPayment',
controller: 'walletForPaymentController',
needProfile: true
})
.state('join', {
url: '/join',
needProfile: true,
@ -145,16 +149,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
},
}
})
.state('importLegacy', {
url: '/importLegacy',
needProfile: true,
views: {
'main': {
templateUrl: 'views/importLegacy.html',
},
}
})
.state('create', {
url: '/create',
templateUrl: 'views/create.html',
@ -215,7 +209,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('uriglidera', {
url: '/uri-glidera?code',
url: '/uri-glidera/:url',
needProfile: true,
views: {
'main': {
@ -284,7 +278,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('uricoinbase', {
url: '/uri-coinbase?code',
url: '/uri-coinbase/:url',
needProfile: true,
views: {
'main': {
@ -504,12 +498,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
},
}
})
.state('warning', {
url: '/warning',
controller: 'warningController',
templateUrl: 'views/warning.html',
needProfile: false
})
.state('add', {
url: '/add',
needProfile: true,
@ -520,7 +508,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
});
})
.run(function($rootScope, $state, $log, $timeout, $ionicPlatform, uriHandler, platformInfo, profileService, uxLanguage, animationService, go, gettextCatalog) {
.run(function($rootScope, $state, $location, $log, $timeout, $ionicPlatform, platformInfo, profileService, uxLanguage, go, gettextCatalog) {
$ionicPlatform.ready(function() {
if (platformInfo.isCordova) {
@ -539,14 +527,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
});
$ionicPlatform.on('resume', function() {
if (!window.ignoreMobilePause) {
$rootScope.$emit('Local/Resume');
}
setTimeout(function() {
var loc = window.location;
var ignoreMobilePause = loc.toString().match(/(buy|sell|buycoinbase|sellcoinbase)/) ? true : false;
window.ignoreMobilePause = ignoreMobilePause;
}, 100);
$rootScope.$emit('Local/Resume');
});
$ionicPlatform.on('backbutton', function(event) {
@ -575,10 +556,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}, 100);
go.walletHome();
setTimeout(function() {
window.ignoreMobilePause = false;
}, 100);
});
$ionicPlatform.on('menubutton', function() {
@ -593,11 +570,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
uxLanguage.init();
// Register URI handler, not for mobileApp
if (!platformInfo.isMobile) {
uriHandler.register();
}
if (platformInfo.isNW) {
var gui = require('nw.gui');
var win = gui.Window.get();
@ -614,6 +586,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
$log.debug('Route change from:', fromState.name || '-', ' to:', toState.name);
$log.debug(' toParams:' + JSON.stringify(toParams || {}));
$log.debug(' fromParams:' + JSON.stringify(fromParams || {}));
if (!profileService.profile && toState.needProfile) {
@ -641,16 +615,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
if (profileService.focusedClient && !profileService.focusedClient.isComplete() && toState.walletShouldBeComplete) {
$state.transitionTo('copayers');
event.preventDefault();
}
}
if (!animationService.transitionAnimated(fromState, toState)) {
event.preventDefault();
// Time for the backpane to render
setTimeout(function() {
$state.transitionTo(toState);
}, 50);
}
});
});

View file

@ -1,163 +0,0 @@
'use strict';
angular.module('copayApp.services').factory('animationService', function(platformInfo) {
var root = {};
var cachedTransitionState, cachedBackPanel;
var isCordova = platformInfo.isCordova;
// DISABLE ANIMATION ON DESKTOP
root.modalAnimated = {
slideUp: isCordova ? 'full animated slideInUp' : 'full',
slideRight: isCordova ? 'full animated slideInRight' : 'full',
slideOutDown: isCordova ? 'slideOutDown' : 'hideModal',
slideOutRight: isCordova ? 'slideOutRight' : 'hideModal',
};
var pageWeight = {
walletHome: 0,
copayers: -1,
cordova: -1,
payment: -1,
uriglidera: -1,
preferences: 11,
preferencesGlobal: 11,
glidera: 11,
coinbase: 11,
preferencesColor: 12,
backup: 12,
preferencesAdvanced: 12,
buyGlidera: 12,
buyCoinbase: 12,
sellGlidera: 12,
sellCoinbase: 12,
preferencesGlidera: 12,
preferencesCoinbase: 12,
about: 12,
delete: 13,
preferencesLanguage: 12,
preferencesUnit: 12,
preferencesFee: 12,
preferencesAltCurrency: 12,
preferencesBwsUrl: 13,
preferencesHistory: 13,
preferencesAlias: 12,
preferencesEmail: 12,
export: 13,
paperWallet: 13,
logs: 13,
information: 13,
termOfUse: 13,
translators: 13,
add: 11,
buyandsell: 11,
create: 12,
join: 12,
import: 12,
importLegacy: 13
};
function cleanUpLater(e, e2) {
var cleanedUp = false,
timeoutID;
var cleanUp = function() {
if (cleanedUp) return;
cleanedUp = true;
e2.parentNode.removeChild(e2);
e2.innerHTML = "";
e.className = '';
cachedBackPanel = null;
cachedTransitionState = '';
if (timeoutID) {
timeoutID = null;
window.clearTimeout(timeoutID);
}
};
e.addEventListener("animationend", cleanUp, true);
e2.addEventListener("animationend", cleanUp, true);
e.addEventListener("webkitAnimationEnd", cleanUp, true);
e2.addEventListener("webkitAnimationEnd", cleanUp, true);
timeoutID = setTimeout(cleanUp, 500);
};
root.transitionAnimated = function(fromState, toState, event) {
if (isaosp)
return true;
// Animation in progress?
var x = document.getElementById('mainSectionDup');
if (x && !cachedTransitionState) {
console.log('Anim in progress');
return true;
}
var fromName = fromState.name;
var toName = toState.name;
if (!fromName || !toName)
return true;
var fromWeight = pageWeight[fromName];
var toWeight = pageWeight[toName];
var entering = null,
leaving = null;
// Horizontal Slide Animation?
if (isCordova && fromWeight && toWeight) {
if (fromWeight > toWeight) {
leaving = 'CslideOutRight';
} else {
entering = 'CslideInRight';
}
// Vertical Slide Animation?
} else if (isCordova && fromName && fromWeight >= 0 && toWeight >= 0) {
if (toWeight) {
entering = 'CslideInUp';
} else {
leaving = 'CslideOutDown';
}
// no Animation ?
} else {
return true;
}
var e = document.getElementById('mainSection');
var desiredTransitionState = (fromName || '-') + ':' + (toName || '-');
if (desiredTransitionState == cachedTransitionState) {
e.className = entering || '';
cachedBackPanel.className = leaving || '';
cleanUpLater(e, cachedBackPanel);
//console.log('USing animation', cachedTransitionState);
return true;
} else {
var sc;
// Keep prefDiv scroll
var contentDiv = e.getElementsByClassName('content');
if (contentDiv && contentDiv[0])
sc = contentDiv[0].scrollTop;
cachedBackPanel = e.cloneNode(true);
cachedBackPanel.id = 'mainSectionDup';
var c = document.getElementById('sectionContainer');
c.appendChild(cachedBackPanel);
if (sc)
cachedBackPanel.getElementsByClassName('content')[0].scrollTop = sc;
cachedTransitionState = desiredTransitionState;
return false;
}
}
return root;
});

View file

@ -48,15 +48,15 @@ angular.module('copayApp.services').factory('go', function($window, $ionicSideMe
};
root.addWallet = function() {
$state.go('add');
$state.transitionTo('add');
};
root.preferences = function() {
$state.go('preferences');
$state.transitionTo('preferences');
};
root.preferencesGlobal = function() {
$state.go('preferencesGlobal');
$state.transitionTo('preferencesGlobal');
};
root.reload = function() {

View file

@ -1,146 +0,0 @@
'use strict';
angular.module('copayApp.services')
.factory('legacyImportService', function($rootScope, $log, $timeout, $http, lodash, bitcore, bwcService, sjcl, profileService, platformInfo) {
var root = {};
var wc = bwcService.getClient();
root.getKeyForEmail = function(email) {
var hash = bitcore.crypto.Hash.sha256ripemd160(new bitcore.deps.Buffer(email)).toString('hex');
$log.debug('Storage key:' + hash);
return 'profile::' + hash;
};
root.getKeyForWallet = function(id) {
return 'wallet::' + id;
};
root._importOne = function(user, pass, walletId, get, cb) {
get(root.getKeyForWallet(walletId), function(err, blob) {
if (err) {
$log.warn('Could not fetch wallet: ' + walletId + ":" + err);
return cb('Could not fetch ' + walletId);
}
profileService.importLegacyWallet(user, pass, blob, cb);
});
};
root._doImport = function(user, pass, get, cb) {
var self = this;
get(root.getKeyForEmail(user), function(err, p) {
if (err || !p)
return cb(err || ('Could not find profile for ' + user));
var ids = wc.getWalletIdsFromOldCopay(user, pass, p);
if (!ids)
return cb('Could not find wallets on the profile');
$rootScope.$emit('Local/ImportStatusUpdate',
'Found ' + ids.length + ' wallets to import:' + ids.join());
$log.info('Importing Wallet Ids:', ids);
var i = 0;
var okIds = [];
var toScanIds = [];
lodash.each(ids, function(walletId) {
$timeout(function() {
$rootScope.$emit('Local/ImportStatusUpdate',
'Importing wallet ' + walletId + ' ... ');
self._importOne(user, pass, walletId, get, function(err, id, name, existed) {
if (err) {
$rootScope.$emit('Local/ImportStatusUpdate',
'Failed to import wallet ' + (name || walletId));
} else {
okIds.push(walletId);
$rootScope.$emit('Local/ImportStatusUpdate',
'Wallet ' + id + '[' + name + '] imported successfully');
if (!existed) {
$log.info('Wallet ' + walletId + ' was created. need to be scanned');
toScanIds.push(id);
}
}
if (++i == ids.length) {
return cb(null, okIds, toScanIds);
}
});
}, 100);
});
});
};
root.import = function(user, pass, serverURL, fromCloud, cb) {
var insightGet = function(key, cb) {
var kdfbinary = function(password, salt, iterations, length) {
iterations = iterations || defaultIterations;
length = length || 512;
salt = sjcl.codec.base64.toBits(salt || defaultSalt);
var hash = sjcl.hash.sha256.hash(sjcl.hash.sha256.hash(password));
var prff = function(key) {
return new sjcl.misc.hmac(hash, sjcl.hash.sha1);
};
return sjcl.misc.pbkdf2(hash, salt, iterations, length, prff);
};
var salt = 'jBbYTj8zTrOt6V';
var iter = 1000;
var SEPARATOR = '|';
var kdfb = kdfbinary(pass + SEPARATOR + user, salt, iter);
var kdfb64 = sjcl.codec.base64.fromBits(kdfb);
var keyBuf = new bitcore.deps.Buffer(kdfb64);
var passphrase = bitcore.crypto.Hash.sha256sha256(keyBuf).toString('base64');
var authHeader = new bitcore.deps.Buffer(user + ':' + passphrase).toString('base64');
var retrieveUrl = serverURL + '/retrieve';
var getParams = {
method: 'GET',
url: retrieveUrl + '?key=' + encodeURIComponent(key) + '&rand=' + Math.random(),
headers: {
'Authorization': authHeader,
},
};
$log.debug('Insight GET', getParams);
$http(getParams)
.success(function(data) {
data = JSON.stringify(data);
$log.info('Fetch from insight OK:' + getParams.url);
return cb(null, data);
})
.error(function() {
$log.warn('Failed to fetch from insight');
return cb('PNOTFOUND: Profile not found');
});
};
var localStorageGet = function(key, cb) {
if (platformInfo.isChromeApp) {
chrome.storage.local.get(key,
function(data) {
return cb(null, data[key]);
});
} else {
var v = localStorage.getItem(key);
return cb(null, v);
}
};
var get = fromCloud ? insightGet : localStorageGet;
root._doImport(user, pass, get, cb);
};
return root;
});

114
src/js/services/openURL.js Normal file
View file

@ -0,0 +1,114 @@
'use strict';
angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, go, platformInfo, lodash, profileService) {
var root = {};
root.registeredUriHandlers = [{
name: 'Bitcoin BIP21 URL',
startsWith: 'bitcoin:',
transitionTo: 'uripayment',
}, {
name: 'Glidera Authentication Callback',
startsWith: 'copay:glidera',
transitionTo: 'uriglidera',
}, {
name: 'Coinbase Authentication Callback',
startsWith: 'copay:coinbase',
transitionTo: 'uricoinbase',
}];
var handleOpenURL = function(args) {
$log.info('Handling Open URL: ' + JSON.stringify(args));
if (!profileService.isBound) {
$log.warn('Profile not bound yet. Waiting');
return $rootScope.$on('Local/ProfileBound', function() {
// Wait ux to settle
setTimeout(function() {
$log.warn('Profile ready, retrying...');
handleOpenURL(args);
}, 2000);
});
};
// Stop it from caching the first view as one to return when the app opens
$ionicHistory.nextViewOptions({
historyRoot: true,
disableBack: true,
disableAnimation: true
});
var url = args.url;
if (!url) {
$log.error('No url provided');
return;
};
if (url) {
if ('cordova' in window) {
window.cordova.removeDocumentEventHandler('handleopenurl');
window.cordova.addStickyDocumentEventHandler('handleopenurl');
}
document.removeEventListener('handleopenurl', handleOpenURL);
}
document.addEventListener('handleopenurl', handleOpenURL, false);
var x = lodash.find(root.registeredUriHandlers, function(x) {
return url.indexOf(x.startsWith) == 0 ||
url.indexOf('web+' + x.startsWith) == 0 || // web protocols
url.indexOf(x.startsWith.replace(':', '://')) == 0 // from mobile devices
;
});
if (x) {
$log.debug('openURL GOT ' + x.name + ' URL');
return $state.transitionTo(x.transitionTo, {
url: url
});
} else {
$log.warn('Unknown URL! : ' + url);
}
};
var handleResume = function() {
$log.debug('Handle Resume @ openURL...');
document.addEventListener('handleopenurl', handleOpenURL, false);
};
root.init = function() {
$log.debug('Initializing openURL');
document.addEventListener('handleopenurl', handleOpenURL, false);
document.addEventListener('resume', handleResume, false);
if (platformInfo.isChromeApp) {
$log.debug('Registering Chrome message listener');
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.url) {
handleOpenURL(request.url);
}
});
} else if (platformInfo.isDevel) {
var base = window.location.origin + '/';
var url = base + '#/uri/%s';
if (navigator.registerProtocolHandler) {
$log.debug('Registering Browser handlers base:' + base);
navigator.registerProtocolHandler('bitcoin', url, 'Copay Bitcoin Handler');
navigator.registerProtocolHandler('web+copay', url, 'Copay Wallet Handler');
}
}
};
root.registerHandler = function(x) {
$log.debug('Registering URL Handler: ' + x.name);
root.registeredUriHandlers.push(x);
};
root.handleURL = handleOpenURL;
return root;
});

View file

@ -123,9 +123,9 @@ angular.module('copayApp.services')
// Used when reading wallets from the profile
root.bindWallet = function(credentials) {
root.bindWallet = function(credentials, cb) {
if (!credentials.walletId)
throw 'bindWallet should receive credentials JSON';
return cb('bindWallet should receive credentials JSON');
// Create the client
@ -136,16 +136,21 @@ angular.module('copayApp.services')
};
var skipKeyValidation = root.profile.isChecked(platformInfo.ua, credentials.walletId);
$log.info('Binding wallet:' + credentials.walletId + ' Validating?:' + !skipKeyValidation);
var client = bwcService.getClient(JSON.stringify(credentials), {
bwsurl: getBWSURL(credentials.walletId),
skipKeyValidation: skipKeyValidation,
});
if (!skipKeyValidation) {
$rootScope.$emit('Local/ValidatingWallet');
}
$timeout(function() {
$log.info('Binding wallet:' + credentials.walletId + ' Validating?:' + !skipKeyValidation);
var client = bwcService.getClient(JSON.stringify(credentials), {
bwsurl: getBWSURL(credentials.walletId),
skipKeyValidation: skipKeyValidation,
});
if (!skipKeyValidation && !client.incorrectDerivation)
root.profile.setChecked(platformInfo.ua, credentials.walletId);
if (!skipKeyValidation && !client.incorrectDerivation)
root.profile.setChecked(platformInfo.ua, credentials.walletId);
return root.bindWalletClient(client);
return cb(null, root.bindWalletClient(client));
}, skipKeyValidation ? 50 : 0);
};
root.bindProfile = function(profile, cb) {
@ -155,23 +160,44 @@ angular.module('copayApp.services')
$log.debug('Preferences read');
if (err) return cb(err);
lodash.each(root.profile.credentials, function(credentials) {
root.bindWallet(credentials);
});
$rootScope.$emit('Local/WalletListUpdated');
function bindWallets(cb) {
var l = root.profile.credentials.length;
var i = 0, totalBound = 0;
storageService.getFocusedWalletId(function(err, focusedWalletId) {
if (err) return cb(err);
root._setFocus(focusedWalletId, function() {
if (usePushNotifications)
root.pushNotificationsInit();
root.isDisclaimerAccepted(function(val) {
if (!val) {
return cb(new Error('NONAGREEDDISCLAIMER: Non agreed disclaimer'));
if (!l) return cb();
lodash.each(root.profile.credentials, function(credentials) {
root.bindWallet(credentials, function(err, bound) {
i++;
totalBound += bound;
if (i == l) {
$log.info('Bound ' + totalBound + ' out of ' + l + ' wallets');
if (totalBound)
$rootScope.$emit('Local/WalletListUpdated');
return cb();
}
return cb();
});
});
}
bindWallets(function() {
storageService.getFocusedWalletId(function(err, focusedWalletId) {
if (err) return cb(err);
root._setFocus(focusedWalletId, function() {
if (usePushNotifications)
root.pushNotificationsInit();
root.isBound = true;
$rootScope.$emit('Local/ProfileBound');
root.isDisclaimerAccepted(function(val) {
if (!val) {
return cb(new Error('NONAGREEDDISCLAIMER: Non agreed disclaimer'));
}
return cb();
});
});
})
});
});
};
@ -182,7 +208,6 @@ angular.module('copayApp.services')
push.on('notification', function(data) {
if (!data.additionalData.foreground) {
window.ignoreMobilePause = true;
$log.debug('Push notification event: ', data.message);
$timeout(function() {
@ -288,22 +313,23 @@ angular.module('copayApp.services')
// Creates a wallet on BWC/BWS
var doCreateWallet = function(opts, cb) {
$log.debug('Creating Wallet:', opts);
seedWallet(opts, function(err, walletClient) {
if (err) return cb(err);
$timeout(function() {
seedWallet(opts, function(err, walletClient) {
if (err) return cb(err);
var name = opts.name || gettextCatalog.getString('Personal Wallet');
var myName = opts.myName || gettextCatalog.getString('me');
var name = opts.name || gettextCatalog.getString('Personal Wallet');
var myName = opts.myName || gettextCatalog.getString('me');
console.log('[profileService.js.303]', opts); //TODO
walletClient.createWallet(name, myName, opts.m, opts.n, {
network: opts.networkName,
singleAddress: opts.singleAddress,
walletPrivKey: opts.walletPrivKey,
}, function(err, secret) {
if (err) return bwsError.cb(err, gettext('Error creating wallet'), cb);
return cb(null, walletClient, secret);
walletClient.createWallet(name, myName, opts.m, opts.n, {
network: opts.networkName,
singleAddress: opts.singleAddress,
walletPrivKey: opts.walletPrivKey,
}, function(err, secret) {
if (err) return bwsError.cb(err, gettext('Error creating wallet'), cb);
return cb(null, walletClient, secret);
});
});
});
}, 5);
};
// Creates the default Copay profile and its wallet
@ -347,8 +373,8 @@ console.log('[profileService.js.303]', opts); //TODO
// check if exist
if (lodash.find(root.profile.credentials, {
'walletId': walletData.walletId
})) {
'walletId': walletData.walletId
})) {
return cb(gettext('Cannot join the same wallet more that once'));
}
} catch (ex) {
@ -612,7 +638,6 @@ console.log('[profileService.js.303]', opts); //TODO
var defaults = configService.getDefaults();
configService.get(function(err) {
root.createDefaultProfile(opts, function(err, p) {
if (err) return cb(err);
@ -649,23 +674,6 @@ console.log('[profileService.js.303]', opts); //TODO
});
};
root.importLegacyWallet = function(username, password, blob, cb) {
var walletClient = bwcService.getClient();
walletClient.createWalletFromOldCopay(username, password, blob, function(err, existed) {
if (err) return cb(gettext('Error importing wallet: ') + err);
if (root.profile.hasWallet(walletClient.credentials.walletId)) {
$log.debug('Wallet:' + walletClient.credentials.walletName + ' already imported');
return cb(gettext('Wallet Already Imported: ') + walletClient.credentials.walletName);
};
root.addAndBindWalletClient(walletClient, {
isImport: true
}, cb);
});
};
root.updateCredentials = function(credentials, cb) {
root.profile.updateWallet(credentials);
storageService.storeProfileThrottled(root.profile, cb);
@ -698,7 +706,7 @@ console.log('[profileService.js.303]', opts); //TODO
});
};
root.getWallets = function(network) {
root.getWallets = function(network, n) {
if (!root.profile) return [];
var config = configService.getSync();
@ -720,6 +728,12 @@ console.log('[profileService.js.303]', opts); //TODO
return (w.network == network);
});
}
if (n) {
ret = lodash.filter(ret, function(w) {
return (w.n == n);
});
}
return lodash.sortBy(ret, 'name');
};

View file

@ -1,14 +0,0 @@
'use strict';
var UriHandler = function() {};
UriHandler.prototype.register = function() {
var base = window.location.origin + '/';
var url = base + '#/uri-payment/%s';
if(navigator.registerProtocolHandler) {
navigator.registerProtocolHandler('bitcoin', url, 'Copay');
}
};
angular.module('copayApp.services').value('uriHandler', new UriHandler());

View file

@ -1701,15 +1701,14 @@ a.missing-copayers {
padding: 1rem 0.7rem;
font-size: 12px;
font-weight: 300;
color: #A5B2BF;
cursor: pointer !important;
}
.sidebar ul {
margin: 0 0 30px 0;
}
.sidebar a {
color: #A5B2BF;
}
.modal-content ul li a {
font-size: 12px;

View file

@ -221,7 +221,6 @@ mocks.init = function(fixtures, controllerName, opts, done) {
done();
});
} else {
_profileService_.create({
noWallet: true
}, function(err) {