fix merge conflicts

This commit is contained in:
Marty Alcala 2016-11-15 11:01:30 -05:00
commit 64d81c55ba
47 changed files with 1039 additions and 410 deletions

View File

@ -145,6 +145,12 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi
updateHistoryFromCache(function() {
self.update();
});
bitpayCardService.getBitpayDebitCards(function(err, cards) {
if (err) return;
$scope.card = lodash.find(cards, function(card) {
return card.eid == $scope.cardId;
});
});
}
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('thanksController', function($scope, $stateParams, $timeout, $log, platformInfo, configService, storageService) {
angular.module('copayApp.controllers').controller('completeController', function($scope, $stateParams, $timeout, $log, platformInfo, configService, storageService) {
$scope.score = parseInt($stateParams.score);
$scope.skipped = $stateParams.skipped == 'false' ? false : true;
$scope.isCordova = platformInfo.isCordova;
@ -31,7 +31,12 @@ angular.module('copayApp.controllers').controller('thanksController', function($
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
storageService.setRateCardFlag('true', function() {});
storageService.getFeedbackInfo(function(error, info) {
var feedbackInfo = JSON.parse(info);
feedbackInfo.sent = true;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {});
});
if (!$scope.isCordova) return;
window.plugins.socialsharing.available(function(isAvailable) {

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('rateAppStoreController', function($scope, $state, $stateParams, externalLinkService, configService, gettextCatalog, platformInfo) {
angular.module('copayApp.controllers').controller('rateAppController', function($scope, $state, $stateParams, lodash, externalLinkService, configService, gettextCatalog, platformInfo, feedbackService, ongoingProcess) {
$scope.score = parseInt($stateParams.score);
var isAndroid = platformInfo.isAndroid;
var isIOS = platformInfo.isIOS;
@ -8,14 +8,29 @@ angular.module('copayApp.controllers').controller('rateAppStoreController', func
var config = configService.getSync();
$scope.skip = function() {
$state.go('feedback.thanks', {
score: $scope.score,
skipped: true
var dataSrc = {
"Email": lodash.values(config.emailFor)[0] || ' ',
"Feedback": ' ',
"Score": $stateParams.score
};
ongoingProcess.set('sendingFeedback', true);
feedbackService.send(dataSrc, function(err) {
ongoingProcess.set('sendingFeedback', false);
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not send feedback'));
return;
}
$state.go('feedback.complete', {
score: $stateParams.score,
skipped: true
});
});
};
$scope.sendFeedback = function() {
$state.go('feedback.sendFeedback', {
$state.go('feedback.send', {
score: $scope.score
});
};

View File

@ -3,6 +3,7 @@
angular.module('copayApp.controllers').controller('rateCardController', function($scope, $state, $timeout, gettextCatalog, platformInfo, storageService) {
$scope.isCordova = platformInfo.isCordova;
$scope.score = 0;
$scope.goFeedbackFlow = function() {
if ($scope.isModal) {
@ -10,11 +11,11 @@ angular.module('copayApp.controllers').controller('rateCardController', function
$scope.rateModal.remove();
}
if ($scope.isCordova && $scope.score == 5) {
$state.go('feedback.rateAppStore', {
$state.go('feedback.rateApp', {
score: $scope.score
});
} else {
$state.go('feedback.sendFeedback', {
$state.go('feedback.send', {
score: $scope.score
});
}
@ -49,13 +50,17 @@ angular.module('copayApp.controllers').controller('rateCardController', function
$scope.rateModal.hide();
$scope.rateModal.remove();
} else {
storageService.setRateCardFlag('true', function() {
$scope.hideRateCard.value = true;
storageService.getFeedbackInfo(function(error, info) {
var feedbackInfo = JSON.parse(info);
feedbackInfo.sent = true;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {
$scope.showRateCard.value = false;
});
});
}
$timeout(function() {
$scope.$apply();
})
}, 100);
}
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('sendFeedbackController', function($scope, $state, $log, $stateParams, gettextCatalog, popupService, configService, lodash, feedbackService, ongoingProcess) {
angular.module('copayApp.controllers').controller('sendController', function($scope, $state, $log, $stateParams, gettextCatalog, popupService, configService, lodash, feedbackService, ongoingProcess) {
$scope.score = parseInt($stateParams.score);
switch ($scope.score) {
case 1:
@ -42,7 +42,7 @@ angular.module('copayApp.controllers').controller('sendFeedbackController', func
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not send feedback'));
return;
}
$state.go('feedback.thanks', {
$state.go('feedback.complete', {
score: $stateParams.score,
skipped: skip
});

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('headController',
function($scope, $window, $log, glideraService) {
function($scope, $window, $log) {
$scope.appConfig = $window.appConfig;
$log.info('Running head controller:' + $window.appConfig.nameCase)
});

View File

@ -19,13 +19,7 @@ angular.module('copayApp.controllers').controller('welcomeController', function(
$log.debug('Creating profile');
profileService.createProfile(function(err) {
if (err) $log.warn(err);
setProfileCreationTime();
});
};
function setProfileCreationTime() {
var now = moment().unix() * 1000 + 24 * 60 * 60 * 1000;
storageService.setProfileCreationTime(now, function() {});
};
});

View File

@ -3,16 +3,16 @@
angular.module('copayApp.controllers').controller('preferencesBitpayCardController',
function($scope, $state, $timeout, $ionicHistory, bitpayCardService, popupService, gettextCatalog) {
$scope.remove = function() {
$scope.remove = function(card) {
var msg = gettextCatalog.getString('Are you sure you would like to remove your BitPay Card account from this device?');
popupService.showConfirm(null, msg, null, null, function(res) {
if (res) remove();
if (res) remove(card);
});
};
var remove = function() {
bitpayCardService.remove(function() {
$ionicHistory.removeBackView();
var remove = function(card) {
bitpayCardService.remove(card, function() {
$ionicHistory.clearHistory();
$timeout(function() {
$state.go('tabs.home');
}, 100);
@ -22,7 +22,7 @@ angular.module('copayApp.controllers').controller('preferencesBitpayCardControll
$scope.$on("$ionicView.beforeEnter", function(event, data) {
bitpayCardService.getBitpayDebitCards(function(err, data) {
if (err) return;
$scope.bitpayCards = data.cards;
$scope.bitpayCards = data;
});
});

View File

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('tabHomeController',
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, $window, bitpayCardService, startupService, addressbookService) {
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, $window, bitpayCardService, startupService, addressbookService, feedbackService) {
var wallet;
var listeners = [];
var notifications = [];
@ -13,7 +13,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.isCordova = platformInfo.isCordova;
$scope.isAndroid = platformInfo.isAndroid;
$scope.isNW = platformInfo.isNW;
$scope.hideRateCard = {};
$scope.showRateCard = {};
$scope.$on("$ionicView.afterEnter", function() {
startupService.ready();
@ -37,13 +37,37 @@ angular.module('copayApp.controllers').controller('tabHomeController',
});
}
storageService.getProfileCreationTime(function(error, time) {
var now = moment().unix() * 1000;
storageService.getRateCardFlag(function(error, value) {
$scope.hideRateCard.value = (value == 'true' || (time - now) > 0) ? true : false;
});
storageService.getFeedbackInfo(function(error, info) {
if (!info) {
initFeedBackInfo();
} else {
var feedbackInfo = JSON.parse(info);
//Check if current version is greater than saved version
var currentVersion = window.version;
var savedVersion = feedbackInfo.version;
var isVersionUpdated = feedbackService.isVersionUpdated(currentVersion, savedVersion);
if (!isVersionUpdated) {
initFeedBackInfo();
return;
}
var now = moment().unix();
var timeExceeded = (now - feedbackInfo.time) >= 24 * 60 * 60;
$scope.showRateCard.value = timeExceeded && !feedbackInfo.sent;
$timeout(function() {
$scope.$apply();
});
}
});
function initFeedBackInfo() {
var feedbackInfo = {};
feedbackInfo.time = moment().unix();
feedbackInfo.version = window.version;
feedbackInfo.sent = false;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {
$scope.showRateCard.value = false;
});
};
});
$scope.$on("$ionicView.enter", function(event, data) {
@ -102,12 +126,6 @@ angular.module('copayApp.controllers').controller('tabHomeController',
});
});
$scope.$on("$ionicView.leave", function(event, data) {
lodash.each(listeners, function(x) {
x();
});
});
$scope.openExternalLink = function(url, optIn, title, message, okText, cancelText) {
externalLinkService.open(url, optIn, title, message, okText, cancelText);
};
@ -178,8 +196,11 @@ angular.module('copayApp.controllers').controller('tabHomeController',
lodash.each($scope.wallets, function(wallet) {
walletService.getStatus(wallet, {}, function(err, status) {
if (err) {
if (err === 'WALLET_NOT_REGISTERED') wallet.error = gettextCatalog.getString('Wallet not registered');
else wallet.error = gettextCatalog.getString('Could not update');;
$log.error(err);
} else {
wallet.error = null;
wallet.status = status;
}
if (++j == i) {
@ -231,7 +252,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
var services = ['AmazonGiftCards', 'BitpayCard', 'BuyAndSell'];
lodash.each(services, function(service) {
storageService.getNextStep(service, function(err, value) {
$scope.externalServices[service] = value ? true : false;
$scope.externalServices[service] = value == 'true' ? true : false;
if (++i == services.length) return cb();
});
});
@ -252,7 +273,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.bitpayCards = null;
return;
}
$scope.bitpayCards = data.cards;
$scope.bitpayCards = data;
});
bitpayCardService.getBitpayDebitCardsHistory(null, function(err, data) {
if (err) return;

View File

@ -1,9 +1,11 @@
'use strict';
angular.module('copayApp.controllers').controller('tabReceiveController', function($scope, $timeout, $log, $ionicModal, $state, $ionicHistory, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService) {
angular.module('copayApp.controllers').controller('tabReceiveController', function($rootScope, $scope, $timeout, $log, $ionicModal, $state, $ionicHistory, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService, bwcError) {
var listeners = [];
$scope.isCordova = platformInfo.isCordova;
$scope.isNW = platformInfo.isNW;
$scope.walletAddrs = {};
$scope.shareAddress = function(addr) {
if ($scope.generatingAddress) return;
@ -18,14 +20,21 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.generatingAddress = true;
walletService.getAddress($scope.wallet, forceNew, function(err, addr) {
$scope.generatingAddress = false;
if (err) popupService.showAlert(gettextCatalog.getString('Error'), err);
if (err) popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err));
$scope.addr = addr;
if ($scope.walletAddrs[$scope.wallet.id]) $scope.walletAddrs[$scope.wallet.id] = addr;
$timeout(function() {
$scope.$apply();
}, 10);
});
};
$scope.loadAddresses = function(wallet, index) {
walletService.getAddress(wallet, false, function(err, addr) {
$scope.walletAddrs[wallet.id] = addr;
});
}
$scope.goCopayers = function() {
$ionicHistory.removeBackView();
$ionicHistory.nextViewOptions({
@ -67,6 +76,24 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
});
};
$scope.setWallet = function(index) {
$scope.wallet = $scope.wallets[index];
$scope.walletIndex = index;
if ($scope.walletAddrs[$scope.walletIndex].addr) $scope.addr = $scope.walletAddrs[$scope.walletIndex].addr;
else $scope.setAddress(false);
}
$scope.isActive = function(index) {
return $scope.wallets[index] == $scope.wallet;
}
$scope.walletPosition = function(index) {
if (index == $scope.walletIndex) return 'current';
if (index < $scope.walletIndex) return 'prev';
if (index > $scope.walletIndex) return 'next';
}
$scope.$on('Wallet/Changed', function(event, wallet) {
if (!wallet) {
$log.debug('No wallet provided');
@ -77,14 +104,57 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
return;
}
$scope.wallet = wallet;
$scope.generatingAddress = false;
$log.debug('Wallet changed: ' + wallet.name);
$scope.walletIndex = lodash.findIndex($scope.wallets, function(wallet) {
return wallet.id == $scope.wallet.id;
});
if (!$scope.walletAddrs[wallet.id]) $scope.setAddress(false);
else $scope.addr = $scope.walletAddrs[wallet.id];
$timeout(function() {
$scope.setAddress(false);
$scope.$apply();
}, 100);
});
$scope.updateCurrentWallet = function() {
walletService.getStatus($scope.wallet, {}, function(err, status) {
if (err) {
$log.error(err);
}
$timeout(function() {
$scope.wallet = profileService.getWallet($scope.wallet.id);
$scope.wallet.status = status;
$scope.setAddress();
$scope.$apply();
}, 200);
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.wallets = profileService.getWallets();
lodash.each($scope.wallets, function(wallet, index) {
$scope.loadAddresses(wallet);
});
listeners = [
$rootScope.$on('bwsEvent', function(e, walletId, type, n) {
// Update current address
if ($scope.wallet && walletId == $scope.wallet.id) $scope.updateCurrentWallet();
})
];
// Update current wallet
if ($scope.wallet) $scope.updateCurrentWallet();
});
$scope.$on("$ionicView.leave", function(event, data) {
lodash.each(listeners, function(x) {
x();
});
});
});

View File

@ -49,7 +49,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
var updateStatus = function(force) {
$scope.updatingStatus = true;
$scope.updateStatusError = false;
$scope.updateStatusError = null;
$scope.walletNotRegistered = false;
walletService.getStatus($scope.wallet, {
@ -60,18 +60,16 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
if (err === 'WALLET_NOT_REGISTERED') {
$scope.walletNotRegistered = true;
} else {
$scope.updateStatusError = true;
$scope.updateStatusError = err;
}
$scope.status = null;
return;
} else {
setPendingTxps(status.pendingTxps);
$scope.status = status;
}
setPendingTxps(status.pendingTxps);
$scope.status = status;
$timeout(function() {
$scope.$apply();
}, 1);
});
});
};
@ -114,6 +112,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
if (err) return;
$timeout(function() {
walletService.startScan($scope.wallet, function() {
$scope.updateAll();
$scope.$apply();
});
});

View File

@ -739,30 +739,30 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
abstract: true,
template: '<ion-nav-view name="feedback"></ion-nav-view>'
})
.state('feedback.sendFeedback', {
url: '/sendFeedback/:score',
.state('feedback.send', {
url: '/send/:score',
views: {
'feedback': {
controller: 'sendFeedbackController',
templateUrl: 'views/feedback/sendFeedback.html'
controller: 'sendController',
templateUrl: 'views/feedback/send.html'
}
}
})
.state('feedback.thanks', {
url: '/thanks/:score/:skipped',
.state('feedback.complete', {
url: '/complete/:score/:skipped',
views: {
'feedback': {
controller: 'thanksController',
templateUrl: 'views/feedback/thanks.html'
controller: 'completeController',
templateUrl: 'views/feedback/complete.html'
}
}
})
.state('feedback.rateAppStore', {
url: '/rateAppStore/:score',
.state('feedback.rateApp', {
url: '/rateApp/:score',
views: {
'feedback': {
controller: 'rateAppStoreController',
templateUrl: 'views/feedback/rateAppStore.html'
controller: 'rateAppController',
templateUrl: 'views/feedback/rateApp.html'
}
}
})
@ -1009,41 +1009,50 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
});
}
$log.info('Init profile...');
// Try to open local profile
profileService.loadAndBindProfile(function(err) {
$ionicHistory.nextViewOptions({
disableAnimate: true
});
$log.info('Verifying storage...');
storageService.verify(function(err) {
if (err) {
if (err.message && err.message.match('NOPROFILE')) {
$log.debug('No profile... redirecting');
$state.go('onboarding.welcome');
} else if (err.message && err.message.match('NONAGREEDDISCLAIMER')) {
if (lodash.isEmpty(profileService.getWallets())) {
$log.debug('No wallets and no disclaimer... redirecting');
$state.go('onboarding.welcome');
} else {
$log.debug('Display disclaimer... redirecting');
$state.go('onboarding.disclaimer', {
resume: true
});
}
} else {
throw new Error(err); // TODO
}
$log.error('Storage failed to verify: ' + err);
// TODO - what next?
} else {
profileService.storeProfileIfDirty();
$log.debug('Profile loaded ... Starting UX.');
scannerService.gentleInitialize();
$state.go('tabs.home');
$log.info('Storage OK');
}
// After everything have been loaded, initialize handler URL
$timeout(function() {
openURLService.init();
}, 1000);
$log.info('Init profile...');
// Try to open local profile
profileService.loadAndBindProfile(function(err) {
$ionicHistory.nextViewOptions({
disableAnimate: true
});
if (err) {
if (err.message && err.message.match('NOPROFILE')) {
$log.debug('No profile... redirecting');
$state.go('onboarding.welcome');
} else if (err.message && err.message.match('NONAGREEDDISCLAIMER')) {
if (lodash.isEmpty(profileService.getWallets())) {
$log.debug('No wallets and no disclaimer... redirecting');
$state.go('onboarding.welcome');
} else {
$log.debug('Display disclaimer... redirecting');
$state.go('onboarding.disclaimer', {
resume: true
});
}
} else {
throw new Error(err); // TODO
}
} else {
profileService.storeProfileIfDirty();
$log.debug('Profile loaded ... Starting UX.');
scannerService.gentleInitialize();
$state.go('tabs.home');
}
// After everything have been loaded, initialize handler URL
$timeout(function() {
openURLService.init();
}, 1000);
});
});
});

View File

@ -174,7 +174,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
if (err) return cb(err);
root.getBitpayDebitCards(function(err, data) {
if (err) return cb(err);
var card = lodash.find(data.cards, {id : cardId});
var card = lodash.find(data, {id : cardId});
if (!card) return cb(_setError('Not card found'));
// Get invoices
$http(_post('/api/v2/' + card.token, json, credentials)).then(function(data) {
@ -211,7 +211,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
if (err) return cb(err);
root.getBitpayDebitCards(function(err, data) {
if (err) return cb(err);
var card = lodash.find(data.cards, {id : cardId});
var card = lodash.find(data, {id : cardId});
if (!card) return cb(_setError('Not card found'));
$http(_post('/api/v2/' + card.token, json, credentials)).then(function(data) {
$log.info('BitPay TopUp: SUCCESS');
@ -288,13 +288,11 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
});
};
root.remove = function(cb) {
storageService.removeBitpayCardCredentials(BITPAY_CARD_NETWORK, function(err) {
storageService.removeBitpayDebitCards(BITPAY_CARD_NETWORK, function(err) {
storageService.removeBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err) {
$log.info('BitPay Debit Cards Removed: SUCCESS');
return cb();
});
root.remove = function(card, cb) {
storageService.removeBitpayDebitCard(BITPAY_CARD_NETWORK, card, function(err) {
storageService.removeBitpayDebitCardHistory(BITPAY_CARD_NETWORK, card, function(err) {
$log.info('BitPay Debit Card(s) Removed: SUCCESS');
return cb();
});
});
};

View File

@ -24,5 +24,35 @@ angular.module('copayApp.services').factory('feedbackService', function($http, $
};
};
root.isVersionUpdated = function(currentVersion, savedVersion) {
if (!verifyTagFormat(currentVersion))
return 'Cannot verify the format of version tag: ' + currentVersion;
if (!verifyTagFormat(savedVersion))
return 'Cannot verify the format of the saved version tag: ' + savedVersion;
var current = formatTagNumber(currentVersion);
var saved = formatTagNumber(savedVersion);
if (saved.major > current.major || (saved.major == current.major && saved.minor > current.minor))
return false;
return true;
function verifyTagFormat(tag) {
var regex = /^v?\d+\.\d+\.\d+$/i;
return regex.exec(tag);
};
function formatTagNumber(tag) {
var formattedNumber = tag.replace(/^v/i, '').split('.');
return {
major: +formattedNumber[0],
minor: +formattedNumber[1],
patch: +formattedNumber[2]
};
};
};
return root;
});

View File

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services')
.factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo) {
.factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, $timeout) {
var root = {};
@ -74,7 +74,90 @@ angular.module('copayApp.services')
});
};
////////////////////////////////////////////////////////////////////////////
//
// UPGRADING STORAGE
//
// 1. Write a function to upgrade the desired storage key(s). The function should have the protocol:
//
// _upgrade_x(key, network, cb), where:
//
// `x` is the name of the storage key
// `key` is the name of the storage key being upgraded
// `network` is one of 'livenet', 'testnet'
//
// 2. Add the storage key to `_upgraders` object using the name of the key as the `_upgrader` object key
// with the value being the name of the upgrade function (e.g., _upgrade_x). In order to avoid conflicts
// when a storage key is involved in multiple upgraders as well as predicte the order in which upgrades
// occur the `_upgrader` object key should be prefixed with '##_' (e.g., '01_') to create a unique and
// sortable name. This format is interpreted by the _upgrade() function.
//
// Upgraders are executed in numerical order per the '##_' object key prefix.
//
var _upgraders = {
'00_bitpayDebitCards' : _upgrade_bitpayDebitCards // 2016-11: Upgrade bitpayDebitCards-x to bitpayAccounts-x
};
function _upgrade_bitpayDebitCards(key, network, cb) {
key += '-' + network;
storage.get(key, function(err, data) {
if (err) return cb(err);
if (data != null) {
// Needs upgrade
if (lodash.isString(data)) {
data = JSON.parse(data);
}
data = data || {};
root.setBitpayDebitCards(network, data, function(err) {
if (err) return cb(err);
storage.remove(key, function() {
cb(null, 'replaced with \'bitpayAccounts\'');
});
});
} else {
cb();
}
});
};
//
////////////////////////////////////////////////////////////////////////////
// IMPORTANT: This function is designed to block execution until it completes.
// Ideally storage should not be used until it has been verified.
root.verify = function(cb) {
_upgrade(function(err) {
cb(err);
});
};
function _handleUpgradeError(key, err) {
$log.error('Failed to upgrade storage for \'' + key + '\': ' + err);
};
function _handleUpgradeSuccess(key, msg) {
$log.info('Storage upgraded for \'' + key + '\': ' + msg);
};
function _upgrade(cb) {
var errorCount = 0;
var errorMessage = undefined;
var keys = Object.keys(_upgraders).sort();
var networks = ['livenet', 'testnet'];
keys.forEach(function(key) {
networks.forEach(function(network) {
var storagekey = key.split('_')[1];
_upgraders[key](storagekey, network, function(err, msg) {
if (err) {
_handleUpgradeError(storagekey, err);
errorCount++;
errorMessage = errorCount + ' storage upgrade failures';
}
if (msg) _handleUpgradeSuccess(storagekey, msg);
});
});
});
cb(errorMessage);
};
root.tryToMigrate = function(cb) {
if (!shouldUseFileStorage) return cb();
@ -138,12 +221,12 @@ angular.module('copayApp.services')
storage.remove('profile', cb);
};
root.setProfileCreationTime = function(time, cb) {
storage.set('profileCreationTime', time, cb);
root.setFeedbackInfo = function(feedbackValues, cb) {
storage.set('feedback', feedbackValues, cb);
};
root.getProfileCreationTime = function(cb) {
storage.get('profileCreationTime', cb);
root.getFeedbackInfo = function(cb) {
storage.get('feedback', cb);
};
root.storeFocusedWalletId = function(id, cb) {
@ -211,14 +294,6 @@ angular.module('copayApp.services')
storage.set('homeTip', val, cb);
};
root.getRateCardFlag = function(cb) {
storage.get('rateCardFlag', cb);
};
root.setRateCardFlag = function(val, cb) {
storage.set('rateCardFlag', val, cb);
};
root.setHideBalanceFlag = function(walletId, val, cb) {
storage.set('hideBalance-' + walletId, val, cb);
};
@ -349,20 +424,76 @@ angular.module('copayApp.services')
storage.get('bitpayDebitCardsHistory-' + network, cb);
};
root.removeBitpayDebitCardsHistory = function(network, cb) {
storage.remove('bitpayDebitCardsHistory-' + network, cb);
root.removeBitpayDebitCardHistory = function(network, card, cb) {
root.getBitpayDebitCardsHistory(network, function(err, data) {
if (err) return cb(err);
if (lodash.isString(data)) {
data = JSON.parse(data);
}
data = data || {};
delete data[card.eid];
root.setBitpayDebitCardsHistory(network, JSON.stringify(data), cb);
});
};
root.setBitpayDebitCards = function(network, data, cb) {
storage.set('bitpayDebitCards-' + network, data, cb);
if (lodash.isString(data)) {
data = JSON.parse(data);
}
data = data || {};
if (lodash.isEmpty(data) || !data.email) return cb('No card(s) to set');
storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
if (err) return cb(err);
bitpayAccounts = JSON.parse(bitpayAccounts) || {};
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data;
storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
});
};
root.getBitpayDebitCards = function(network, cb) {
storage.get('bitpayDebitCards-' + network, cb);
storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
bitpayAccounts = JSON.parse(bitpayAccounts) || {};
var cards = [];
Object.keys(bitpayAccounts).forEach(function(email) {
// For the UI, add the account email to the card object.
var acctCards = bitpayAccounts[email]['bitpayDebitCards-' + network].cards;
for (var i = 0; i < acctCards.length; i++) {
acctCards[i].email = email;
}
cards = cards.concat(acctCards);
});
cb(err, cards);
});
};
root.removeBitpayDebitCards = function(network, cb) {
storage.remove('bitpayDebitCards-' + network, cb);
root.removeBitpayDebitCard = function(network, card, cb) {
if (lodash.isString(card)) {
card = JSON.parse(card);
}
card = card || {};
if (lodash.isEmpty(card) || !card.eid) return cb('No card to remove');
storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
if (err) cb(err);
bitpayAccounts = JSON.parse(bitpayAccounts) || {};
Object.keys(bitpayAccounts).forEach(function(userId) {
var data = bitpayAccounts[userId]['bitpayDebitCards-' + network];
var newCards = lodash.reject(data.cards, {'eid': card.eid});
data.cards = newCards;
root.setBitpayDebitCards(network, data, function(err) {
if (err) cb(err);
// If there are no more cards in storage then re-enable the next step entry.
root.getBitpayDebitCards(network, function(err, cards){
if (err) cb(err);
if (cards.length == 0) {
root.removeNextStep('BitpayCard', cb);
} else {
cb();
}
});
});
});
});
};
root.setBitpayCardCredentials = function(network, data, cb) {

View File

@ -29,16 +29,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
});
};
// // RECEIVE
// // Check address
// root.isUsed(wallet.walletId, balance.byAddress, function(err, used) {
// if (used) {
// $log.debug('Address used. Creating new');
// $rootScope.$emit('Local/AddressIsUsed');
// }
// });
//
var _signWithLedger = function(wallet, txp, cb) {
$log.info('Requesting Ledger Chrome app to sign the transaction');
@ -67,32 +57,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
});
};
// TODO
// This handles errors from BWS/index which normally
// trigger from async events (like updates).
// Debounce function avoids multiple popups
var _handleError = function(err) {
$log.warn('wallet ERROR: ', err);
$log.warn('TODO');
return; // TODO!!!
if (err instanceof errors.NOT_AUTHORIZED) {
console.log('[walletService.js.93] TODO NOT AUTH'); //TODO
// TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
wallet.notAuthorized = true;
$state.go('tabs.home');
} else if (err instanceof errors.NOT_FOUND) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not access Wallet Service: Not found'));
} else {
var msg = ""
$rootScope.$emit('Local/ClientError', (err.error ? err.error : err));
popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err, gettextCatalog.getString('Error at Wallet Service')));
}
};
root.handleError = lodash.debounce(_handleError, 1000);
root.invalidateCache = function(wallet) {
if (wallet.cachedStatus)
wallet.cachedStatus.isValid = false;
@ -220,7 +184,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + cache.unitName;
cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + cache.unitName;
cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + cache.unitName;
cache.pendingBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat + (cache.pendingAmount === null? 0 : cache.pendingAmount)) + ' ' + cache.unitName;
cache.pendingBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat + (cache.pendingAmount === null ? 0 : cache.pendingAmount)) + ' ' + cache.unitName;
if (cache.pendingAmount !== null && cache.pendingAmount !== 0) {
cache.pendingAmountStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + cache.unitName;
@ -231,6 +195,17 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
cache.alternativeName = config.settings.alternativeName;
cache.alternativeIsoCode = config.settings.alternativeIsoCode;
// Check address
root.isAddressUsed(wallet, balance.byAddress, function(err, used) {
if (used) {
$log.debug('Address used. Creating new');
// Force new address
root.getAddress(wallet, true, function(err, addr) {
$log.debug('New address: ', addr);
});
}
});
rateService.whenAvailable(function() {
var totalBalanceAlternative = rateService.toFiat(cache.totalBalanceSat, cache.alternativeIsoCode);
@ -760,12 +735,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
});
};
root.isUsed = function(wallet, byAddress, cb) {
// Check address
root.isAddressUsed = function(wallet, byAddress, cb) {
storageService.getLastAddress(wallet.id, function(err, addr) {
var used = lodash.find(byAddress, {
address: addr
});
return cb(null, used);
return cb(err, used);
});
};
@ -798,12 +774,14 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
};
root.getAddress = function(wallet, forceNew, cb) {
storageService.getLastAddress(wallet.id, function(err, addr) {
if (err) return cb(err);
if (!forceNew && addr) return cb(null, addr);
if (!wallet.isComplete())
return cb('WALLET_NOT_COMPLETE');
createAddress(wallet, function(err, _addr) {
if (err) return cb(err, addr);
storageService.storeLastAddress(wallet.id, _addr, function() {

View File

@ -0,0 +1,15 @@
#bitpayCardPreferences {
.item {
.item-title {
display: block;
}
.item-subtitle {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: $light-gray;
font-size: 14px;
}
}
}

View File

@ -1,4 +1,4 @@
#thanks-feedback {
#complete {
background-color: #ffffff;
.item-heading {
border-style: none;
@ -19,10 +19,22 @@
}
.subtitle {
padding: 10px 30px 20px 40px;
.image {
text-align: center;
padding: 30px;
}
}
.icon-svg > img {
height: 16rem;
width: 16rem;
margin: 10px;
}
.socialsharing-icon {
display: inline-block;
width: 50px;
height: 50px;
border-radius: 50%;
}
.addressbook-icon-svg {
display: inline-block;
width: 50px;
height: 50px;
}
.share-buttons {
bottom: 0;

View File

@ -1,14 +1,19 @@
#rate-app-store {
#rate-app {
background-color: #ffffff;
.skip {
margin: 10px;
color: #667;
}
.icon-svg > img {
width: 80px;
height: 80px;
margin-top: 15px;
}
.title {
font-size: 20px;
font-weight: bold;
color: $dark-gray;
margin: 40px 10px;
margin: 40px 50px 10px;
text-align: center;
}
.subtitle {

View File

@ -1,20 +1,12 @@
#rate-card {
.stars {
display: flex;
border-bottom: none;
.button {
background-color: #fff;
outline: none;
border: none;
height:10px;
width:10px;
}
.gold {
color: #ffd700;
}
.subtle-gray {
color: $subtle-gray;
}
.row {
border: none;
}
.row.row-margin{
margin: 20px 0px 20px 0px;
}
.item-icon-right {
margin: 0;
}
.feedback-flow-button {
padding: 20px;

View File

@ -1,5 +1,8 @@
#send-feedback {
background-color: #ffffff;
.row {
border: none;
}
.skip {
margin: 20px 20px 10px;
color: #667;
@ -11,18 +14,6 @@
font-weight: bold;
color: $dark-gray;
}
.star {
a {
font-size: 25px;
padding: 20px;
.gold {
color: #ffd700;
}
.subtle-gray {
color: $subtle-gray;
}
}
}
.comment {
padding: 20px;
font-size: 1rem;

View File

@ -9,6 +9,7 @@
box-shadow:$subtle-box-shadow;
padding:0;
border-radius: 6px;
margin: 0 auto;
@media (min-width: 500px) {
& {
width: 350px;
@ -32,7 +33,7 @@
visibility: hidden;
}
&.visible{
visibility: visible !important;
visibility: visible !important;
}
}
.big-icon-svg{
@ -64,10 +65,10 @@
transform: scale(.8);
}
&.swiper-slide-prev {
left: 10vw;
left: 5vw;
}
&.swiper-slide-next {
left: -10vw;
left: -5vw;
}
}
}

View File

@ -49,6 +49,7 @@
%cta-buttons {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}

View File

@ -13,7 +13,7 @@
.scroll{height:100%;}
#address {
background: #fff;
height: calc(100vh - 33vh);
height: calc(100vh - 34vh);
display: flex;
align-items: center;
justify-content: center;
@ -22,14 +22,26 @@
@media(max-height: 600px){
height: calc(100vh - 36vh);
}
&-info{
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
}
article{
flex:1;
width: 100%;
}
#bit-address{
position: absolute;
bottom:0;
width:100%;
width: 100%;
align-self: flex-end;
margin-top: auto;
justify-content: center;
align-content: center;
position: relative;
min-height: 40px;
#next-address{
color:$light-gray;
}
@ -58,6 +70,31 @@
}
.bit-address {
font-size: .8rem;
// left:10%;
position: absolute;
transition: all .4s ease;
width:100%;
height: 100%;
z-index: 0;
position: absolute;
top:50%;
&, &.next{
left:100%;
transform: translate(100%, -40%);
}
&.next, &.prev{
z-index:2;
}
&.current, &.prev{
left:50%;
}
&.current{
transform: translate(-50%, -40%);
z-index: 3;
}
&.prev{
transform: translate(-150%, -40%);
}
.item {
padding-top: 5px;
padding-bottom: 5px;
@ -67,6 +104,32 @@
}
.qr {
padding: calc(100vh - 85vh) 0 calc(100vh - 96vh);
align-self: center;
margin-top: auto;
height: 220px;
position: relative;
justify-content: center;
flex: 1;
div{
transition: all .4s ease;
&.current, &.prev, &.next{
position: absolute;
top:50%;
}
&.current, &.prev{
left:50%;
}
&.current{
transform: translate(-50%, -40%);
}
&.prev{
transform: translate(-150%, -40%);
}
&.next{
left:100%;
transform: translate(100%, -40%);
}
}
@media(max-height: 700px){
padding: calc(100vh - 90vh) 0 calc(100vh - 96vh);
}
@ -74,13 +137,13 @@
display: flex;
justify-content: center;
align-items: center;
position: relative;
min-height: 220px;
}
}
#qr-options{
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
align-self: flex-end;
.item{
i{left:25px;}
}
@ -90,6 +153,8 @@
color: #fff;
position: absolute;
top: 0;
left:0;
z-index: 2;
i {
padding: 10px;
}
@ -122,7 +187,7 @@
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
z-index: 2;
z-index: 4;
}
}
#first-time-tip {
@ -165,6 +230,9 @@
border-right: 1px solid rgb(228, 228, 228);
padding-right: 10px;
}
#wallets{
#sidebar-wallet{display: none;}
}
.wallets{
position: relative;
height: calc(100vh - 83vh);
@ -175,6 +243,17 @@
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
max-width: 450px;
.swiper-slide{
text-align: center;
.card{
margin-top:2vh;
display: inline-block;
width:80%;
}
&-next{left:-25%;}
&-prev{left:25%;}
}
@media (max-height: 600px){
&{
-webkit-transform: translate(-50%, -58%);
@ -184,23 +263,107 @@
}
}
}
// @media(min-width: 700px) and (min-height: 700px){
// .wallets{display: none;}
// #address{
// height:90vh;
// width:75%;
// .qr{
// height: 70%;
// div{
// transform: scale(1.5);
// }
// }
// #bit-address{
// height: 10%;
// padding: calc(100vh - 99vh);
// }
// }
// }
@media(min-width: 700px) and (min-height: 700px){
.wallets{display: none;}
#address{
float:left;
height:90vh;
width:65%;
&-info{
height: 100%;
}
.qr{
height: 70%;
div{
opacity: 0;
transition: none;
&.current{
opacity: 1;
}
}
}
.bit-address{
opacity: 0;
transition: none;
&.current{
opacity: 1;
}
}
.backup, #bit-address{left:0;}
#bit-address{
height: 10%;
padding: calc(100vh - 99vh);
}
}
#wallets{
float:left;
width:35%;
height: 100%;
display: flex;
flex-direction: column;
overflow: visible;
#sidebar-wallet{display: block;}
.list{height: 100%;overflow: visible;}
#wallet-list{
position: absolute;
width: 100%;
overflow-y: scroll;
height: 100%;
left: -6%;
}
.wallet{
position: relative;
&.current{
&:before {
right: 93%;
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-right-color: #f2f2f2;
border-width: 20px;
margin-top: -20px;
}
}
}
.card {
max-width: 350px;
box-shadow:$subtle-box-shadow;
padding:0;
border-radius: 6px;
padding:2px;
width: 80%;
position: relative;
margin: 1.5rem auto 0;
.item{
padding: 6% 10% 6% 8%;
i{left:auto;}
span{
clear:both;
width: 100%;
display: inline-block;
&.wallet-name{
margin-top:10px;
margin-bottom:5px;
font-size:13px;
}
&.wallet-number{
visibility: hidden;
}
&.visible{
visibility: visible !important;
}
}
.big-icon-svg{
& > .bg{padding:.3rem;width: 40px;height:40px;}
}
}
}
}
}
}
@keyframes fadeIn {

View File

@ -13,14 +13,15 @@
@import "advancedSettings";
@import "bitpayCard";
@import "bitpayCardIntro";
@import "bitpayCardPreferences";
@import "address-book";
@import "wallet-backup-phrase";
@import "zero-state";
@import "onboarding/onboarding";
@import "feedback/rateCard";
@import "feedback/sendFeedback";
@import "feedback/thanks";
@import "feedback/rateAppStore";
@import "feedback/send";
@import "feedback/complete";
@import "feedback/rateApp";
@import "includes/actionSheet";
@import "export";
@import "import";

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 17.9 16.4" style="enable-background:new 0 0 17.9 16.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#CCCBCB;}
.st1{fill:#E86C60;}
.st2{fill:#DCDCDC;}
.st3{fill:#EEEEEE;}
</style>
<path class="st0" d="M8.9,12.6c-0.1,0-0.1,0-0.2-0.1L0.2,7.1C0.1,7.1,0,6.9,0,6.8c0-0.1,0.1-0.3,0.2-0.3L8.9,1l8.7,5.4
c0.1,0.1,0.2,0.2,0.2,0.3c0,0.1-0.1,0.3-0.2,0.3l-8.5,5.4C9.1,12.6,9,12.6,8.9,12.6z"/>
<path class="st1" d="M8.9,6.8L8.7,6.6C8.4,6.3,5.5,3.9,5.5,2.1c0-1.2,0.9-2.1,2-2.1c0.5,0,1,0.2,1.4,0.6C9.3,0.2,9.8,0,10.3,0
c1.1,0,2,0.9,2,2.1c0,1.8-2.9,4.2-3.2,4.5L8.9,6.8z"/>
<path class="st2" d="M17.5,16.4C17.4,16.4,17.4,16.4,17.5,16.4l-8.9-5l9.2-4.6V16c0,0.1-0.1,0.2-0.1,0.3
C17.6,16.3,17.6,16.4,17.5,16.4z"/>
<path class="st3" d="M17.5,16.4H0.4c-0.2,0-0.4-0.2-0.4-0.4V6.8l17.7,8.9c0.2,0.1,0.2,0.3,0.2,0.4C17.8,16.3,17.6,16.4,17.5,16.4z"
/>
</svg>

After

Width:  |  Height:  |  Size: 1018 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 17.8 17.8" style="enable-background:new 0 0 17.8 17.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F8E71C;}
</style>
<path class="st0" d="M17.7,6c-0.1-0.2-0.2-0.3-0.4-0.3h-5.5L9.3,0.3C9.2,0.1,9.1,0,8.9,0C8.7,0,8.6,0.1,8.5,0.3L5.9,5.8H0.4
C0.3,5.8,0.1,5.9,0,6C0,6.2,0,6.4,0.1,6.5l4,4.2l-1.6,6.5c0,0.2,0,0.4,0.2,0.5c0.1,0.1,0.3,0.1,0.5,0l5.7-3.3l5.7,3.3
c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.2,0,0.3-0.1c0.1-0.1,0.2-0.3,0.2-0.5l-1.6-6.5l4-4.2C17.8,6.4,17.8,6.2,17.7,6z"/>
</svg>

After

Width:  |  Height:  |  Size: 654 B

10
www/img/ico-star.svg Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 17.8 17.8" style="enable-background:new 0 0 17.8 17.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F2F2F2;}
</style>
<path class="st0" d="M17.7,6c-0.1-0.2-0.2-0.3-0.4-0.3h-5.5L9.3,0.3C9.2,0.1,9.1,0,8.9,0C8.7,0,8.6,0.1,8.5,0.3L5.9,5.8H0.4
C0.3,5.8,0.1,5.9,0,6C0,6.2,0,6.4,0.1,6.5l4,4.2l-1.6,6.5c0,0.2,0,0.4,0.2,0.5c0.1,0.1,0.3,0.1,0.5,0l5.7-3.3l5.7,3.3
c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.2,0,0.3-0.1c0.1-0.1,0.2-0.3,0.2-0.5l-1.6-6.5l4-4.2C17.8,6.4,17.8,6.2,17.7,6z"/>
</svg>

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#7A7A7A;}
</style>
<path class="st0" d="M46.4,0C20.8,0,0,20.8,0,46.4C0,72,20.8,92.8,46.4,92.8C72,92.8,92.8,72,92.8,46.4C92.8,20.8,72,0,46.4,0z
M68.2,61.2c0,1.6-1.3,2.8-2.8,2.8H26c-1.6,0-2.8-1.3-2.8-2.8V38.1L45.7,55l22.5-16.9V61.2z M45.7,49.9L23.2,33
c0-1.6,1.3-2.8,2.8-2.8h39.4c1.6,0,2.8,1.3,2.8,2.8L45.7,49.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 699 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#3B5998;}
</style>
<path class="st0" d="M46.4,0C20.8,0,0,20.8,0,46.4s20.8,46.4,46.4,46.4C72,92.8,92.8,72,92.8,46.4S72,0,46.4,0z M59.4,29.3h-5.6
c-2.5,0-3.7,1.4-3.7,3.8v6.8h8.7l-1.3,8.6H50v23.2h-9.1V48.5h-7.5v-8.6h7.5v-7.4c0-6.8,4.1-11.3,12.3-11.3c3.6,0,6.1,0.4,6.1,0.4
V29.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 568 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#DD4B39;}
</style>
<path class="st0" d="M46.4,0C20.8,0,0,20.8,0,46.4C0,72,20.8,92.8,46.4,92.8C72,92.8,92.8,72,92.8,46.4C92.8,20.8,72,0,46.4,0z
M39.8,64.5c-9.9,0-18-8.1-18-18.1c0-10,8.1-18.1,18-18.1c4.7,0,8.9,1.8,12.1,4.7c-3.8,3.6-3.6,3.8-5.1,5.3c-1.8-1.5-3.9-2.6-7-2.6
c-5.9,0-10.5,4.8-10.5,10.8c0,5.9,4.6,10.8,10.5,10.8c5.8,0,8.2-2.5,9.7-7.2c-2.8,0-9.7,0-9.7,0v-7.2h17.3
C58.3,51.5,54.7,64.5,39.8,64.5z M78.5,47.7h-6.2v6.5h-4.5v-6.5h-6.4v-4.5h6.4v-6.3h4.5v6.3h6.2V47.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 860 B

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#4A90E2;}
.st1{fill:#93C8F4;}
.st2{fill:#FFFFFF;}
</style>
<circle class="st0" cx="46.4" cy="46.4" r="46.4"/>
<path class="st1" d="M68.2,52.2c0-7.3-7.9-13.3-17.7-13.3c-9.7,0-17.7,6-17.7,13.3s7.9,13.3,17.7,13.3c1.2,0,2.3-0.1,3.4-0.3
l8.6,4.2c0.1,0.1,0.3,0.1,0.5,0.1c0.2,0,0.4-0.1,0.5-0.2c0.3-0.2,0.5-0.5,0.5-0.9v-7.8C66.7,58.4,68.2,55.5,68.2,52.2z"/>
<path class="st2" d="M42.3,24.6c-12,0-21.8,7.8-21.8,17.4c0,3.7,1.4,7.2,4.2,10.2v10.3c0,0.4,0.2,0.7,0.5,0.9
c0.2,0.1,0.4,0.2,0.5,0.2c0.2,0,0.3,0,0.5-0.1l9.7-4.8c2.1,0.5,4.3,0.8,6.5,0.8c12,0,21.8-7.8,21.8-17.4
C64.1,32.4,54.3,24.6,42.3,24.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 980 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#1DA1F2;}
</style>
<path class="st0" d="M46.4,0C20.8,0,0,20.8,0,46.4s20.8,46.4,46.4,46.4S92.8,72,92.8,46.4S72,0,46.4,0z M64.3,37.2v1.2
c0,12.2-9.3,26.3-26.3,26.3c-5.2,0-10.1-1.1-14.2-3.8c0.7,0.1,1.5,0.2,2.2,0.2c4.3,0,8.3-1.9,11.5-4.4c-4,0-7.5-2.8-8.6-6.4
c0.6,0.1,1.1,0.2,1.7,0.2c0.8,0,1.7-0.1,2.5-0.3c-4.2-0.8-7.4-4.6-7.4-9.1V41c1.3,0.7,2.7,1.1,4.2,1.1c-2.5-1.7-4.1-4.5-4.1-7.7
c0-1.7,0.5-3.1,1.3-4.5c4.6,5.6,11.4,9.1,19,9.5c-0.2-0.7-0.2-1.4-0.2-2.1c0-5.1,4.1-9.2,9.2-9.2c2.7,0,5.1,1.1,6.8,2.9
c2.1-0.4,4.1-1.2,5.8-2.2c-0.7,2.2-2.1,4-4.1,5.1c1.9-0.2,3.6-0.7,5.3-1.5C67.7,34.3,66.1,35.9,64.3,37.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 987 B

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 92.8 92.8" style="enable-background:new 0 0 92.8 92.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:#3ACE01;}
</style>
<g>
<path class="st0" d="M47.8,26.5c-10.9,0-19.8,8.9-19.8,19.7c0,3.7,1,7.4,3,10.5l0.5,0.7l-2,7.3l7.5-2l0.7,0.4
c3,1.8,6.5,2.8,10.1,2.8h0c10.9,0,19.7-8.9,19.8-19.7c0-5.3-2.1-10.2-5.8-14C58.1,28.6,53.1,26.6,47.8,26.5z M59.5,54.8
c-0.5,1.4-2.9,2.7-4,2.8c-1,0.2-2.3,0.2-3.7-0.2c-0.9-0.3-2-0.6-3.4-1.3c-6-2.6-9.8-8.6-10.1-9c-0.3-0.4-2.4-3.2-2.4-6.1
c0-2.9,1.5-4.4,2.1-5c0.5-0.6,1.2-0.7,1.6-0.7c0.4,0,0.8,0,1.1,0c0.4,0,0.9-0.1,1.3,1c0.5,1.2,1.7,4.1,1.8,4.4
c0.1,0.3,0.2,0.6,0.1,1c-0.2,0.4-0.3,0.6-0.6,1c-0.3,0.3-0.6,0.8-0.9,1C42,44.1,41.7,44.5,42,45c0.3,0.6,1.5,2.5,3.3,4.1
c2.3,2,4.2,2.6,4.8,2.9s0.9,0.2,1.3-0.1c0.3-0.4,1.5-1.7,1.9-2.3c0.4-0.6,0.8-0.5,1.3-0.3c0.5,0.2,3.5,1.6,4.1,1.9
c0.6,0.3,1,0.4,1.1,0.7C59.9,52.2,59.9,53.4,59.5,54.8z"/>
<path class="st0" d="M46.4,0C20.8,0,0,20.8,0,46.4C0,72,20.8,92.8,46.4,92.8S92.8,72,92.8,46.4C92.8,20.8,72,0,46.4,0z M47.8,70.1
L47.8,70.1c-4,0-7.9-1-11.4-2.9l-12.6,3.3l3.4-12.3c-2.1-3.6-3.2-7.7-3.2-11.9c0-13.1,10.7-23.8,23.8-23.8c6.4,0,12.3,2.5,16.8,7
c4.5,4.5,7,10.5,7,16.8C71.6,59.4,60.9,70.1,47.8,70.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -2,7 +2,7 @@
<ion-nav-bar class="bar-royal">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-title>BitPay Visa<sup>&reg;</sup> Card</ion-nav-title>
<ion-nav-title>BitPay Visa<sup>&reg;</sup> Card ({{card.lastFourDigits}})</ion-nav-title>
<ion-nav-buttons side="secondary">
<button class="button no-border" ui-sref="tabs.bitpayCard.preferences">
<i class="icon ion-ios-settings"></i>

View File

@ -0,0 +1,99 @@
<ion-view id="complete">
<ion-content scroll="false">
<div class="item item-icon-right item-heading">
<a ui-sref="tabs.home"><i class="icon ion-ios-close-empty close-home-tip"></i></a>
</div>
<div ng-show="skipped && isCordova">
<div ng-show="score > 3">
<div class="title" translate>Invite friends to BitPay Wallet!</div>
<div class="text-center">
<i class="icon addressbook-icon-svg">
<img src="img/address-book-add.svg"/>
</i>
</div>
<div class="text-center">
<span translate>Share the love by inviting your friends.</span>
</div>
</div>
<div ng-show="score <= 3">
<div class="title" translate>Thank you!</div>
<div class="subtitle">
<span translate>A member of the team will review your feedback as soon as possible.</span>
</div>
<div class="subtitle" ng-if="score <= 3 || !isCordova">
<span translate>If you have additional feedback, please let us know by tapping the "Send feedback" option in the Settings tab.</span>
</div>
<div ng-if="score <= 3 || !isCordova">
<div class="text-center">
<i class="icon icon-svg">
<img src="img/illustration-send-feedback.png"/>
</i>
</div>
</div>
</div>
</div>
<div ng-show="!skipped || !isCordova">
<div class="title" translate>Thank you!</div>
<div class="subtitle">
<span translate>A member of the team will review your feedback as soon as possible.</span>
</div>
<div class="subtitle" ng-if="score <= 3 || !isCordova">
<span translate>If you have additional feedback, please let us know by tapping the "Send feedback" option in the Settings tab.</span>
</div>
<div ng-if="score <= 3 || !isCordova">
<div class="text-center">
<i class="icon icon-svg">
<img src="img/illustration-send-feedback.png"/>
</i>
</div>
</div>
<div class="text-center" ng-if="score > 3 && isCordova">
<span translate>Share the love by inviting your friends.</span>
</div>
</div>
<div class="share-buttons" ng-if="isCordova && score > 3">
<div class="ng-hide" ng-show="socialsharing" ng-if="score >= 4">
<div class="row">
<div class="ng-hide" ng-show="facebook" ng-click="shareFacebook()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-facebook.svg"/>
</i>
<span>Facebook</span>
</div>
<div class="ng-hide" ng-show="twitter" ng-click="shareTwitter()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-twitter.svg"/>
</i>
<span>Twitter</span>
</div>
<div class="ng-hide" ng-show="googleplus" ng-click="shareGooglePlus()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-googleplus.svg"/>
</i>
<span>Google+</span>
</div>
</div>
<div class="row">
<div class="ng-hide" ng-show="email" ng-click="shareEmail()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-email.svg"/>
</i>
<span>Email</span>
</div>
<div class="ng-hide" ng-show="whatsapp" ng-click="shareWhatsapp()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-whatsapp.svg"/>
</i>
<span>Whatsapp</span>
</div>
<div ng-click="shareMessage()">
<i class="icon socialsharing-icon">
<img src="img/social-icons/ico-social-message.svg"/>
</i>
<span>Message</span>
</div>
</div>
</div>
</div>
</ion-content>
</ion-view>

View File

@ -1,18 +1,18 @@
<ion-view id="rate-app-store">
<ion-view id="rate-app">
<ion-content scroll="false">
<a class="right skip" ng-click="skip()">Skip</a>
<div class="title">
<span translate>Thank you!</span>
<div>
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
<i class="icon icon-svg">
<img src="img/ico-positive-feedback.svg" class="bg"/>
</i>
</div>
</div>
<div class="subtitle">
<div class="subtitle text-center">
<span translate>5-star ratings help us get BitPay Wallet into more hands, and more users means more resoucers can be committed to the app!</span>
</div>
<div class="subtitle">
<div class="subtitle text-center">
<span class="text-bold" translate>Would you be willing to rate BitPay Wallet in the app store?</span>
</div>
<div class="buttons">

View File

@ -3,12 +3,37 @@
<span translate>How do you like BitPay Wallet?</span>
<a ng-click="hideCard()" ><i class="icon ion-ios-close-empty close-home-tip"></i></a>
</div>
<div class="stars item item-sub">
<button class="button icon ion-android-star" ng-click="setScore(1)" ng-class="{'gold': 1 <= score, 'subtle-gray': 1 > score}"></button>
<button class="button icon ion-android-star" ng-click="setScore(2)" ng-class="{'gold': 2 <= score, 'subtle-gray': 2 > score}"></button>
<button class="button icon ion-android-star" ng-click="setScore(3)" ng-class="{'gold': 3 <= score, 'subtle-gray': 3 > score}"></button>
<button class="button icon ion-android-star" ng-click="setScore(4)" ng-class="{'gold': 4 <= score, 'subtle-gray': 4 > score}"></button>
<button class="button icon ion-android-star" ng-click="setScore(5)" ng-class="{'gold': 5 == score, 'subtle-gray': 5 > score}"></button>
<div class="row item item-sub" ng-class="{'row-margin': isModal}">
<div class="col col-20">
<i class="icon icon-svg" ng-click="setScore(1)">
<img ng-if="1 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="1 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-20">
<i class="icon icon-svg" ng-click="setScore(2)">
<img ng-if="2 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="2 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-20">
<i class="icon icon-svg" ng-click="setScore(3)">
<img ng-if="3 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="3 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-20">
<i class="icon icon-svg" ng-click="setScore(4)">
<img ng-if="4 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="4 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-20">
<i class="icon icon-svg" ng-click="setScore(5)">
<img ng-if="5 == score" src="img/ico-star-filled.svg"/>
<img ng-if="5 > score" src="img/ico-star.svg"/>
</i>
</div>
</div>
<div class="feedback-flow-button" ng-if="button_title">
<button type="submit" class="button button-standard button-primary" ng-click="goFeedbackFlow()">

View File

@ -0,0 +1,51 @@
<ion-view id="send-feedback">
<a class="right skip" ng-click="sendFeedback(null,true)" href translate>Skip</a>
<ion-content class="has-header" scroll="false">
<div class="title">
<span>{{reaction}}</span>
</div>
<div class="row item item-sub">
<div class="col col-10">
<i class="icon icon-svg" ng-click="setScore(1)">
<img ng-if="1 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="1 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-10">
<i class="icon icon-svg" ng-click="setScore(2)">
<img ng-if="2 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="2 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-10">
<i class="icon icon-svg" ng-click="setScore(3)">
<img ng-if="3 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="3 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-10">
<i class="icon icon-svg" ng-click="setScore(4)">
<img ng-if="4 <= score" src="img/ico-star-filled.svg"/>
<img ng-if="4 > score" src="img/ico-star.svg"/>
</i>
</div>
<div class="col col-10">
<i class="icon icon-svg" ng-click="setScore(5)">
<img ng-if="5 == score" src="img/ico-star-filled.svg"/>
<img ng-if="5 > score" src="img/ico-star.svg"/>
</i>
</div>
</div>
<div class="comment">
<span translate>{{comment}}</span>
</div>
<div>
<textarea ng-model="feedback" placeholder="Is there anything we could do to improve your experience?" row="40"></textarea>
</div>
<div class="padding">
<button ng-disabled="!feedback" type="submit" class="button button-full button-primary" ng-click="sendFeedback(feedback, false)" translate>
Send
</button>
</div>
</ion-content>
</ion-view>

View File

@ -1,26 +0,0 @@
<ion-view id="send-feedback">
<a class="right skip" ng-click="sendFeedback(null,true)" href translate>Skip</a>
<ion-content class="has-header" scroll="false">
<div class="title">
<span>{{reaction}}</span>
</div>
<div class="star">
<a><i ng-class="{'gold': 1 <= score, 'subtle-gray': 1 > score}" class="icon ion-android-star"></i></a>
<a><i ng-class="{'gold': 2 <= score, 'subtle-gray': 2 > score}" class="icon ion-android-star"></i></a>
<a><i ng-class="{'gold': 3 <= score, 'subtle-gray': 3 > score}" class="icon ion-android-star"></i></a>
<a><i ng-class="{'gold': 4 <= score, 'subtle-gray': 4 > score}" class="icon ion-android-star"></i></a>
<a><i ng-class="{'gold': 5 == score, 'subtle-gray': 5 > score}" class="icon ion-android-star"></i></a>
</div>
<div class="comment">
<span translate>{{comment}}</span>
</div>
<div>
<textarea ng-model="feedback" placeholder="Is there anything we could do to improve your experience?" row="40"></textarea>
</div>
<div class="padding">
<button ng-disabled="!feedback" type="submit" class="button button-full button-primary" ng-click="sendFeedback(feedback, false)" translate>
Send
</button>
</div>
</ion-content>
</ion-view>

View File

@ -1,79 +0,0 @@
<ion-view id="thanks-feedback">
<ion-content scroll="false">
<div class="item item-icon-right item-heading">
<a ui-sref="tabs.home()"><i class="icon ion-ios-close-empty close-home-tip"></i></a>
</div>
<div ng-show="skipped && isCordova">
<div class="title" translate>Invite friends to BitPay Wallet!</div>
<div>
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
</div>
<div class="text-center">
<span translate>Share the love by inviting your friends.</span>
</div>
</div>
<div ng-show="!skipped || !isCordova">
<div class="title" translate>Thank you!</div>
<div class="subtitle">
<span translate>A member of the team will review your feedback as soon as possible.</span>
</div>
<div class="subtitle" ng-if="score <= 3 || !isCordova">
<span translate>If you have additional feedback, please let us know by tapping the "Send feedback" option in the Settings tab.</span>
<div class="image">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
</div>
</div>
<div class="text-center" ng-if="score > 3 && isCordova">
<span translate>Share the love by inviting your friends.</span>
</div>
</div>
<div class="share-buttons" ng-if="isCordova && score > 3">
<div class="ng-hide" ng-show="socialsharing" ng-if="score >= 4">
<div class="row">
<div class="ng-hide" ng-show="facebook" ng-click="shareFacebook()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Facebook</span>
</div>
<div class="ng-hide" ng-show="twitter" ng-click="shareTwitter()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Twitter</span>
</div>
<div class="ng-hide" ng-show="googleplus" ng-click="shareGooglePlus()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Google+</span>
</div>
</div>
<div class="row">
<div class="ng-hide" ng-show="email" ng-click="shareEmail()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Email</span>
</div>
<div class="ng-hide" ng-show="whatsapp" ng-click="shareWhatsapp()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Whatsapp</span>
</div>
<div ng-click="shareMessage()">
<i class="icon zero-state-icon">
<img src="img/address-book-add.svg"/>
</i>
<span>Message</span>
</div>
</div>
</div>
</div>
</ion-content>
</ion-view>

View File

@ -1,4 +1,4 @@
<ion-view>
<ion-view id="bitpayCardPreferences">
<ion-nav-bar class="bar-royal">
<ion-nav-back-button>
</ion-nav-back-button>
@ -10,12 +10,14 @@
<div class="item item-divider" translate>
Cards
</div>
<div class="item" ng-repeat="card in bitpayCards">
xxxx-xxxx-xxxx-{{card.lastFourDigits}}
</div>
<div class="item item-divider"></div>
<div class="item assertive" ng-click="remove()">
Removes all data from this device
<div class="item item-icon-right" ng-click="remove(card)" ng-repeat="card in bitpayCards">
<span class="item-title">
xxxx-xxxx-xxxx-{{card.lastFourDigits}}
</span>
<span class="item-subtitle">
{{card.email}}
</span>
<i class="icon ion-trash-b assertive"></i>
</div>
</div>
</ion-content>

View File

@ -1,4 +1,4 @@
<ion-view>
<ion-view class="settings">
<ion-nav-bar class="bar-royal">
<ion-nav-title>Wallet Service URL</ion-nav-title>
<ion-nav-back-button>
@ -6,8 +6,8 @@
</ion-nav-bar>
<ion-content>
<div class="list">
<label class="item item-input item-stacked-label no-border">
<div class="list settings-list settings-input-group">
<label class="item item-input item-stacked-label">
<span class="input-label">Wallet Service URL</span>
<input type="text" id="bwsurl" type="text" name="bwsurl" ng-model="bwsurl.value">
<a class="postfix" on-tap="resetDefaultUrl()">

View File

@ -13,7 +13,7 @@
<div class="release ng-hide" ng-show="newRelease" ng-click="openExternalLink('https://github.com/bitpay/copay/releases/latest', true, 'Update Available', 'An update to this app is available. For your security, please update to the latest version.', 'View Update', 'Go Back')">
<span translate>An update to this app is available</span><span><i class="icon bp-arrow-right"></i></span>
</div>
<div class="list card ng-hide" ng-show="!hideRateCard.value">
<div class="list card ng-hide" ng-show="showRateCard.value">
<span ng-include="'views/feedback/rateCard.html'"></span>
</div>
<div class="list card homeTip" ng-if="homeTip">
@ -87,33 +87,31 @@
<span class="tab-home__wallet__multisig-number" ng-if="wallet.n > 1">
{{wallet.m}}-of-{{wallet.n}}
</span>
<span class="assertive" ng-if="wallet.error">{{wallet.error}}</span>
</span>
&nbsp;
</p>
<i class="icon bp-arrow-right"></i>
</a>
</div>
</div>
<div class="list card" ng-if="bitpayCardEnabled && bitpayCards[0] && externalServices.BitpayCard">
<div class="item item-icon-right item-heading">
<span translate>Cards</span>
<a ui-sref="tabs.bitpayCardIntro"><i class="icon ion-ios-plus-empty list-add-button"></i></a>
</div>
<div>
<a ng-repeat="card in bitpayCards"
ui-sref="tabs.bitpayCard({id:card.id})"
ng-if="bitpayCardEnabled && bitpayCards[0]"
class="item item-sub item-icon-left item-big-icon-left item-icon-right">
<i class="icon big-icon-svg">
<div class="bg icon-bitpay-card"></div>
</i>
<span>BitPay Visa&reg; Card</span>
<span>BitPay Visa&reg; Card ({{card.lastFourDigits}})</span>
<p>{{cardsHistory[card.id].balance ? '$' + cardsHistory[card.id].balance : 'Add funds to get started'|translate}}</p>
<i class="icon bp-arrow-right"></i>
</a>
<a ui-sref="tabs.bitpayCardIntro"
ng-if="bitpayCardEnabled && !bitpayCards[0] && externalServices.BitpayCard"
class="item item-sub item-icon-left item-big-icon-left item-icon-right">
<i class="icon big-icon-svg">
<div class="bg icon-bitpay-card"></div>
</i>
<span>BitPay Visa&reg; Card</span>
<p translate>Add your card</p>
<i class="icon bp-arrow-right"></i>
</a>
</div>
</div>

View File

@ -3,11 +3,11 @@
<ion-nav-title>{{'Receive' | translate}}</ion-nav-title>
</ion-nav-bar>
<ion-content scroll="false">
<div class="list card padding text-center" ng-if="!wallets[0]">
<article class="list card padding text-center" ng-if="!wallets[0]">
<span translate>No Wallet</span>
</div>
<div id="address" ng-if="wallets[0]">
<article class="text-center" ng-if="!wallet">
</article>
<article id="address" ng-if="wallets[0]">
<div id="address-info" class="text-center" ng-if="!wallet">
<div class="row qr">
<div class="text-center col center-block">
<div style="height:225px; width:220px; margin:auto; background: white; padding-top: 25%;">
@ -23,8 +23,8 @@
</div>
</div>
</div>
</article>
<article class="text-center" ng-if="wallet && !wallet.isComplete()">
</div>
<div id="address-info" class="text-center" ng-if="wallet && !wallet.isComplete()">
<div class="incomplete">
<div class="title">
<span translate>Incomplete wallet</span>
@ -44,17 +44,17 @@
</div>
</div>
</div>
</article>
<article ng-if="wallet && wallet.isComplete()">
</div>
<div id="address-info" ng-if="wallet && wallet.isComplete()">
<div class="row backup" ng-show="wallet.needsBackup" ng-click="openBackupNeededModal()">
<div class="text-center col center-block">
<i class="icon ion-alert"></i><span translate>Wallet not backed up</span><i class="icon ion-ios-arrow-thin-right"></i>
</div>
</div>
<div class="row qr">
<div class="text-center col center-block" copy-to-clipboard="addr">
<qrcode ng-if="addr" size="220" data="bitcoin:{{addr}}" color="#334"></qrcode>
<div ng-if="!addr" style="height:225px; width:220px; margin:auto; background: white; padding-top: 25%;">
<div class="text-center col center-block" copy-to-clipboard="addr" ng-repeat="wallet in wallets track by $index" ng-class="walletPosition($index)">
<qrcode ng-if="walletAddrs[wallet.id]" size="220" data="bitcoin:{{walletAddrs[wallet.id]}}" color="#334"></qrcode>
<div ng-if="!walletAddrs[wallet.id]" style="height:225px; width:220px; margin:auto;padding-top: 25%;position:absolute;left:50%;top:50%;z-index:1;">
...
</div>
</div>
@ -72,20 +72,35 @@
</div>
</div>
<div id="bit-address" class="row border-top">
<div class="col col-90 center-block bit-address text-center">
<div class="center-block bit-address text-center" ng-repeat="wallet in wallets track by $index" ng-class="walletPosition($index)">
<div class="item item-icon-left item-icon-right">
<i class="icon icon-svg receive-tab-bitcoin-icon"><img src="img/icon-bitcoin-symbol.svg"></i>
<span class="bit-address-gen-address" ng-if="generatingAddress">...</span>
<span class="bit-address-gen-address" ng-if="!generatingAddress" copy-to-clipboard="addr">{{addr}}</span>
<span class="bit-address-gen-address" ng-if="!generatingAddress" copy-to-clipboard="walletAddrs[wallet.id]">{{walletAddrs[wallet.id]}}</span>
</div>
</div>
</div>
</article>
</div>
<article id="wallets" ng-if="wallets[0]">
<div class="list">
<wallets wallets="wallets"></wallets>
</div>
</article>
<article id="wallets" ng-if="wallets[0]">
<div id="sidebar-wallet" class="list">
<div id="wallet-list">
<div class="wallet" ng-repeat="wallet in wallets track by $index" ng-click="setWallet($index)" ng-class="walletPosition($index)">
<div class="card">
<div class="item item-icon-left text-right" ng-class="{'noBalance': !wallet.status.availableBalanceStr}">
<i class="icon big-icon-svg">
<img src="img/icon-wallet.svg" ng-style="{'background-color': wallet.color}" class="bg"/>
</i>
<span class="wallet-name">{{wallet.name || wallet.id}}</span>
<span class="item-note m10l">
{{wallet.status.availableBalanceStr}}
</span>
</div>
</div>
</div>
</div>
</div>
<wallets id="wallet-slider" wallets="wallets" options="sliderOptions"></wallets>
</article>
</ion-content>
</ion-view>

View File

@ -143,7 +143,7 @@
Wallet not backed up
</a>
<div class="p60b" ng-show="wallet && wallet.isComplete()" style="padding-top: 1rem;">
<div class="p60b" ng-show="wallet && wallet.isComplete() && !walletNotRegistered" style="padding-top: 1rem;">
<div class="oh pr m20t" ng-show="wallet.incorrectDerivation">
<div class="text-center text-warning">
<i class="fi-alert"></i>
@ -152,25 +152,6 @@
</span>
</div>
</div>
<div class="oh pr m20t" ng-show="notAuthorized && !updatingStatus">
<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="recreate()">
<span translate>Recreate</span>
</span>
</div>
</div>
<div class="list" ng-if="txps[0]">
<!-- <div class="item item-heading" translate>
<span ng-show="requiresMultipleSignatures" translate>Payment Proposals</span>
@ -193,7 +174,7 @@
<!-- Transactions -->
<div class="oh pr m20t text-gray size-12 text-center"
ng-show="!txHistory[0] && !updatingTxHistory && !txHistoryError && !updateStatusError && !notAuthorized" translate>
ng-show="!txHistory[0] && !updatingTxHistory && !txHistoryError && !updateStatusError" translate>
No transactions yet
</div>
@ -283,6 +264,7 @@
on-infinite="showMore()"
distance="1%">
</ion-infinite-scroll>
</div>
</ion-content>
</div>
</ion-view>