diff --git a/src/js/controllers/bitpayCard.js b/src/js/controllers/bitpayCard.js index dd84deaf9..48ec83506 100644 --- a/src/js/controllers/bitpayCard.js +++ b/src/js/controllers/bitpayCard.js @@ -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; + }); + }); } }); diff --git a/src/js/controllers/feedback/thanks.js b/src/js/controllers/feedback/complete.js similarity index 87% rename from src/js/controllers/feedback/thanks.js rename to src/js/controllers/feedback/complete.js index 7aa84334f..c337e14f9 100644 --- a/src/js/controllers/feedback/thanks.js +++ b/src/js/controllers/feedback/complete.js @@ -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) { diff --git a/src/js/controllers/feedback/rateAppStore.js b/src/js/controllers/feedback/rateApp.js similarity index 51% rename from src/js/controllers/feedback/rateAppStore.js rename to src/js/controllers/feedback/rateApp.js index b659fa516..764b79faa 100644 --- a/src/js/controllers/feedback/rateAppStore.js +++ b/src/js/controllers/feedback/rateApp.js @@ -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 }); }; diff --git a/src/js/controllers/feedback/rateCard.js b/src/js/controllers/feedback/rateCard.js index 8eaa98cfa..4c858b3ed 100644 --- a/src/js/controllers/feedback/rateCard.js +++ b/src/js/controllers/feedback/rateCard.js @@ -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); } }); diff --git a/src/js/controllers/feedback/sendFeedback.js b/src/js/controllers/feedback/send.js similarity index 87% rename from src/js/controllers/feedback/sendFeedback.js rename to src/js/controllers/feedback/send.js index 8899301c3..fc8fa410c 100644 --- a/src/js/controllers/feedback/sendFeedback.js +++ b/src/js/controllers/feedback/send.js @@ -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 }); diff --git a/src/js/controllers/headController.js b/src/js/controllers/headController.js index 663126321..a33c2d8be 100644 --- a/src/js/controllers/headController.js +++ b/src/js/controllers/headController.js @@ -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) }); diff --git a/src/js/controllers/onboarding/welcomeController.js b/src/js/controllers/onboarding/welcomeController.js index 3b74544a7..1a7e3a6a6 100644 --- a/src/js/controllers/onboarding/welcomeController.js +++ b/src/js/controllers/onboarding/welcomeController.js @@ -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() {}); - }; - }); diff --git a/src/js/controllers/preferencesBitpayCard.js b/src/js/controllers/preferencesBitpayCard.js index 0fb74d228..33060296d 100644 --- a/src/js/controllers/preferencesBitpayCard.js +++ b/src/js/controllers/preferencesBitpayCard.js @@ -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; }); }); diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js index bf8443081..25dd485cf 100644 --- a/src/js/controllers/tab-home.js +++ b/src/js/controllers/tab-home.js @@ -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; diff --git a/src/js/controllers/tab-receive.js b/src/js/controllers/tab-receive.js index 11095db14..ea8b9778a 100644 --- a/src/js/controllers/tab-receive.js +++ b/src/js/controllers/tab-receive.js @@ -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(); + }); }); }); diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 34e78b751..17a725e39 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -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(); }); }); diff --git a/src/js/routes.js b/src/js/routes.js index a0921a390..912d57c66 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -739,30 +739,30 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr abstract: true, template: '' }) - .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); + }); }); }); diff --git a/src/js/services/bitpayCardService.js b/src/js/services/bitpayCardService.js index 84bf93a47..bd671c02d 100644 --- a/src/js/services/bitpayCardService.js +++ b/src/js/services/bitpayCardService.js @@ -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(); }); }); }; diff --git a/src/js/services/feedbackService.js b/src/js/services/feedbackService.js index 0a1788edc..b35c4c323 100644 --- a/src/js/services/feedbackService.js +++ b/src/js/services/feedbackService.js @@ -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; }); diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 60545747a..6921b4f9b 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -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) { diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index a2dea86dc..3e5da9097 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -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() { diff --git a/src/sass/views/bitpayCardPreferences.scss b/src/sass/views/bitpayCardPreferences.scss new file mode 100644 index 000000000..670e8752e --- /dev/null +++ b/src/sass/views/bitpayCardPreferences.scss @@ -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; + } + } +} diff --git a/src/sass/views/feedback/thanks.scss b/src/sass/views/feedback/complete.scss similarity index 68% rename from src/sass/views/feedback/thanks.scss rename to src/sass/views/feedback/complete.scss index 2d86c357f..f5e0052b9 100644 --- a/src/sass/views/feedback/thanks.scss +++ b/src/sass/views/feedback/complete.scss @@ -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; diff --git a/src/sass/views/feedback/rateAppStore.scss b/src/sass/views/feedback/rateApp.scss similarity index 77% rename from src/sass/views/feedback/rateAppStore.scss rename to src/sass/views/feedback/rateApp.scss index 5003e6b02..9f44f5920 100644 --- a/src/sass/views/feedback/rateAppStore.scss +++ b/src/sass/views/feedback/rateApp.scss @@ -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 { diff --git a/src/sass/views/feedback/rateCard.scss b/src/sass/views/feedback/rateCard.scss index 9d01ea078..d141ca633 100644 --- a/src/sass/views/feedback/rateCard.scss +++ b/src/sass/views/feedback/rateCard.scss @@ -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; diff --git a/src/sass/views/feedback/sendFeedBack.scss b/src/sass/views/feedback/send.scss similarity index 73% rename from src/sass/views/feedback/sendFeedBack.scss rename to src/sass/views/feedback/send.scss index 33b1720ca..2a0f9a210 100644 --- a/src/sass/views/feedback/sendFeedBack.scss +++ b/src/sass/views/feedback/send.scss @@ -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; diff --git a/src/sass/views/includes/wallets.scss b/src/sass/views/includes/wallets.scss index a3e1a4320..7bb22c807 100644 --- a/src/sass/views/includes/wallets.scss +++ b/src/sass/views/includes/wallets.scss @@ -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; } } } diff --git a/src/sass/views/onboarding/onboarding.scss b/src/sass/views/onboarding/onboarding.scss index 550f8de32..4acd9bfc5 100644 --- a/src/sass/views/onboarding/onboarding.scss +++ b/src/sass/views/onboarding/onboarding.scss @@ -49,6 +49,7 @@ %cta-buttons { position: absolute; bottom: 0; + left: 0; width: 100%; } diff --git a/src/sass/views/tab-receive.scss b/src/sass/views/tab-receive.scss index 1b18083c0..99bc97ea5 100644 --- a/src/sass/views/tab-receive.scss +++ b/src/sass/views/tab-receive.scss @@ -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 { diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss index 5b3e8290d..f67826f61 100644 --- a/src/sass/views/views.scss +++ b/src/sass/views/views.scss @@ -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"; diff --git a/www/img/ico-positive-feedback.svg b/www/img/ico-positive-feedback.svg new file mode 100644 index 000000000..508cc7ded --- /dev/null +++ b/www/img/ico-positive-feedback.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/www/img/ico-star-filled.svg b/www/img/ico-star-filled.svg new file mode 100644 index 000000000..a475c9e2c --- /dev/null +++ b/www/img/ico-star-filled.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/www/img/ico-star.svg b/www/img/ico-star.svg new file mode 100644 index 000000000..bab3db3e5 --- /dev/null +++ b/www/img/ico-star.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/www/img/illustration-send-feedback.png b/www/img/illustration-send-feedback.png new file mode 100644 index 000000000..13f5b6ccd Binary files /dev/null and b/www/img/illustration-send-feedback.png differ diff --git a/www/img/social-icons/ico-social-email.svg b/www/img/social-icons/ico-social-email.svg new file mode 100644 index 000000000..bd88c0374 --- /dev/null +++ b/www/img/social-icons/ico-social-email.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/www/img/social-icons/ico-social-facebook.svg b/www/img/social-icons/ico-social-facebook.svg new file mode 100644 index 000000000..c74f94971 --- /dev/null +++ b/www/img/social-icons/ico-social-facebook.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/www/img/social-icons/ico-social-googleplus.svg b/www/img/social-icons/ico-social-googleplus.svg new file mode 100644 index 000000000..282bd61b6 --- /dev/null +++ b/www/img/social-icons/ico-social-googleplus.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/www/img/social-icons/ico-social-message.svg b/www/img/social-icons/ico-social-message.svg new file mode 100644 index 000000000..0bc23d2de --- /dev/null +++ b/www/img/social-icons/ico-social-message.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/www/img/social-icons/ico-social-twitter.svg b/www/img/social-icons/ico-social-twitter.svg new file mode 100644 index 000000000..1dd16e791 --- /dev/null +++ b/www/img/social-icons/ico-social-twitter.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/www/img/social-icons/ico-social-whatsapp.svg b/www/img/social-icons/ico-social-whatsapp.svg new file mode 100644 index 000000000..9c19f2e68 --- /dev/null +++ b/www/img/social-icons/ico-social-whatsapp.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/www/views/bitpayCard.html b/www/views/bitpayCard.html index 34c345732..e9a9a53da 100644 --- a/www/views/bitpayCard.html +++ b/www/views/bitpayCard.html @@ -2,7 +2,7 @@ - BitPay Visa® Card + BitPay Visa® Card ({{card.lastFourDigits}}) - - - - +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+ + diff --git a/www/views/feedback/sendFeedback.html b/www/views/feedback/sendFeedback.html deleted file mode 100644 index f22e175e8..000000000 --- a/www/views/feedback/sendFeedback.html +++ /dev/null @@ -1,26 +0,0 @@ - - - -
- {{reaction}} -
-
- - - - - -
-
- {{comment}} -
-
- -
-
- -
-
-
diff --git a/www/views/feedback/thanks.html b/www/views/feedback/thanks.html deleted file mode 100644 index 826f65675..000000000 --- a/www/views/feedback/thanks.html +++ /dev/null @@ -1,79 +0,0 @@ - - -
- -
-
-
Invite friends to BitPay Wallet!
-
- - - -
-
- Share the love by inviting your friends. -
-
-
-
Thank you!
-
- A member of the team will review your feedback as soon as possible. -
-
- If you have additional feedback, please let us know by tapping the "Send feedback" option in the Settings tab. -
- - - -
-
-
- Share the love by inviting your friends. -
-
- -
-
diff --git a/www/views/preferencesBitpayCard.html b/www/views/preferencesBitpayCard.html index c20545f7b..756a0dca2 100644 --- a/www/views/preferencesBitpayCard.html +++ b/www/views/preferencesBitpayCard.html @@ -1,4 +1,4 @@ - + @@ -10,12 +10,14 @@
Cards
-
- xxxx-xxxx-xxxx-{{card.lastFourDigits}} -
-
-
- Removes all data from this device +
+ + xxxx-xxxx-xxxx-{{card.lastFourDigits}} + + + {{card.email}} + +
diff --git a/www/views/preferencesBwsUrl.html b/www/views/preferencesBwsUrl.html index d03d415bc..e3d2e7594 100644 --- a/www/views/preferencesBwsUrl.html +++ b/www/views/preferencesBwsUrl.html @@ -1,4 +1,4 @@ - + Wallet Service URL @@ -6,8 +6,8 @@ -
-