diff --git a/src/js/controllers/activity.js b/src/js/controllers/activity.js index 29721ca3b..9ea9a31e9 100644 --- a/src/js/controllers/activity.js +++ b/src/js/controllers/activity.js @@ -26,7 +26,10 @@ angular.module('copayApp.controllers').controller('activityController', $scope.openNotificationModal = function(n) { if (n.txid) { - openTxModal(n); + $state.transitionTo('tabs.wallet.tx-details', { + txid: n.txid, + walletId: n.walletId + }); } else { var txp = lodash.find($scope.txps, { id: n.txpId @@ -46,35 +49,4 @@ angular.module('copayApp.controllers').controller('activityController', } } }; - - var openTxModal = function(n) { - var wallet = profileService.getWallet(n.walletId); - - ongoingProcess.set('loadingTxInfo', true); - walletService.getTx(wallet, n.txid, function(err, tx) { - ongoingProcess.set('loadingTxInfo', false); - - if (err) { - $log.error(err); - return popupService.showAlert(gettextCatalog.getString('Error'), err); - } - - if (!tx) { - $log.warn('No tx found'); - return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not found')); - } - - $scope.wallet = wallet; - $scope.btx = lodash.cloneDeep(tx); - $state.transitionTo('tabs.wallet.tx-details', { - txid: $scope.btx.txid, - walletId: $scope.walletId - }); - - walletService.getTxNote(wallet, n.txid, function(err, note) { - if (err) $log.warn('Could not fetch transaction note: ' + err); - $scope.btx.note = note; - }); - }); - }; }); diff --git a/src/js/controllers/feedback/rateAppStore.js b/src/js/controllers/feedback/rateAppStore.js new file mode 100644 index 000000000..b659fa516 --- /dev/null +++ b/src/js/controllers/feedback/rateAppStore.js @@ -0,0 +1,34 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('rateAppStoreController', function($scope, $state, $stateParams, externalLinkService, configService, gettextCatalog, platformInfo) { + $scope.score = parseInt($stateParams.score); + var isAndroid = platformInfo.isAndroid; + var isIOS = platformInfo.isIOS; + var isWP = platformInfo.isWP; + var config = configService.getSync(); + + $scope.skip = function() { + $state.go('feedback.thanks', { + score: $scope.score, + skipped: true + }); + }; + + $scope.sendFeedback = function() { + $state.go('feedback.sendFeedback', { + score: $scope.score + }); + }; + + $scope.goAppStore = function() { + var url; + if (isAndroid) url = config.rateApp.android; + if (isIOS) url = config.rateApp.ios; + // if (isWP) url = config.rateApp.ios; TODO + var title = gettextCatalog.getString('Rate the app'); + var message = gettextCatalog.getString('You must go to the official website of the app to rate it'); + var okText = gettextCatalog.getString('Go'); + var cancelText = gettextCatalog.getString('Cancel'); + externalLinkService.open(url, true, title, message, okText, cancelText); + }; +}); diff --git a/src/js/controllers/feedback/rateCard.js b/src/js/controllers/feedback/rateCard.js new file mode 100644 index 000000000..8eaa98cfa --- /dev/null +++ b/src/js/controllers/feedback/rateCard.js @@ -0,0 +1,61 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('rateCardController', function($scope, $state, $timeout, gettextCatalog, platformInfo, storageService) { + + $scope.isCordova = platformInfo.isCordova; + + $scope.goFeedbackFlow = function() { + if ($scope.isModal) { + $scope.rateModal.hide(); + $scope.rateModal.remove(); + } + if ($scope.isCordova && $scope.score == 5) { + $state.go('feedback.rateAppStore', { + score: $scope.score + }); + } else { + $state.go('feedback.sendFeedback', { + 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() { + if ($scope.isModal) { + $scope.rateModal.hide(); + $scope.rateModal.remove(); + } else { + storageService.setRateCardFlag('true', function() { + $scope.hideRateCard.value = true; + }); + } + $timeout(function() { + $scope.$apply(); + }) + } + +}); diff --git a/src/js/controllers/feedback/sendFeedback.js b/src/js/controllers/feedback/sendFeedback.js new file mode 100644 index 000000000..8899301c3 --- /dev/null +++ b/src/js/controllers/feedback/sendFeedback.js @@ -0,0 +1,52 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('sendFeedbackController', function($scope, $state, $log, $stateParams, gettextCatalog, popupService, configService, lodash, feedbackService, ongoingProcess) { + $scope.score = parseInt($stateParams.score); + switch ($scope.score) { + case 1: + $scope.reaction = gettextCatalog.getString("Ouch!"); + $scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong."); + break; + case 2: + $scope.reaction = gettextCatalog.getString("Oh no!"); + $scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong."); + break; + case 3: + $scope.reaction = gettextCatalog.getString("Thanks!"); + $scope.comment = gettextCatalog.getString("We're always looking for ways to improve BitPay wallet."); + 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."); + break; + case 5: + $scope.reaction = gettextCatalog.getString("Feedback!"); + $scope.comment = gettextCatalog.getString("We're always looking for ways to improve BitPay wallet."); + break; + } + + $scope.sendFeedback = function(feedback, skip) { + + var config = configService.getSync(); + + var dataSrc = { + "Email": lodash.values(config.emailFor)[0] || ' ', + "Feedback": skip ? ' ' : 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.thanks', { + score: $stateParams.score, + skipped: skip + }); + }); + }; + +}); diff --git a/src/js/controllers/feedback/thanks.js b/src/js/controllers/feedback/thanks.js new file mode 100644 index 000000000..7aa84334f --- /dev/null +++ b/src/js/controllers/feedback/thanks.js @@ -0,0 +1,76 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('thanksController', function($scope, $stateParams, $timeout, $log, platformInfo, configService, storageService) { + $scope.score = parseInt($stateParams.score); + $scope.skipped = $stateParams.skipped == 'false' ? false : true; + $scope.isCordova = platformInfo.isCordova; + var config = configService.getSync(); + + $scope.shareFacebook = function() { + window.plugins.socialsharing.shareViaFacebook(config.download.url, null, null, null); + }; + + $scope.shareTwitter = function() { + window.plugins.socialsharing.shareVia($scope.shareTwitterVia, config.download.url, null, null, null, null, null); + }; + + $scope.shareGooglePlus = function() { + window.plugins.socialsharing.shareVia($scope.shareGooglePlusVia, config.download.url, null, null, null); + }; + + $scope.shareEmail = function() { + window.plugins.socialsharing.shareViaEmail(config.download.url, null, null, null); + }; + + $scope.shareWhatsapp = function() { + window.plugins.socialsharing.shareViaWhatsApp(config.download.url, null, null, null); + }; + + $scope.shareMessage = function() { + window.plugins.socialsharing.shareViaSMS(config.download.url, null, null, null); + }; + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + storageService.setRateCardFlag('true', function() {}); + if (!$scope.isCordova) return; + + window.plugins.socialsharing.available(function(isAvailable) { + // the boolean is only false on iOS < 6 + $scope.socialsharing = isAvailable; + if (isAvailable) { + window.plugins.socialsharing.canShareVia('com.apple.social.facebook', 'msg', null, null, null, function(e) { + $scope.facebook = true; + }, function(e) { + $log.debug('facebook error: ' + e); + $scope.facebook = false; + }); + window.plugins.socialsharing.canShareVia('com.twitter.android', 'msg', null, null, null, function(e) { + $scope.shareTwitterVia = 'com.twitter.android'; + $scope.twitter = true; + }, function(e) { + $log.debug('twitter error: ' + e); + $scope.twitter = false; + }); + window.plugins.socialsharing.canShareVia('com.google.android.apps.plus', 'msg', null, null, null, function(e) { + $scope.shareGooglePlusVia = 'com.google.android.apps.plus'; + $scope.googleplus = true; + }, function(e) { + $log.debug('googlePlus error: ' + e); + $scope.googleplus = false; + }); + window.plugins.socialsharing.canShareViaEmail(function(e) { + $scope.email = true; + }, function(e) { + $log.debug('email error: ' + e); + $scope.email = false; + }); + window.plugins.socialsharing.canShareVia('whatsapp', 'msg', null, null, null, function(e) { + $scope.whatsapp = true; + }, function(e) { + $log.debug('whatsapp error: ' + e); + $scope.whatsapp = false; + }); + } + }, 100); + }); +}); diff --git a/src/js/controllers/onboarding/welcomeController.js b/src/js/controllers/onboarding/welcomeController.js index 3a1651f75..3b74544a7 100644 --- a/src/js/controllers/onboarding/welcomeController.js +++ b/src/js/controllers/onboarding/welcomeController.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('welcomeController', function($scope, $state, $timeout, $ionicConfig, $log, profileService, startupService) { +angular.module('copayApp.controllers').controller('welcomeController', function($scope, $state, $timeout, $ionicConfig, $log, profileService, startupService, storageService) { $ionicConfig.views.swipeBackEnabled(false); @@ -19,7 +19,13 @@ 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/tab-home.js b/src/js/controllers/tab-home.js index 656949602..bf8443081 100644 --- a/src/js/controllers/tab-home.js +++ b/src/js/controllers/tab-home.js @@ -13,27 +13,100 @@ angular.module('copayApp.controllers').controller('tabHomeController', $scope.isCordova = platformInfo.isCordova; $scope.isAndroid = platformInfo.isAndroid; $scope.isNW = platformInfo.isNW; + $scope.hideRateCard = {}; $scope.$on("$ionicView.afterEnter", function() { startupService.ready(); }); - if (!$scope.homeTip) { - storageService.getHomeTipAccepted(function(error, value) { - $scope.homeTip = (value == 'accepted') ? false : true; - }); - } + $scope.$on("$ionicView.beforeEnter", function(event, data) { + if (!$scope.homeTip) { + storageService.getHomeTipAccepted(function(error, value) { + $scope.homeTip = (value == 'accepted') ? false : true; + }); + } - if ($scope.isNW) { - latestReleaseService.checkLatestRelease(function(err, newRelease) { - if (err) { - $log.warn(err); - return; - } + if ($scope.isNW) { + latestReleaseService.checkLatestRelease(function(err, newRelease) { + if (err) { + $log.warn(err); + return; + } - if (newRelease) $scope.newRelease = true; + if (newRelease) $scope.newRelease = true; + }); + } + + 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; + }); }); - } + + }); + + $scope.$on("$ionicView.enter", function(event, data) { + updateAllWallets(); + + addressbookService.list(function(err, ab) { + if (err) $log.error(err); + $scope.addressbook = ab || {}; + }); + + listeners = [ + $rootScope.$on('bwsEvent', function(e, walletId, type, n) { + var wallet = profileService.getWallet(walletId); + updateWallet(wallet); + if ($scope.recentTransactionsEnabled) getNotifications(); + }), + $rootScope.$on('Local/TxAction', function(e, walletId) { + $log.debug('Got action for wallet ' + walletId); + var wallet = profileService.getWallet(walletId); + updateWallet(wallet); + if ($scope.recentTransactionsEnabled) getNotifications(); + }) + ]; + + configService.whenAvailable(function() { + nextStep(function() { + var config = configService.getSync(); + var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + + $scope.glideraEnabled = config.glidera.enabled && !isWindowsPhoneApp; + $scope.coinbaseEnabled = config.coinbase.enabled && !isWindowsPhoneApp; + $scope.amazonEnabled = config.amazon.enabled; + $scope.bitpayCardEnabled = config.bitpayCard.enabled; + + var buyAndSellEnabled = !$scope.externalServices.BuyAndSell && ($scope.glideraEnabled || $scope.coinbaseEnabled); + var amazonEnabled = !$scope.externalServices.AmazonGiftCards && $scope.amazonEnabled; + var bitpayCardEnabled = !$scope.externalServices.BitpayCard && $scope.bitpayCardEnabled; + + $scope.nextStepEnabled = buyAndSellEnabled || amazonEnabled || bitpayCardEnabled; + $scope.recentTransactionsEnabled = config.recentTransactions.enabled; + + if ($scope.recentTransactionsEnabled) getNotifications(); + + if ($scope.bitpayCardEnabled) bitpayCardCache(); + $timeout(function() { + $ionicScrollDelegate.resize(); + $scope.$apply(); + }, 10); + }); + }); + }); + + $scope.$on("$ionicView.leave", function(event, data) { + lodash.each(listeners, function(x) { + x(); + }); + }); + + $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); @@ -43,7 +116,10 @@ angular.module('copayApp.controllers').controller('tabHomeController', wallet = profileService.getWallet(n.walletId); if (n.txid) { - openTxModal(n); + $state.transitionTo('tabs.wallet.tx-details', { + txid: n.txid, + walletId: n.walletId + }); } else { var txp = lodash.find($scope.txps, { id: n.txpId @@ -65,37 +141,6 @@ angular.module('copayApp.controllers').controller('tabHomeController', } }; - var openTxModal = function(n) { - wallet = profileService.getWallet(n.walletId); - - ongoingProcess.set('loadingTxInfo', true); - walletService.getTx(wallet, n.txid, function(err, tx) { - ongoingProcess.set('loadingTxInfo', false); - - if (err) { - $log.error(err); - return popupService.showAlert(gettextCatalog.getString('Error'), err); - } - - if (!tx) { - $log.warn('No tx found'); - return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not found')); - } - - $scope.wallet = wallet; - $scope.btx = lodash.cloneDeep(tx); - $state.transitionTo('tabs.wallet.tx-details', { - txid: $scope.btx.txid, - walletId: $scope.walletId - }); - - walletService.getTxNote(wallet, n.txid, function(err, note) { - if (err) $log.warn('Could not fetch transaction note: ' + err); - $scope.btx.note = note; - }); - }); - }; - $scope.openWallet = function(wallet) { if (!wallet.isComplete()) { return $state.go('tabs.copayers', { @@ -117,6 +162,7 @@ angular.module('copayApp.controllers').controller('tabHomeController', $scope.txpsN = n; $timeout(function() { $ionicScrollDelegate.resize(); + $scope.$apply(); }, 100); }) }; @@ -141,25 +187,6 @@ angular.module('copayApp.controllers').controller('tabHomeController', } }); }); - - if (!$scope.recentTransactionsEnabled) return; - $scope.fetchingNotifications = true; - profileService.getNotifications({ - limit: 3 - }, function(err, n) { - if (err) { - $log.error(err); - return; - } - $scope.fetchingNotifications = false; - $scope.notifications = n; - - $timeout(function() { - $ionicScrollDelegate.resize(); - $scope.$apply(); - }, 100); - - }) }; var updateWallet = function(wallet) { @@ -171,20 +198,22 @@ angular.module('copayApp.controllers').controller('tabHomeController', } wallet.status = status; updateTxps(); + }); + }; - if (!$scope.recentTransactionsEnabled) return; - - $scope.fetchingNotifications = true; - profileService.getNotifications({ - limit: 3 - }, function(err, notifications) { - $scope.fetchingNotifications = false; - if (err) { - $log.error(err); - return; - } - $scope.notifications = notifications; - }); + var getNotifications = function() { + profileService.getNotifications({ + limit: 3 + }, function(err, n) { + if (err) { + $log.error(err); + return; + } + $scope.notifications = n; + $timeout(function() { + $ionicScrollDelegate.resize(); + $scope.$apply(); + }, 100); }); }; @@ -241,57 +270,4 @@ angular.module('copayApp.controllers').controller('tabHomeController', }, 300); updateAllWallets(); }; - - $scope.$on("$ionicView.enter", function(event, data) { - updateAllWallets(); - - addressbookService.list(function(err, ab) { - if (err) $log.error(err); - $scope.addressbook = ab || {}; - }); - - listeners = [ - $rootScope.$on('bwsEvent', function(e, walletId, type, n) { - var wallet = profileService.getWallet(walletId); - updateWallet(wallet); - }), - $rootScope.$on('Local/TxAction', function(e, walletId) { - $log.debug('Got action for wallet ' + walletId); - var wallet = profileService.getWallet(walletId); - updateWallet(wallet); - }) - ]; - - configService.whenAvailable(function() { - nextStep(function() { - var config = configService.getSync(); - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; - - $scope.glideraEnabled = config.glidera.enabled && !isWindowsPhoneApp; - $scope.coinbaseEnabled = config.coinbase.enabled && !isWindowsPhoneApp; - $scope.amazonEnabled = config.amazon.enabled; - $scope.bitpayCardEnabled = config.bitpayCard.enabled; - - var buyAndSellEnabled = !$scope.externalServices.BuyAndSell && ($scope.glideraEnabled || $scope.coinbaseEnabled); - var amazonEnabled = !$scope.externalServices.AmazonGiftCards && $scope.amazonEnabled; - var bitpayCardEnabled = !$scope.externalServices.BitpayCard && $scope.bitpayCardEnabled; - - $scope.nextStepEnabled = buyAndSellEnabled || amazonEnabled || bitpayCardEnabled; - $scope.recentTransactionsEnabled = config.recentTransactions.enabled; - - if ($scope.bitpayCardEnabled) bitpayCardCache(); - $timeout(function() { - $ionicScrollDelegate.resize(); - $scope.$apply(); - }, 10); - }); - }); - }); - - $scope.$on("$ionicView.leave", function(event, data) { - lodash.each(listeners, function(x) { - x(); - }); - }); - }); diff --git a/src/js/controllers/tab-settings.js b/src/js/controllers/tab-settings.js index 773a6a5f3..13d482102 100644 --- a/src/js/controllers/tab-settings.js +++ b/src/js/controllers/tab-settings.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, $window, uxLanguage, platformInfo, profileService, feeService, configService, externalLinkService) { +angular.module('copayApp.controllers').controller('tabSettingsController', function($scope, $window, $ionicModal, uxLanguage, platformInfo, profileService, feeService, configService, externalLinkService) { var updateConfig = function() { @@ -32,4 +32,15 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct updateConfig(); }); + $scope.openRateModal = function() { + $scope.isModal = true; + $ionicModal.fromTemplateUrl('views/feedback/rateCard.html', { + scope: $scope, + backdropClickToClose: false, + hardwareBackButtonClose: false + }).then(function(modal) { + $scope.rateModal = modal; + $scope.rateModal.show(); + }); + } }); diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index e41cca9c2..1b6beb58b 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('txDetailsController', function($log, $timeout, $ionicHistory, $scope, $stateParams, walletService, lodash, gettextCatalog, profileService, configService, externalLinkService, popupService) { +angular.module('copayApp.controllers').controller('txDetailsController', function($log, $ionicHistory, $scope, walletService, lodash, gettextCatalog, profileService, configService, externalLinkService, popupService, ongoingProcess) { $scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.title = gettextCatalog.getString('Transaction'); @@ -9,11 +9,13 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio $scope.copayerId = $scope.wallet.credentials.copayerId; $scope.isShared = $scope.wallet.credentials.n > 1; - walletService.getTx($scope.wallet, $stateParams.txid, function(err, tx) { + ongoingProcess.set('loadingTxInfo', true); + walletService.getTx($scope.wallet, data.stateParams.txid, function(err, tx) { + ongoingProcess.set('loadingTxInfo', false); if (err) { $log.warn('Could not get tx'); $ionicHistory.goBack(); - return; + return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not found')); } $scope.btx = tx; if ($scope.btx.action != 'invalid') { @@ -130,6 +132,27 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio return n.substring(0, 4); }; + $scope.getFiatRate = function() { + if ($scope.rateDate) return; + var alternativeIsoCode = $scope.wallet.status.alternativeIsoCode; + $scope.loadingRate = true; + $scope.wallet.getFiatRate({ + code: alternativeIsoCode, + ts: $scope.btx.time * 1000 + }, function(err, res) { + $scope.loadingRate = false; + if (err) { + $log.debug('Could not get historic rate'); + return; + } + if (res && res.rate) { + $scope.rateDate = res.fetchedOn; + $scope.rateStr = res.rate + ' ' + alternativeIsoCode; + $scope.$apply(); + } + }); + }; + $scope.cancel = function() { $scope.txDetailsModal.hide(); }; diff --git a/src/js/routes.js b/src/js/routes.js index 2b92f5af2..ee65083d3 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -720,13 +720,50 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr }, }) - /* * - * Buy or Sell Bitcoin + * Feedback * */ + .state('feedback', { + url: '/feedback', + abstract: true, + template: '' + }) + .state('feedback.sendFeedback', { + url: '/sendFeedback/:score', + views: { + 'feedback': { + controller: 'sendFeedbackController', + templateUrl: 'views/feedback/sendFeedback.html' + } + } + }) + .state('feedback.thanks', { + url: '/thanks/:score/:skipped', + views: { + 'feedback': { + controller: 'thanksController', + templateUrl: 'views/feedback/thanks.html' + } + } + }) + .state('feedback.rateAppStore', { + url: '/rateAppStore/:score', + views: { + 'feedback': { + controller: 'rateAppStoreController', + templateUrl: 'views/feedback/rateAppStore.html' + } + } + }) + /* + * + * Buy or Sell Bitcoin + * + */ + .state('tabs.buyandsell', { url: '/buyandsell', views: { diff --git a/src/js/services/configService.js b/src/js/services/configService.js index 618118e35..a51906f82 100644 --- a/src/js/services/configService.js +++ b/src/js/services/configService.js @@ -15,6 +15,16 @@ angular.module('copayApp.services').factory('configService', function(storageSer url: 'https://bws.bitpay.com/bws/api', }, + download: { + url: 'https://bitpay.com/wallet', + }, + + rateApp: { + ios: 'https://itunes.apple.com/app/bitpay-secure-bitcoin-wallet/id1149581638', + android: 'https://play.google.com/store/apps/details?id=com.bitpay.wallet', + wp: '' + }, + // wallet default config wallet: { requiredCopayers: 2, diff --git a/src/js/services/feedbackService.js b/src/js/services/feedbackService.js new file mode 100644 index 000000000..0a1788edc --- /dev/null +++ b/src/js/services/feedbackService.js @@ -0,0 +1,28 @@ +'use strict'; +angular.module('copayApp.services').factory('feedbackService', function($http, $log, $httpParamSerializer, configService) { + var root = {}; + var URL = "https://script.google.com/macros/s/AKfycbybtvNSQKUfgzgXcj3jYLlvCKrcBoktjiJ1V8_cwd2yVkpUBGe3/exec"; + + 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) + }; + }; + + return root; +}); diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index d1bcf2fe0..acede937d 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -33,6 +33,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti 'validatingWallet': gettext('Validating wallet integrity...'), 'validatingWords': gettext('Validating recovery phrase...'), 'loadingTxInfo': gettext('Loading transaction info...'), + 'sendingFeedback': gettext('Sending feedback...'), }; root.clear = function() { @@ -64,7 +65,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti var showName = $filter('translate')(processNames[name] || name); - if(customHandler) { + if (customHandler) { customHandler(processName, showName, isOn); } else if (root.onGoingProcessName) { if (isCordova) { diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 4c65a3f48..78f99a86b 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -795,7 +795,7 @@ angular.module('copayApp.services') root.getNotifications = function(opts, cb) { opts = opts || {}; - var TIME_STAMP = 60 * 60 * 24 * 7; + var TIME_STAMP = 60 * 60 * 6; var MAX = 100; var typeFilter = { @@ -861,26 +861,25 @@ angular.module('copayApp.services') var finale = shown; // GROUPING DISABLED! - // var finale = [], - // prev; - // - // - // // Item grouping... DISABLED. - // - // // REMOVE (if we want 1-to-1 notification) ???? - // lodash.each(shown, function(x) { - // if (prev && prev.walletId === x.walletId && prev.txpId && prev.txpId === x.txpId && prev.creatorId && prev.creatorId === x.creatorId) { - // prev.types.push(x.type); - // prev.data = lodash.assign(prev.data, x.data); - // prev.txid = prev.txid || x.txid; - // prev.amountStr = prev.amountStr || x.amountStr; - // prev.creatorName = prev.creatorName || x.creatorName; - // } else { - // finale.push(x); - // prev = x; - // } - // }); - // + var finale = [], + prev; + + + // Item grouping... DISABLED. + + // REMOVE (if we want 1-to-1 notification) ???? + lodash.each(shown, function(x) { + if (prev && prev.walletId === x.walletId && prev.txpId && prev.txpId === x.txpId && prev.creatorId && prev.creatorId === x.creatorId) { + prev.types.push(x.type); + prev.data = lodash.assign(prev.data, x.data); + prev.txid = prev.txid || x.txid; + prev.amountStr = prev.amountStr || x.amountStr; + prev.creatorName = prev.creatorName || x.creatorName; + } else { + finale.push(x); + prev = x; + } + }); var u = bwcService.getUtils(); lodash.each(finale, function(x) { diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 4184f8454..60545747a 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -138,6 +138,14 @@ angular.module('copayApp.services') storage.remove('profile', cb); }; + root.setProfileCreationTime = function(time, cb) { + storage.set('profileCreationTime', time, cb); + }; + + root.getProfileCreationTime = function(cb) { + storage.get('profileCreationTime', cb); + }; + root.storeFocusedWalletId = function(id, cb) { storage.set('focusedWalletId', id || '', cb); }; @@ -203,6 +211,14 @@ 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); }; diff --git a/src/sass/views/feedback/rateAppStore.scss b/src/sass/views/feedback/rateAppStore.scss new file mode 100644 index 000000000..5003e6b02 --- /dev/null +++ b/src/sass/views/feedback/rateAppStore.scss @@ -0,0 +1,27 @@ +#rate-app-store { + background-color: #ffffff; + .skip { + margin: 10px; + color: #667; + } + .title { + font-size: 20px; + font-weight: bold; + color: $dark-gray; + margin: 40px 10px; + text-align: center; + } + .subtitle { + padding: 10px 30px 20px 40px; + } + .buttons { + bottom: 0; + width: 100%; + position: absolute; + background-color: $subtle-gray; + .button { + margin-top: 40px; + margin-bottom: 30px; + } + } +} diff --git a/src/sass/views/feedback/rateCard.scss b/src/sass/views/feedback/rateCard.scss new file mode 100644 index 000000000..9d01ea078 --- /dev/null +++ b/src/sass/views/feedback/rateCard.scss @@ -0,0 +1,22 @@ +#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; + } + } + .feedback-flow-button { + padding: 20px; + } +} diff --git a/src/sass/views/feedback/sendFeedBack.scss b/src/sass/views/feedback/sendFeedBack.scss new file mode 100644 index 000000000..33b1720ca --- /dev/null +++ b/src/sass/views/feedback/sendFeedBack.scss @@ -0,0 +1,39 @@ +#send-feedback { + background-color: #ffffff; + .skip { + margin: 20px 20px 10px; + color: #667; + text-decoration: none; + } + .title { + padding: 20px; + font-size: 20px; + 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; + line-height: 1.5em; + font-weight: 300; + color: $dark-gray; + } + textarea { + padding: 20px; + border-top: 1px solid $subtle-gray; + padding: 20px; + width: 100%; + } +} diff --git a/src/sass/views/feedback/thanks.scss b/src/sass/views/feedback/thanks.scss new file mode 100644 index 000000000..2d86c357f --- /dev/null +++ b/src/sass/views/feedback/thanks.scss @@ -0,0 +1,44 @@ +#thanks-feedback { + background-color: #ffffff; + .item-heading { + border-style: none; + margin-top: 10px; + a { + color: $dark-gray; + } + i { + font-size: 40px; + } + } + .title { + font-size: 20px; + font-weight: bold; + color: $dark-gray; + margin: 20px 10px; + text-align: center; + } + .subtitle { + padding: 10px 30px 20px 40px; + .image { + text-align: center; + padding: 30px; + } + } + .share-buttons { + bottom: 0; + width: 100%; + position: absolute; + background-color: $subtle-gray; + .row { + margin: 20px 0px 20px; + span { + margin-top: 15px; + display: block; + } + div { + text-align: center; + width: 100%; + } + } + } +} diff --git a/src/sass/views/tab-home.scss b/src/sass/views/tab-home.scss index 5ecd6d819..ca1a7bde9 100644 --- a/src/sass/views/tab-home.scss +++ b/src/sass/views/tab-home.scss @@ -125,6 +125,6 @@ font-size: 20px; margin-left: 10px; position: absolute; - } + } } } diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss index c449d07db..5b3e8290d 100644 --- a/src/sass/views/views.scss +++ b/src/sass/views/views.scss @@ -17,6 +17,10 @@ @import "wallet-backup-phrase"; @import "zero-state"; @import "onboarding/onboarding"; +@import "feedback/rateCard"; +@import "feedback/sendFeedback"; +@import "feedback/thanks"; +@import "feedback/rateAppStore"; @import "includes/actionSheet"; @import "export"; @import "import"; diff --git a/www/views/activity.html b/www/views/activity.html index fb84142dc..8586e97e9 100644 --- a/www/views/activity.html +++ b/www/views/activity.html @@ -1,7 +1,7 @@ - {{'Recent Activity'|translate}} + {{'Recent Transactions'|translate}} @@ -11,7 +11,7 @@ - Updating activity. Please stand by + Updating... Please stand by @@ -22,7 +22,7 @@ - No recent activity + No recent transactions diff --git a/www/views/feedback/rateAppStore.html b/www/views/feedback/rateAppStore.html new file mode 100644 index 000000000..3da6ed36b --- /dev/null +++ b/www/views/feedback/rateAppStore.html @@ -0,0 +1,27 @@ + + + Skip + + Thank you! + + + + + + + + 5-star ratings help us get BitPay Wallet into more hands, and more users means more resoucers can be committed to the app! + + + Would you be willing to rate BitPay Wallet in the app store? + + + + Rate on the app store + + + Send us feedback instead + + + + diff --git a/www/views/feedback/rateCard.html b/www/views/feedback/rateCard.html new file mode 100644 index 000000000..fd9f95f73 --- /dev/null +++ b/www/views/feedback/rateCard.html @@ -0,0 +1,18 @@ + + + How do you like BitPay Wallet? + + + + + + + + + + + + {{button_title}} + + + diff --git a/www/views/feedback/sendFeedback.html b/www/views/feedback/sendFeedback.html new file mode 100644 index 000000000..f22e175e8 --- /dev/null +++ b/www/views/feedback/sendFeedback.html @@ -0,0 +1,26 @@ + + Skip + + + {{reaction}} + + + + + + + + + + {{comment}} + + + + + + + Send + + + + diff --git a/www/views/feedback/thanks.html b/www/views/feedback/thanks.html new file mode 100644 index 000000000..826f65675 --- /dev/null +++ b/www/views/feedback/thanks.html @@ -0,0 +1,79 @@ + + + + + + + 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. + + + + + + + + + + Facebook + + + + + + Twitter + + + + + + Google+ + + + + + + + + Email + + + + + + Whatsapp + + + + + + Message + + + + + + diff --git a/www/views/tab-home.html b/www/views/tab-home.html index 1c972afd6..716b44573 100644 --- a/www/views/tab-home.html +++ b/www/views/tab-home.html @@ -10,9 +10,12 @@ spinner="ios-small" on-refresh="onRefresh()"> - + An update to this app is available + + + @@ -47,10 +50,6 @@ Recent Transactions - - - Updating activity... - diff --git a/www/views/tab-settings.html b/www/views/tab-settings.html index 075ff0a81..735a125e8 100644 --- a/www/views/tab-settings.html +++ b/www/views/tab-settings.html @@ -29,7 +29,7 @@ - + diff --git a/www/views/tx-details.html b/www/views/tx-details.html index 22dd3472f..0008b66e2 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -22,7 +22,13 @@ {{displayAmount}} {{displayUnit}} - {{btx.alternativeAmountStr}} + + {{btx.alternativeAmountStr}} + + {{rateStr}} ({{rateDate | amDateFormat:'MM/DD/YYYY HH:mm a'}}) + ... + +