diff --git a/app-template/bitcoincom/appConfig.json b/app-template/bitcoincom/appConfig.json index 28e24e9fb..fefcb9a4f 100644 --- a/app-template/bitcoincom/appConfig.json +++ b/app-template/bitcoincom/appConfig.json @@ -24,9 +24,9 @@ "windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c", "pushSenderId": "1036948132229", "description": "A Secure Bitcoin Wallet", - "version": "4.12.2", - "fullVersion": "4.12-rc3", - "androidVersion": "412200", + "version": "4.13.0", + "fullVersion": "4.13-rc1", + "androidVersion": "413000", "_extraCSS": "", "_enabledExtensions": { "coinbase": false, diff --git a/i18n/po/template.pot b/i18n/po/template.pot index 2ee53ec78..4bab9ff2e 100644 --- a/i18n/po/template.pot +++ b/i18n/po/template.pot @@ -610,10 +610,14 @@ msgstr "" msgid "Connection reset by peer" msgstr "" -#: www/views/tab-send.html:45 +#: www/views/tab-send.html:85 msgid "Contacts" msgstr "" +#: www/views/tab-send.html:86 +msgid "Saved frequently used addresses" +msgstr "" + #: www/views/onboarding/notifications.html:9 msgid "Continue" msgstr "" @@ -815,7 +819,7 @@ msgstr "" #: www/views/onboarding/tour.html:51 #: www/views/tab-home.html:75 -#: www/views/tab-send.html:36 +#: www/views/tab-send.html:75 msgid "Create bitcoin wallet" msgstr "" @@ -2525,6 +2529,14 @@ msgstr "" msgid "Search or enter bitcoin address" msgstr "" +#: src/js/controllers/tab-send.js:28 +msgid "Clipboard" +msgstr "" + +#: src/js/controllers/tab-send.js:29 +msgid "Your Clipboard is empty" +msgstr "" + #: www/views/modals/search.html:16 msgid "Search transactions" msgstr "" @@ -2583,9 +2595,70 @@ msgid "Send by email" msgstr "" #: src/js/controllers/confirm.js:177 +#: src/js/controllers/tab-send.js:94 msgid "Send from" msgstr "" +#: src/js/controllers/tab-send.js:77 +msgid "Send to" +msgstr "" + +#: www/views/tab-send.html:20 +msgid "Paste Clipboard" +msgstr "" + +#: www/views/tab-send.html:21 +msgid "Paste Address" +msgstr "" + +#: www/views/tab-send.html:27 +msgid "Wallet to Wallet Transfer" +msgstr "" + +#: www/views/tab-send.html:35 +msgid "Scan QR Code" +msgstr "" + +#: www/views/tab-send.html:46 +msgid "Send Bitcoin faster!" +msgstr "" + +#: www/views/tab-send.html:46 +msgid "Send Bitcoin faster!" +msgstr "" + +#: www/views/tab-send.html:50 +msgid "Save frequently used addresses and send them Bitcoin in just one tap" +msgstr "" + +#: www/views/tab-send.html:55 +msgid "Add your first contact" +msgstr "" + +#: www/views/tab-send.html:65 +msgid "Your Bitcoin wallet is empty" +msgstr "" + +#: www/views/tab-send.html:69 +msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address." +msgstr "" + +#: www/views/tab-send.html:70 +msgid "You can receive bitcoin from any wallet or service." +msgstr "" + +#: www/views/tab-send.html:72 +msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin." +msgstr "" + +#: www/views/tab-send.html:74 +msgid "Buy Bitcoin now" +msgstr "" + +#: www/views/tab-send.html:76 +msgid "Show my address" +msgstr "" + #: www/views/includes/itemSelector.html:8 msgid "Send max amount" msgstr "" diff --git a/src/js/controllers/addressbookAdd.js b/src/js/controllers/addressbookAdd.js index dcdb43b9f..9529d943e 100644 --- a/src/js/controllers/addressbookAdd.js +++ b/src/js/controllers/addressbookAdd.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('addressbookAddController', function($scope, $state, $stateParams, $timeout, $ionicHistory, gettextCatalog, addressbookService, popupService, configService, bitcoinCashJsService) { +angular.module('copayApp.controllers').controller('addressbookAddController', function($scope, $state, $stateParams, $timeout, $ionicHistory, gettextCatalog, addressbookService, popupService, configService, bitcoinCashJsService, platformInfo) { var config = configService.getSync(); var defaults = configService.getDefaults(); diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index f10121ee6..52695e829 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -38,9 +38,11 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.minShapeshiftAmount = parseFloat(data.stateParams.minShapeshiftAmount); $scope.maxShapeshiftAmount = parseFloat(data.stateParams.maxShapeshiftAmount); $scope.shapeshiftOrderId = data.stateParams.shapeshiftOrderId; - $scope.fromWalletId = data.stateParams.fromWalletId; } + // To get the wallet from with the new flow + $scope.fromWalletId = data.stateParams.fromWalletId; + if (data.stateParams.noPrefix) { $scope.showWarningMessage = data.stateParams.noPrefix != 0; if ($scope.showWarningMessage) { @@ -458,7 +460,8 @@ angular.module('copayApp.controllers').controller('amountController', function($ amount: $scope.useSendMax ? null : _amount, currency: unit.id.toUpperCase(), coin: coin, - useSendMax: $scope.useSendMax + useSendMax: $scope.useSendMax, + fromWalletId: $scope.fromWalletId }); } else { var amount = _amount; @@ -479,6 +482,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ toColor: $scope.toColor, coin: coin, useSendMax: $scope.useSendMax, + fromWalletId: $scope.fromWalletId }; if ($scope.shapeshiftOrderId) { diff --git a/src/js/controllers/buyBitcoindotcom.js b/src/js/controllers/buyBitcoindotcom.js index 741898c34..64766eede 100644 --- a/src/js/controllers/buyBitcoindotcom.js +++ b/src/js/controllers/buyBitcoindotcom.js @@ -1,7 +1,9 @@ 'use strict'; angular.module('copayApp.controllers').controller('buyBitcoindotcomController', - function($scope, $timeout, $ionicModal, $log, $state, $ionicHistory, lodash, bitcoincomService, externalLinkService, popupService) { + function($scope, platformInfo, externalLinkService) { + + $scope.os = platformInfo.isAndroid ? 'android' : platformInfo.isIOS ? 'ios' : 'desktop'; $scope.openExternalLink = function(url) { externalLinkService.open(url); diff --git a/src/js/controllers/feedback/rateApp.js b/src/js/controllers/feedback/rateApp.js deleted file mode 100644 index 6ae485a3a..000000000 --- a/src/js/controllers/feedback/rateApp.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('rateAppController', function($scope, $state, $stateParams, $window, lodash, externalLinkService, configService, platformInfo, feedbackService, ongoingProcess, popupService, appConfigService) { - $scope.score = parseInt($stateParams.score); - $scope.appName = appConfigService.nameCase; - var isAndroid = platformInfo.isAndroid; - var isIOS = platformInfo.isIOS; - - var config = configService.getSync(); - - $scope.skip = function() { - var dataSrc = { - "Email": lodash.values(config.emailFor)[0] || ' ', - "Feedback": ' ', - "Score": $stateParams.score, - "AppVersion": $window.version, - "Platform": ionic.Platform.platform(), - "DeviceVersion": ionic.Platform.version() - }; - feedbackService.send(dataSrc, function(err) { - if (err) { - // try to send, but not essential, since the user didn't add a message - $log.warn('Could not send feedback.'); - } - }); - $state.go('tabs.rate.complete', { - score: $stateParams.score, - skipped: true - }); - }; - - $scope.sendFeedback = function() { - $state.go('tabs.rate.send', { - score: $scope.score - }); - }; - - $scope.goAppStore = function() { - var defaults = configService.getDefaults(); - var url; - if (isAndroid) - url = defaults.rateApp.bitcoincom.android; - if (isIOS) - url = defaults.rateApp.bitcoincom.ios; - - externalLinkService.open(url); - $state.go('tabs.rate.complete', { - score: $stateParams.score, - skipped: true, - rated: true - }); - }; -}); diff --git a/src/js/controllers/feedback/rateCard.js b/src/js/controllers/feedback/rateCard.js deleted file mode 100644 index abc109796..000000000 --- a/src/js/controllers/feedback/rateCard.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('rateCardController', function($scope, $state, $timeout, $log, gettextCatalog, platformInfo, storageService, appConfigService) { - - $scope.isCordova = platformInfo.isCordova; - $scope.score = 0; - $scope.appName = appConfigService.nameCase; - - $scope.goFeedbackFlow = function() { - $scope.hideCard(); - if ($scope.isCordova && $scope.score == 5) { - $state.go('tabs.rate.rateApp', { - score: $scope.score - }); - } else { - $state.go('tabs.rate.send', { - score: $scope.score - }); - } - }; - - $scope.setScore = function(score) { - $scope.score = score; - switch ($scope.score) { - case 1: - $scope.button_title = gettextCatalog.getString("I think this app is terrible."); - break; - case 2: - $scope.button_title = gettextCatalog.getString("I don't like it"); - break; - case 3: - $scope.button_title = gettextCatalog.getString("Meh - it's alright"); - break; - case 4: - $scope.button_title = gettextCatalog.getString("I like the app"); - break; - case 5: - $scope.button_title = gettextCatalog.getString("This app is fantastic!"); - break; - } - $timeout(function() { - $scope.$apply(); - }); - }; - - $scope.hideCard = function() { - $log.debug('Feedback card dismissed.') - 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/send.js b/src/js/controllers/feedback/send.js deleted file mode 100644 index 23fb0ea59..000000000 --- a/src/js/controllers/feedback/send.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('sendController', function($scope, $state, $log, $timeout, $stateParams, $ionicNavBarDelegate, $ionicHistory, $ionicConfig, $window, gettextCatalog, popupService, configService, lodash, feedbackService, ongoingProcess, platformInfo, appConfigService) { - - $scope.sendFeedback = function(feedback, goHome) { - - var config = configService.getSync(); - - var dataSrc = { - "Email": lodash.values(config.emailFor)[0] || ' ', - "Feedback": goHome ? ' ' : feedback, - "Score": $stateParams.score || ' ', - "AppVersion": $window.version, - "Platform": ionic.Platform.platform(), - "DeviceVersion": ionic.Platform.version() - }; - - if (!goHome) ongoingProcess.set('sendingFeedback', true); - feedbackService.send(dataSrc, function(err) { - if (goHome) return; - ongoingProcess.set('sendingFeedback', false); - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Feedback could not be submitted. Please try again later.')); - return; - } - if (!$stateParams.score) { - popupService.showAlert(gettextCatalog.getString('Thank you!'), gettextCatalog.getString('A member of the team will review your feedback as soon as possible.'), function() { - $scope.feedback.value = ''; - $ionicHistory.nextViewOptions({ - disableAnimate: false, - historyRoot: true - }); - $ionicHistory.goBack(); - }, gettextCatalog.getString('Finish')); - return; - } - $state.go('tabs.rate.complete', { - score: $stateParams.score - }); - }); - if (goHome) $state.go('tabs.home'); - }; - - $scope.$on("$ionicView.beforeLeave", function(event, data) { - $ionicConfig.views.swipeBackEnabled(true); - }); - - $scope.$on("$ionicView.enter", function(event, data) { - if ($scope.score) - $ionicConfig.views.swipeBackEnabled(false); - }); - - $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.isCordova = platformInfo.isCordova; - $scope.score = (data.stateParams && data.stateParams.score) ? parseInt(data.stateParams.score) : null; - $scope.feedback = {}; - - switch ($scope.score) { - case 1: - $scope.reaction = "Ouch!"; - $scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong.") + ' ' + gettextCatalog.getString("How could we improve your experience?"); - break; - case 2: - $scope.reaction = gettextCatalog.getString("Oh no!"); - $scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong.") + ' ' + gettextCatalog.getString("How could we improve your experience?"); - break; - case 3: - $scope.reaction = "Hmm..."; - $scope.comment = gettextCatalog.getString("We'd love to do better.") + ' ' + gettextCatalog.getString("How could we improve your experience?"); - break; - case 4: - $scope.reaction = gettextCatalog.getString("Thanks!"); - $scope.comment = gettextCatalog.getString("That's exciting to hear. We'd love to earn that fifth star from you – how could we improve your experience?"); - break; - case 5: - $scope.reaction = gettextCatalog.getString("Thank you!"); - $scope.comment = gettextCatalog.getString("We're always looking for ways to improve {{appName}}.", { - appName: appConfigService.nameCase - }) + ' ' + gettextCatalog.getString("Is there anything we could do better?"); - break; - default: - $scope.justFeedback = true; - $scope.comment = gettextCatalog.getString("We're always looking for ways to improve {{appName}}. How could we improve your experience?", { - appName: appConfigService.nameCase - }); - break; - } - }); - - $scope.$on("$ionicView.afterEnter", function() { - $scope.showForm = true; - }); - - $scope.goBack = function() { - $ionicHistory.nextViewOptions({ - disableAnimate: false, - historyRoot: true - }); - $ionicHistory.goBack(); - }; - -}); diff --git a/src/js/controllers/feedback/complete.js b/src/js/controllers/shareApp.js similarity index 77% rename from src/js/controllers/feedback/complete.js rename to src/js/controllers/shareApp.js index 905880901..ba3fdedff 100644 --- a/src/js/controllers/feedback/complete.js +++ b/src/js/controllers/shareApp.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('completeController', function($scope, $stateParams, $timeout, $log, $ionicHistory, $state, $ionicNavBarDelegate, $ionicConfig, platformInfo, configService, storageService, lodash, appConfigService, gettextCatalog) { +angular.module('copayApp.controllers').controller('shareAppController', function($scope, $stateParams, $timeout, $log, $ionicHistory, $state, $ionicNavBarDelegate, $ionicConfig, platformInfo, configService, storageService, lodash, appConfigService, gettextCatalog) { $scope.isCordova = platformInfo.isCordova; $scope.title = gettextCatalog.getString("Share {{appName}}", { appName: appConfigService.nameCase @@ -57,28 +57,8 @@ angular.module('copayApp.controllers').controller('completeController', function $ionicConfig.views.swipeBackEnabled(true); }); - $scope.$on("$ionicView.enter", function() { - if (!$scope.fromSettings) - $ionicConfig.views.swipeBackEnabled(false); - }); - $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.score = (data.stateParams && data.stateParams.score) ? parseInt(data.stateParams.score) : null; - $scope.skipped = (data.stateParams && data.stateParams.skipped) ? true : false; - $scope.rated = (data.stateParams && data.stateParams.rated) ? true : false; - $scope.fromSettings = (data.stateParams && data.stateParams.fromSettings) ? true : false; - - if (!$scope.fromSettings) { - $ionicNavBarDelegate.showBackButton(false); - } else { - $ionicNavBarDelegate.showBackButton(true); - } - - storageService.getFeedbackInfo(function(error, info) { - var feedbackInfo = lodash.isString(info) ? JSON.parse(info) : null; - feedbackInfo.sent = true; - storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {}); - }); + $ionicNavBarDelegate.showBackButton(true); if (!$scope.isCordova) return; $scope.animate = true; @@ -133,13 +113,4 @@ angular.module('copayApp.controllers').controller('completeController', function } }, 100); }); - - $scope.close = function() { - $ionicHistory.nextViewOptions({ - disableAnimate: false, - historyRoot: true - }); - if ($scope.score == 5) $ionicHistory.goBack(-3); - else $ionicHistory.goBack(-2); - }; }); diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js index 3a56e6d5c..a04820ebd 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, $window, gettextCatalog, lodash, popupService, ongoingProcess, bannerService, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, feedbackService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, bitcoincomService, pricechartService, firebaseEventsService, servicesService, shapeshiftService, $ionicNavBarDelegate, signVerifyMessageService) { + function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, bannerService, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, bitcoincomService, pricechartService, firebaseEventsService, servicesService, shapeshiftService, $ionicNavBarDelegate, signVerifyMessageService) { var wallet; var listeners = []; var notifications = []; @@ -14,7 +14,6 @@ angular.module('copayApp.controllers').controller('tabHomeController', $scope.isAndroid = platformInfo.isAndroid; $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; $scope.isNW = platformInfo.isNW; - $scope.showRateCard = {}; $scope.showServices = false; $scope.bannerIsLoading = true; $scope.bannerImageUrl = ''; @@ -52,43 +51,6 @@ angular.module('copayApp.controllers').controller('tabHomeController', } }); } - - storageService.getFeedbackInfo(function(error, info) { - - if ($scope.isWindowsPhoneApp) { - $scope.showRateCard.value = false; - return; - } - if (!info) { - initFeedBackInfo(); - } else { - var feedbackInfo = JSON.parse(info); - //Check if current version is greater than saved version - var currentVersion = $scope.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 * 7 * 60 * 60; - $scope.showRateCard.value = timeExceeded && !feedbackInfo.sent; - $timeout(function() { - $scope.$apply(); - }); - } - }); - - function initFeedBackInfo() { - var feedbackInfo = {}; - feedbackInfo.time = moment().unix(); - feedbackInfo.version = $scope.version; - feedbackInfo.sent = false; - storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() { - $scope.showRateCard.value = false; - }); - }; }); $scope.$on("$ionicView.enter", function(event, data) { diff --git a/src/js/controllers/tab-send.js b/src/js/controllers/tab-send.js index 2282ab878..99265457d 100644 --- a/src/js/controllers/tab-send.js +++ b/src/js/controllers/tab-send.js @@ -1,32 +1,139 @@ 'use strict'; -angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicNavBarDelegate) { - +angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, $ionicLoading, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicPopup, $ionicNavBarDelegate, clipboardService) { + var clipboardHasAddress = false; + var clipboardHasContent = false; var originalList; - var CONTACTS_SHOW_LIMIT; - var currentContactsPage; - $scope.isChromeApp = platformInfo.isChromeApp; - $scope.sectionDisplay = { - transferToWallet: false + $scope.displayBalanceAsFiat = true; + $scope.walletSelectorTitleForce = true; + + $scope.addContact = function() { + $state.go('tabs.send.addressbook'); + }; + + $scope.pasteClipboard = function() { + if ($scope.clipboardHasAddress || $scope.clipboardHasContent) { + clipboardService.readFromClipboard(function(text) { + $scope.$apply(function() { + $scope.formData.search = text; + $scope.findContact($scope.formData.search); + }); + }); + } else { + $ionicPopup.alert({ + title: gettextCatalog.getString('Clipboard'), + template: gettextCatalog.getString('Your Clipboard is empty') + }); + } + }; + + $scope.$on("$ionicView.enter", function(event, data) { + clipboardService.readFromClipboard(function(text) { + if (text.length > 200) { + text = text.substring(0, 200); + } + + $scope.clipboardHasAddress = false; + $scope.clipboardHasContent = false; + if ((text.indexOf('bitcoincash:') === 0 || text[0] === 'C' || text[0] === 'H' || text[0] === 'p' || text[0] === 'q') && text.replace('bitcoincash:', '').length === 42) { // CashAddr + $scope.clipboardHasAddress = true; + } else if ((text[0] === "1" || text[0] === "3" || text.substring(0, 3) === "bc1") && text.length >= 26 && text.length <= 35) { // Legacy Addresses + $scope.clipboardHasAddress = true; + } else if (text.length > 1) { + $scope.clipboardHasContent = true; + } + }); + + $ionicNavBarDelegate.showBar(true); + if (!$scope.hasWallets) { + $scope.checkingBalance = false; + return; + } + updateHasFunds(); + updateContactsList(function() { + updateList(); + }); + }); + + var wallets; + var walletsBch; + var walletsBtc; + var walletToWalletFrom = false; + + $scope.onWalletSelect = function(wallet) { + if (!$scope.walletToWalletFrom) { + $scope.walletToWalletFrom = wallet; + if (wallet.coin === 'bch') { + $scope.showWalletsBch = true; + } else if (wallet.coin === 'btc') { + $scope.showWalletsBtc = true; + } + $scope.walletSelectorTitleTo = gettextCatalog.getString('Send to'); + } else { + $ionicLoading.show(); + walletService.getAddress(wallet, true, function(err, addr) { + $ionicLoading.hide(); + return $state.transitionTo('tabs.send.amount', { + displayAddress: $scope.walletToWalletFrom.coin === 'bch' ? bitcoinCashJsService.translateAddresses(addr).cashaddr : addr, + recipientType: 'wallet', + fromWalletId: $scope.walletToWalletFrom.id, + toAddress: addr, + coin: $scope.walletToWalletFrom.coin + }); + }); + + } + }; + + $scope.showWalletSelector = function() { + $scope.walletToWalletFrom = false; + $scope.walletSelectorTitleFrom = gettextCatalog.getString('Send from'); + $scope.showWallets = true; + }; + + $scope.findContact = function(search) { + + if (incomingData.redir(search)) { + return; + } + + if (!search || search.length < 1) { + $scope.list = originalList; + $timeout(function() { + $scope.$apply(); + }); + return; + } + + var result = lodash.filter(originalList, function(item) { + var val = item.name; + return lodash.startsWith(val.toLowerCase(), search.toLowerCase()); + }); + + $scope.list = result; }; var hasWallets = function() { + $scope.walletsWithFunds = profileService.getWallets({ + onlyComplete: true, + hasFunds: true + }); $scope.wallets = profileService.getWallets({ - onlyComplete: true + onlyComplete: true, + }); + $scope.walletsBch = profileService.getWallets({ + onlyComplete: true, + coin: 'bch' + }); + $scope.walletsBtc = profileService.getWallets({ + onlyComplete: true, + coin: 'btc' }); $scope.hasWallets = lodash.isEmpty($scope.wallets) ? false : true; }; - // THIS is ONLY to show the 'buy bitcoins' message - // does not has any other function. - var updateHasFunds = function() { - if ($rootScope.everHasFunds) { - $scope.hasFunds = true; - return; - } - $scope.hasFunds = false; var index = 0; lodash.each($scope.wallets, function(w) { @@ -41,10 +148,9 @@ angular.module('copayApp.controllers').controller('tabSendController', function( $scope.hasFunds = true; } else if (status.availableBalanceSat > 0) { $scope.hasFunds = true; - $rootScope.everHasFunds = true; } - if (index == $scope.wallets.length) { + if (index === $scope.wallets.length) { $scope.checkingBalance = false; $timeout(function() { $scope.$apply(); @@ -54,52 +160,6 @@ angular.module('copayApp.controllers').controller('tabSendController', function( }); }; - var updateWalletsList = function() { - var config = configService.getSync(); - var networkResult = lodash.countBy($scope.wallets, 'network'); - - $scope.showTransferCard = $scope.hasWallets && (networkResult.livenet > 1 || networkResult.testnet > 1); - - if ($scope.showTransferCard) { - var walletsToTransfer = $scope.wallets; - if (!(networkResult.livenet > 1)) { - walletsToTransfer = lodash.filter(walletsToTransfer, function(item) { - return item.network == 'testnet'; - }); - } - if (!(networkResult.testnet > 1)) { - walletsToTransfer = lodash.filter(walletsToTransfer, function(item) { - return item.network == 'livenet'; - }); - } - - var walletList = []; - lodash.each(walletsToTransfer, function(v) { - var displayBalanceAsFiat = - // BD got v.status as undefined here once during development, just - // after creating a new wallet. - v.status && - v.status.alternativeBalanceAvailable && - config.wallet.settings.priceDisplay === 'fiat'; - - walletList.push({ - color: v.color, - name: v.name, - recipientType: 'wallet', - coin: v.coin, - network: v.network, - balanceString: displayBalanceAsFiat ? - v.status.totalBalanceAlternative + ' ' + v.status.alternativeIsoCode : - v.cachedBalance, - getAddress: function(cb) { - walletService.getAddress(v, false, cb); - }, - }); - }); - originalList = originalList.concat(walletList); - } - } - var updateContactsList = function(cb) { var config = configService.getSync(); var defaults = configService.getDefaults(); @@ -118,16 +178,14 @@ angular.module('copayApp.controllers').controller('tabSendController', function( recipientType: 'contact', coin: v.coin, displayCoin: (v.coin == 'bch' - ? (config.bitcoinCashAlias || defaults.bitcoinCashAlias) - : (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase(), + ? (config.bitcoinCashAlias || defaults.bitcoinCashAlias) + : (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase(), getAddress: function(cb) { return cb(null, k); }, }); }); - var contacts = completeContacts.slice(0, (currentContactsPage + 1) * CONTACTS_SHOW_LIMIT); - $scope.contactsShowMore = completeContacts.length > contacts.length; - originalList = originalList.concat(contacts); + originalList = completeContacts; return cb(); }); }; @@ -140,28 +198,6 @@ angular.module('copayApp.controllers').controller('tabSendController', function( }, 10); }; - $scope.openScanner = function() { - var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; - - if (!isWindowsPhoneApp) { - $state.go('tabs.scan'); - return; - } - - scannerService.useOldScanner(function(err, contents) { - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err); - return; - } - incomingData.redir(contents); - }); - }; - - $scope.showMore = function() { - currentContactsPage++; - updateWalletsList(); - }; - $scope.searchInFocus = function() { $scope.searchFocus = true; }; @@ -172,28 +208,6 @@ angular.module('copayApp.controllers').controller('tabSendController', function( } }; - $scope.findContact = function(search) { - - if (incomingData.redir(search)) { - return; - } - - if (!search || search.length < 2) { - $scope.list = originalList; - $timeout(function() { - $scope.$apply(); - }); - return; - } - - var result = lodash.filter(originalList, function(item) { - var val = item.name; - return lodash.includes(val.toLowerCase(), search.toLowerCase()); - }); - - $scope.list = result; - }; - $scope.goToAmount = function(item) { $timeout(function() { item.getAddress(function(err, addr) { @@ -236,34 +250,19 @@ angular.module('copayApp.controllers').controller('tabSendController', function( }; $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.isIOS = platformInfo.isIOS && platformInfo.isCordova; + $scope.showWalletsBch = $scope.showWalletsBtc = $scope.showWallets = false; + $scope.checkingBalance = true; $scope.formData = { search: null }; originalList = []; - CONTACTS_SHOW_LIMIT = 10; - currentContactsPage = 0; hasWallets(); - }); - $scope.$on("$ionicView.enter", function(event, data) { - $ionicNavBarDelegate.showBar(true); - if (!$scope.hasWallets) { - $scope.checkingBalance = false; - return; - } - updateHasFunds(); - updateWalletsList(); - updateContactsList(function() { - updateList(); + configService.whenAvailable(function(_config) { + $scope.displayBalanceAsFiat = _config.wallet.settings.priceDisplay === 'fiat'; }); + }); - - $scope.toggle = function(section) { - $scope.sectionDisplay[section] = !$scope.sectionDisplay[section]; - $timeout(function() { - $ionicScrollDelegate.resize(); - $scope.$apply(); - }, 10); - }; }); diff --git a/src/js/controllers/tab-settings.js b/src/js/controllers/tab-settings.js index 6cfc80def..4d0636d53 100644 --- a/src/js/controllers/tab-settings.js +++ b/src/js/controllers/tab-settings.js @@ -45,6 +45,18 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct }); }; + $scope.sendFeedback = function() { + var mailToLink = 'mailto:wallet@bitcoin.com?subject=Feedback%20for%20Bitcoin.com%20Wallet'; + if (platformInfo.isNW) { + nw.Shell.openExternal(mailToLink); + } else if (platformInfo.isCordova) { + var mailWindow = window.open(mailToLink, '_system'); + mailWindow.close(); // XX SP: bugfix for some browsers in cordova to change the view entirely + } else { + window.location.href = mailToLink; + } + }; + $scope.openExternalLink = function() { var appName = appConfigService.name; var url = appName == 'copay' ? 'https://github.com/bitcoin-com/wallet/issues' : 'https://www.bitcoin.com/wallet-support'; diff --git a/src/js/directives/gravatar.js b/src/js/directives/gravatar.js index 5f7931798..c96a63cfe 100644 --- a/src/js/directives/gravatar.js +++ b/src/js/directives/gravatar.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.directives') - .directive('gravatar', function(md5) { + .directive('gravatar', function(md5, $http) { return { restrict: 'AE', replace: true, @@ -9,13 +9,24 @@ angular.module('copayApp.directives') name: '@', height: '@', width: '@', - email: '@' + email: '@', + url: '@' }, link: function(scope, el, attr) { if (typeof scope.email === "string") { scope.emailHash = md5.createHash(scope.email.toLowerCase() || ''); + var req = { + method: 'GET', + url: 'https://secure.gravatar.com/'+scope.emailHash+'.json', + }; + scope.url = 'img/contact-placeholder.svg'; + $http(req).then(function (response) { + scope.url = 'https://secure.gravatar.com/avatar/'+scope.emailHash+'.jpg?s='+scope.width+'&d=mm'; + }, function (error) { + scope.url = 'img/contact-placeholder.svg'; + }); } }, - template: '{{ name }}' + template: '{{ name }}' }; }); diff --git a/src/js/directives/walletSelector.js b/src/js/directives/walletSelector.js index 79053f812..8a96a0805 100644 --- a/src/js/directives/walletSelector.js +++ b/src/js/directives/walletSelector.js @@ -8,15 +8,21 @@ angular.module('copayApp.directives') transclude: true, scope: { title: '=walletSelectorTitle', + forceTitle: '=walletSelectorForceTitle', show: '=walletSelectorShow', wallets: '=walletSelectorWallets', selectedWallet: '=walletSelectorSelectedWallet', onSelect: '=walletSelectorOnSelect', + onHide: '=walletSelectorOnHide', displayBalanceAsFiat : '=walletSelectorDisplayBalanceAsFiat' }, link: function(scope, element, attrs) { + console.log(scope, element, attrs); scope.hide = function() { scope.show = false; + if (typeof scope.onHide === "function") { + scope.onHide() + } }; scope.selectWallet = function(wallet) { $timeout(function() { diff --git a/src/js/routes.js b/src/js/routes.js index 63b436a85..8277314e5 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -795,63 +795,15 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr fromOnboarding: null }, }) - - /* - * - * Feedback - * - */ - - .state('tabs.feedback', { - url: '/feedback', - views: { - 'tab-settings@tabs': { - templateUrl: 'views/feedback/send.html', - controller: 'sendController' - } - } - }) .state('tabs.shareApp', { - url: '/shareApp/:score/:skipped/:fromSettings', + url: '/shareApp', views: { 'tab-settings@tabs': { - controller: 'completeController', - templateUrl: 'views/feedback/complete.html' + controller: 'shareAppController', + templateUrl: 'views/shareApp.html' } } }) - .state('tabs.rate', { - url: '/rate', - abstract: true - }) - .state('tabs.rate.send', { - url: '/send/:score', - views: { - 'tab-home@tabs': { - templateUrl: 'views/feedback/send.html', - controller: 'sendController' - } - } - }) - .state('tabs.rate.complete', { - url: '/complete/:score/:skipped', - views: { - 'tab-home@tabs': { - controller: 'completeController', - templateUrl: 'views/feedback/complete.html' - } - } - }) - .state('tabs.rate.rateApp', { - url: '/rateApp/:score', - views: { - 'tab-home@tabs': { - controller: 'rateAppController', - templateUrl: 'views/feedback/rateApp.html' - } - } - }) - /* * * Buy or Sell Bitcoin diff --git a/src/js/services/bitcoincomService.js b/src/js/services/bitcoincomService.js index 681ed8f4d..051123111 100644 --- a/src/js/services/bitcoincomService.js +++ b/src/js/services/bitcoincomService.js @@ -1,12 +1,13 @@ 'use strict'; -angular.module('copayApp.services').factory('bitcoincomService', function($http, $log, lodash, moment, storageService, configService, platformInfo, nextStepsService, homeIntegrationsService) { +angular.module('copayApp.services').factory('bitcoincomService', function(platformInfo, nextStepsService) { var root = {}; var credentials = {}; /* * Development: 'testnet' * Production: 'livenet' - */ + */ + var os = platformInfo.isAndroid ? 'android' : platformInfo.isIOS ? 'ios' : 'desktop'; credentials.NETWORK = 'livenet'; //credentials.NETWORK = 'testnet'; @@ -20,28 +21,28 @@ angular.module('copayApp.services').factory('bitcoincomService', function($http, name: 'games', title: 'Bitcoin Cash Games', icon: 'icon-games', - href: 'http://cashgames.bitcoin.com' + href: 'https://cashgames.bitcoin.com' }; var newsItem = { name: 'news', title: 'News', icon: 'icon-news', - href: 'http://news.bitcoin.com' + href: 'https://news.bitcoin.com/?utm_source=WalletApp&utm_medium=' + os + '&utm_campaign=News' }; var poolItem = { name: 'pool', title: 'Mining Pool', icon: 'icon-mining', - href: 'http://pool.bitcoin.com' + href: 'https://pool.bitcoin.com/?utm_source=WalletApp&utm_medium=' + os + '&utm_campaign=Pool' }; var toolsItem = { name: 'tools', title: 'Tools', icon: 'icon-tools', - href: 'http://tools.bitcoin.com' + href: 'https://tools.bitcoin.com/?utm_source=WalletApp&utm_medium=' + os + '&utm_campaign=Tools' }; var priceChartItem = { @@ -55,7 +56,7 @@ angular.module('copayApp.services').factory('bitcoincomService', function($http, name: 'faucet', title: 'Free Bitcoin Cash', icon: 'icon-faucet', - href: 'https://free.bitcoin.com/' + href: 'https://free.bitcoin.com/?utm_source=WalletApp&utm_medium=' + os + '&utm_campaign=Faucet' }; var _getBitPay = function(endpoint) { diff --git a/src/js/services/clipboardService.js b/src/js/services/clipboardService.js index 8712e234b..075cb749a 100644 --- a/src/js/services/clipboardService.js +++ b/src/js/services/clipboardService.js @@ -22,7 +22,27 @@ angular.module('copayApp.services').factory('clipboardService', function ($http, // Not supported return; } + }; + root.readFromClipboard = function (cb) { + $log.debug("Read from clipboard"); + if (platformInfo.isCordova) { + cordova.plugins.clipboard.paste(function(text) { + cb(text); + }) + } else if (platformInfo.isNW) { + cb(nodeWebkitService.readFromClipboard()); + } else { + navigator.clipboard.readText() + .then(function (text) { + cb(text); + }) + .catch(function (err) { + $log.debug("Clipboard reading is not supported in browser.."); + }); + + return; + } }; return root; diff --git a/src/js/services/feedbackService.js b/src/js/services/feedbackService.js deleted file mode 100644 index ae4711d27..000000000 --- a/src/js/services/feedbackService.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; -angular.module('copayApp.services').factory('feedbackService', function($http, $log, $httpParamSerializer, configService) { - var root = {}; -// var URL = "https://script.google.com/macros/s/1pWGRxVSUX9CxPqNAKZTppWHtDvyVtZv9HteY_TRQbWc/exec"; - var URL = "https://wallet-data.bitcoin.com/feedback.php"; - - root.send = function(dataSrc, cb) { - $http(_post(dataSrc)).then(function() { - $log.info("SUCCESS: Feedback sent"); - return cb(); - }, function(err) { - $log.info("ERROR: Feedback sent anyway."); - return cb(err); - }); - }; - - var _post = function(dataSrc) { - return { - method: 'POST', - url: URL, - headers: { - 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - data: $httpParamSerializer(dataSrc) - }; - }; - - 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/incomingData.js b/src/js/services/incomingData.js index a318e1157..1bb87b49c 100644 --- a/src/js/services/incomingData.js +++ b/src/js/services/incomingData.js @@ -228,10 +228,12 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat } else if (/^https?:\/\//.test(data)) { payproService.getPayProDetails(data, coin, function(err, details) { if (err) { - root.showMenu({ - data: data, - type: 'url' - }); + if ($state.includes('tabs.scan')) { + root.showMenu({ + data: data, + type: 'url' + }); + } return; } handlePayPro(details); diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 10f0cdd76..c979098ee 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -217,14 +217,6 @@ angular.module('copayApp.services') }); }; - root.setFeedbackInfo = function(feedbackValues, cb) { - storage.set('feedback', feedbackValues, cb); - }; - - root.getFeedbackInfo = function(cb) { - storage.get('feedback', cb); - }; - root.storeFocusedWalletId = function(id, cb) { storage.set('focusedWalletId', id || '', cb); }; diff --git a/src/sass/buttons.scss b/src/sass/buttons.scss index 348d6d378..a8512ae64 100644 --- a/src/sass/buttons.scss +++ b/src/sass/buttons.scss @@ -16,6 +16,8 @@ &.button-primary, &.button-secondary, &.button-light, + &.button-white, + &.button-green, &.button-assertive { &.button-standard { @extend %button-standard; @@ -33,6 +35,10 @@ } } +@mixin button-shadow() { + box-shadow: 0 2px 11px 0 #C1C1C1;; +} + .button { &.button-secondary { @include button-style($v-button-secondary-bg, $v-button-secondary-border, $v-button-secondary-active-bg, $v-button-secondary-active-border, $v-button-secondary-color); @@ -47,7 +53,24 @@ } .button { + border-radius: 6px; &.button-full { display: block; } + &-green { + @include button-style(#719561, #FFF, #606060, #FFF, #FFF); + @include button-clear(#FFF); + @include button-outline(#C1C1C1); + border: 0px; + @include button-shadow(); + } + &-white { + @include button-style(#FFF, #C1C1C1, #C1C1C1, #FFF, #606060); + @include button-clear(#FFF); + @include button-outline(#C1C1C1); + @include button-shadow(); + &.activated { + color: #FFF; + } + } } \ No newline at end of file diff --git a/src/sass/views/address-book.scss b/src/sass/views/address-book.scss index c0d0f99a8..8bbdbc6be 100644 --- a/src/sass/views/address-book.scss +++ b/src/sass/views/address-book.scss @@ -124,7 +124,6 @@ position: relative; height: 70px; border-color: $royal; - background-color: $royal; padding-top: 20px; margin-bottom: 50px; text-align: center; diff --git a/src/sass/views/feedback/rateApp.scss b/src/sass/views/feedback/rateApp.scss deleted file mode 100644 index 8a4cd2b8e..000000000 --- a/src/sass/views/feedback/rateApp.scss +++ /dev/null @@ -1,38 +0,0 @@ -#rate-app { - background-color: #ffffff; - text-align: center; - .skip-rating { - color: $v-dark-gray; - position: absolute; - top: 5px; - right: 10px; - padding: 15px; - } - .icon-svg > img { - width: 80px; - height: 80px; - margin-top: 15px; - } - .feedback-title { - font-size: 20px; - font-weight: bold; - color: $v-dark-gray; - margin: 80px 50px 10px; - text-align: center; - } - .share-the-love-illustration { - width: 5rem; - margin: 1rem; - } - .subtitle { - padding: 10px 30px 20px 40px; - color: $v-mid-gray; - } - .rate-buttons { - bottom: 0; - width: 100%; - position: absolute; - background-color: $v-subtle-gray; - padding: 30px 0 15px; - } -} diff --git a/src/sass/views/feedback/rateCard.scss b/src/sass/views/feedback/rateCard.scss deleted file mode 100644 index 9d57643d6..000000000 --- a/src/sass/views/feedback/rateCard.scss +++ /dev/null @@ -1,18 +0,0 @@ -#rate-card { - .item-heading { - font-weight: 700; - } - .row { - border: none; - } - .item-icon-right { - margin: 0; - } - .feedback-flow-button { - margin-bottom: 20px; - } - .icon-svg > img { - height: 1.8rem; - margin-bottom: 5px; - } -} diff --git a/src/sass/views/feedback/send.scss b/src/sass/views/feedback/send.scss deleted file mode 100644 index 807c4f8c5..000000000 --- a/src/sass/views/feedback/send.scss +++ /dev/null @@ -1,54 +0,0 @@ -#send-feedback { - @extend .deflash-blue; - background-color: #ffffff; - .row { - border: none; - } - .skip { - color: rgba(255, 255, 255, 0.3); - } - .feedback-heading { - padding-top: 20px - } - .feedback-title { - padding-left: 10px; - font-size: 20px; - font-weight: bold; - color: $v-dark-gray; - } - .rating { - text-align: right; - padding-right: 15px; - } - .comment { - padding: 0 20px 20px; - font-size: 1rem; - line-height: 1.5em; - font-weight: 300; - color: $v-dark-gray; - } - .user-feedback { - border-top: 1px solid $v-subtle-gray; - border-bottom: 1px solid $v-subtle-gray; - padding: 20px; - width: 100%; - margin-bottom: 20px; - -webkit-appearance: none; - } - .send-feedback-star { - height: 1rem; - margin-left: 5px; - } - .form-fade-in { - opacity: 0; - animation-name: fadeIn; - animation-duration: .5s; - animation-fill-mode: forwards; - animation-timing-function: ease-in; - } -} - -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} diff --git a/src/sass/views/feedback/complete.scss b/src/sass/views/shareApp.scss similarity index 86% rename from src/sass/views/feedback/complete.scss rename to src/sass/views/shareApp.scss index bb2e75ea6..9a0ed0698 100644 --- a/src/sass/views/feedback/complete.scss +++ b/src/sass/views/shareApp.scss @@ -1,6 +1,6 @@ -#complete { +#share-app { background-color: #fff; - .complete-layout { + .share-app-layout { display: flex; flex-direction: column; height: 100%; @@ -22,17 +22,6 @@ width: 5rem; margin: 1rem; } - .send-feedback-illustration { - height: 16rem; - margin: 1rem; - } - .feedback-title { - font-size: 20px; - font-weight: bold; - color: $v-dark-gray; - margin: 20px 10px; - text-align: center; - } .subtitle { padding: 10px 30px 20px; text-align: center; diff --git a/src/sass/views/tab-send.scss b/src/sass/views/tab-send.scss index a969faedf..a4025156f 100644 --- a/src/sass/views/tab-send.scss +++ b/src/sass/views/tab-send.scss @@ -1,12 +1,28 @@ #tab-send { @extend .deflash-blue; + + &-header{ + height: 300px; + width: 100%; + } + &-contacts { + height: calc(100vh - 300px - 50px - 44px); /* screen size - button container - bottom-tab-menu - header top */ + &.ios { + height: calc(100vh - 300px - 50px - 44px - 18px); // Remove the notification-bar height on iOS + } + overflow: scroll; + } + .input { + width: 100%; input { width: 100%; - height: auto; - } - &.item { - height: 55px; + height: 57px; + background: #FFF; + border: 1px #D9D9D9 solid; + &::placeholder { + color: #DCDCDC; + } } i { &.left { @@ -19,45 +35,22 @@ } } } - .qr-scan-icon { - cursor: pointer; - cursor: hand; - border-left: 1px solid rgb(228, 228, 228); - padding-left: 10px; - } - .qr-icon { - line-height: 20px; - } - .zero-state-cta { - padding-bottom: 3vh; - left: 0; - } - .send-heading { - font-size: 14px; - font-weight: bold; - padding: 0 0 16px 0; - border: none; - } - .send-header-wrapper { - padding: 10px; - background-color: white; - box-shadow: 0px 5px 10px 0px #cccccc; - } - .search-wrapper { + + .send-wrapper { + &:after { + display: block; + position: relative; + height: 1px; + background: #DEDEDE; + bottom: 0; + content: ''; + margin: 10px 6px 0px; + } + padding: 18px 9px 9px 9px; background-color: #f2f2f2; border-radius: 3px; border: none; - .svg#Bitcoin_Symbol { - width: 14px; - .st0 { - fill: #cccccc; - } - } &.focus { - background: none; - .svg#Bitcoin_Symbol { - display: none; - } .search-input { padding-left: 30px; &:focus::-webkit-input-placeholder { @@ -65,57 +58,88 @@ } } } + .buttons { + margin: auto; + margin-top: 18px; + .button { + &-clipboard-paste { + margin-left: 0; + .address { + display: none; + } + .icon { + background: url(../img/icon-clipboard-paste.svg); + width: 15px; + height: 19px; + display: inline-block; + margin-bottom: 4px; + } + &.contains-address, &.contains-content { + .address { + display: none; + } + background: #FAB915; + color: #FFF !important; + border: 0; + @include button-shadow(); + .icon { + background: url(../img/icon-clipboard-paste-white.svg); + } + &.contains-address { + .address { + display: inline; + } + .non-address { + display: none; + } + } + } + } + span { + font-size: 14px; + } + img { + height: 16px; + width: auto; + margin: 2px 0 4px; + } + height: 60px; + line-height: 16px; + margin-right: 0px; + width: 95%; + max-width: none; + padding: 2px; + &-qr { + font-weight: bold; + max-width: none; + width: 100%; + height: 95px; + margin-top: 20px; + img { + vertical-align: middle; + margin-right: 12px; + width: 43px; + height: 43px; + } + span { + font-size: 19px; + } + } + } + } } - .abs-v-center { - position: absolute; - top: 50%; - transform: translateY(-50%); - } .search-input { background-color: transparent; padding-left: 30px; } - .separator-left { - border-left: 1px solid #d9d9df; - padding-left: 10px; - height: 70%; - } - .bitcoin-address { - border-top: none; - padding-bottom: .5rem; - @media(max-width: 480px) { - input { - font-size: 14px; - } - } - .icon { - line-height: 31px; - padding-top: 2px; - padding-bottom: 1px; - } - } - .show-more { - text-align: center; - padding: 20px; - font-size: 16px; - color: #387ef5; - font-weight: bold; - } .sendTip { + padding-top: 5vh; text-align: center; - & > .item-heading { - margin-top: 10px; - background: 0 none; - } - img { - content: $v-tab-send-selected-icon; - } .item { border-style: none; } & > .title { font-size: 20px; - font-weight: bold; color: $v-dark-gray; margin: 20px 10px; } @@ -123,34 +147,64 @@ font-size: 1rem; line-height: 1.5em; font-weight: 300; - color: $v-dark-gray; + color: #6F6F70; margin: 20px 1em 2.5em; } - .big-icon-svg{ - .bg.green{ + .big-icon-svg { + .bg.green { padding: 0 10px; box-shadow: none; } } + .buttons { + margin-top: 18px; + .button { + font-weight: bold; + font-size: 19px; + } + } + .button-first-contact img { + height: 19px; + width: 19px; + margin-right: 6px; + vertical-align: sub; + } + } + .item-heading { + line-height: 16px; + font-size: 14px; + font-weight: bold; + .subtitle { + color: #B5B2B2; + font-size: 12px; + font-weight: 300; + } } .list { .item { + font-weight: 600; + p { + font-weight: normal; + } + &.item-icon-left { + padding-left: 64px; + } color: #444; - border-top: none; - padding-top: 1.5rem; - padding-bottom: 1.5rem; + //border-top: none; + padding-top: 0.6rem; + padding-bottom: 0.6rem;; .big-icon-svg { - left:5px; - & > .bg{ - width:30px; - height:30px; - box-shadow: none; - } + left: 5px; + & > .bg { + width: 30px; + height: 30px; + box-shadow: none; + } } &:before { display: block; position: absolute; - width: 80%; + width: 100%; height: 1px; background: rgba(221, 221, 221, 0.3); top: 0; @@ -163,7 +217,7 @@ &.item-heading { &:before { top: 99%; - width:100%; + width: 100%; } } &:nth-child(2) { @@ -176,5 +230,40 @@ } } } - .scroll{height: 100%;} + .scroll { + height: 100%; + } + + .card.contacts { + margin: 4px 4px 16px 4px; + + border-radius: 6px; + box-shadow: 0px 2px 1px 0 #C1C1C1; + .gravatar { + border-radius: 30px; + height: 40px; + width: 40px; + } + } + + + ///* iPhone 5/SE and other small screen devices */ + @media only screen and (min-device-width : 320px) and (max-device-width : 568px) { + .send-wrapper .buttons .button-qr { + height: 60px; + span { + font-size: 16px; + } + } + #tab-send-header { + height: 270px; + } + #tab-send-contacts { + height: calc(100vh - 270px - 50px - 44px); /* screen size - button container - bottom-tab-menu - header top */ + &.ios { + height: calc(100vh - 270px - 50px - 44px - 18px); // Remove the notification-bar height on iOS + } + } + } + } diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss index 37754970f..d4ed735ed 100644 --- a/src/sass/views/views.scss +++ b/src/sass/views/views.scss @@ -22,10 +22,7 @@ @import "wallet-backup-phrase"; @import "zero-state"; @import "onboarding/onboarding"; -@import "feedback/rateCard"; -@import "feedback/send"; -@import "feedback/complete"; -@import "feedback/rateApp"; +@import "shareApp"; @import "includes/actionSheet"; @import "export"; @import "import"; diff --git a/www/img/contact-placeholder.svg b/www/img/contact-placeholder.svg index f730da86b..54b0fcec2 100644 --- a/www/img/contact-placeholder.svg +++ b/www/img/contact-placeholder.svg @@ -1,12 +1,18 @@ - - - - - - + + + + Artboard + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/img/icon-clipboard-paste-white.svg b/www/img/icon-clipboard-paste-white.svg new file mode 100644 index 000000000..be0df78bc --- /dev/null +++ b/www/img/icon-clipboard-paste-white.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/www/img/icon-clipboard-paste.svg b/www/img/icon-clipboard-paste.svg new file mode 100644 index 000000000..a82edc11b --- /dev/null +++ b/www/img/icon-clipboard-paste.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/www/img/icon-contact-add.svg b/www/img/icon-contact-add.svg new file mode 100644 index 000000000..36d1f95bc --- /dev/null +++ b/www/img/icon-contact-add.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/www/img/icon-scan-qr.svg b/www/img/icon-scan-qr.svg new file mode 100644 index 000000000..bc4a2bc56 --- /dev/null +++ b/www/img/icon-scan-qr.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/www/img/icon-w2w.svg b/www/img/icon-w2w.svg new file mode 100644 index 000000000..082a0d8cc --- /dev/null +++ b/www/img/icon-w2w.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/www/views/buyBitcoindotcom.html b/www/views/buyBitcoindotcom.html index 2c8ef36f1..f0f8e27e3 100644 --- a/www/views/buyBitcoindotcom.html +++ b/www/views/buyBitcoindotcom.html @@ -15,7 +15,7 @@
- +
diff --git a/www/views/feedback/rateApp.html b/www/views/feedback/rateApp.html deleted file mode 100644 index 9913b9d4e..000000000 --- a/www/views/feedback/rateApp.html +++ /dev/null @@ -1,21 +0,0 @@ - - - Not now - - -
- 5-star ratings help us get {{appName}} into more hands, and more users means more resources can be committed to the app! -
-
- Would you be willing to rate {{appName}} in the app store? -
-
- - -
-
-
diff --git a/www/views/feedback/rateCard.html b/www/views/feedback/rateCard.html deleted file mode 100644 index d31199466..000000000 --- a/www/views/feedback/rateCard.html +++ /dev/null @@ -1,43 +0,0 @@ -
-
- How do you like {{appName}}? - -
-
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
-
- -
-
diff --git a/www/views/feedback/send.html b/www/views/feedback/send.html deleted file mode 100644 index bb979bdee..000000000 --- a/www/views/feedback/send.html +++ /dev/null @@ -1,48 +0,0 @@ - - - {{'Send Feedback' | translate}} - - - - - - - - - - -
- {{comment}} -
-
- - -
-
-
diff --git a/www/views/includes/walletSelector.html b/www/views/includes/walletSelector.html index 136aa4694..97dfeb552 100644 --- a/www/views/includes/walletSelector.html +++ b/www/views/includes/walletSelector.html @@ -5,7 +5,7 @@ ng-init="wallet.coin == 'btc' ? walletsBtc.push(wallet) : walletsBch.push(wallet)"> -
{{title}}
+
{{title}}
Bitcoin Cash (BCH)
diff --git a/www/views/feedback/complete.html b/www/views/shareApp.html similarity index 55% rename from www/views/feedback/complete.html rename to www/views/shareApp.html index 03a98a476..f148e81a0 100644 --- a/www/views/feedback/complete.html +++ b/www/views/shareApp.html @@ -1,32 +1,16 @@ - + {{title}} - - - -
-
-
- -
Share the love by inviting your friends.
-
-
- -
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/tab-send.html b/www/views/tab-send.html index ab40e7e42..8b39808db 100644 --- a/www/views/tab-send.html +++ b/www/views/tab-send.html @@ -3,15 +3,57 @@ {{'Send' | translate}} +
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+
-
-
-
Recipient
-
- -
- - +
+
+
+ Send Bitcoin faster! +
+
+
+

Save frequently used addresses and send them Bitcoin in just one tap

+
+
@@ -19,72 +61,75 @@
-
-
- - - -
- Start sending bitcoin + Your Bitcoin wallet is empty
- To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service. - To get started, you'll need to create a bitcoin wallet and get some bitcoin. -
- - - +
+

To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address.

+

You can receive bitcoin from any wallet or service.

+
+
To get started, you'll need to create a bitcoin wallet and get some bitcoin.
+
+ + +
- -
-
- Contacts - - - -
-
- - - - - - {{item.name}} -

- {{item.displayCoin}} -

- -
-
- Show more +
+
+
+
+
Contacts
+
Saved frequently used addresses
+ + + +
+
- -
-
- Transfer to Wallet - - -
- -
- + + + + + + diff --git a/www/views/tab-settings.html b/www/views/tab-settings.html index 1105937d4..3091e63a6 100644 --- a/www/views/tab-settings.html +++ b/www/views/tab-settings.html @@ -22,14 +22,14 @@ - + {{'Send Feedback' | translate}} - +