Merge sprint 19.

# Conflicts:
#	src/js/controllers/tab-home.js
This commit is contained in:
Brendon Duncan 2018-07-13 21:19:28 +12:00
commit 0bb4de9bd1
49 changed files with 4115 additions and 3815 deletions

View file

@ -0,0 +1,78 @@
'use strict';
angular.module('copayApp.services').factory('bannerService', function ($http, $log) {
// Export
var root = {};
// Constant
var API_URL = 'https://bwscash.bitcoin.com/bws/api/v1/marketing';
// Variable
var hasFetched = false;
var banners = [];
var defaultBanner = {
id: 'default-banner',
imageURL: 'img/banner-store.png',
url: 'https://store.bitcoin.com/',
isLocal: true
};
// Private methods
var fetchSettings = function (cb) {
var req = {
method: 'GET',
url: API_URL+'/settings',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
$http(req).then(function (response) {
$log.info('Get banner settings: SUCCESS');
banners = response.data;
return cb(true);
}, function (error) {
$log.error('Get banner settings: ERROR ' + error.statusText);
return cb(false);
});
};
root.getBanner = function (cb) {
// If not fetch get the banner
if (!hasFetched) {
hasFetched = true;
// If never fetch, lets fetch
fetchSettings(function (isSuccess) {
root.getBanner(cb);
});
// If fetch, and got banners, lets have a look
} else if (banners.length > 0) {
var selectedBanners = [];
for(var i in banners) {
var banner = banners[i];
// Generate the URL for the banner
var fileName = banner.image.substring(0, banner.image.lastIndexOf('.'));
var extension = banner.image.substring(banner.image.lastIndexOf('.')+1);
banner.imageURL = API_URL +'/banners/'+fileName+"/"+extension;
// Add the banner
selectedBanners.push(banners[i]);
}
// If no banner activated, return the default one
if (selectedBanners.length == 0) {
return cb(defaultBanner);
} else {
return cb(selectedBanners[Math.floor(Math.random()*banners.length)]);
}
} else {
return cb(defaultBanner);
}
};
return root;
});

View file

@ -0,0 +1,24 @@
'use strict';
angular.module('copayApp.services').factory('clipboardService', function ($http, $log, platformInfo, nodeWebkitService, gettextCatalog, ionicToast, clipboard) {
var root = {};
root.copyToClipboard = function (data) {
if (!data) return;
$log.debug("Copy '"+data+"' to clipboard");
if (platformInfo.isCordova) {
cordova.plugins.clipboard.copy(data);
} else if (platformInfo.isNW) {
nodeWebkitService.writeToClipboard(data);
} else if (clipboard.supported) {
clipboard.copyText(data);
} else {
// No supported
return;
}
};
return root;
});

View file

@ -103,6 +103,7 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti
_completeInitialization(status, callback);
});
} else {
isAvailable = true; // XX SP: Availability can change after permissions are granted after being denied.
_completeInitialization(status, callback);
}
});

View file

@ -0,0 +1,44 @@
'use strict';
angular.module('copayApp.services').service('soundService', function($log, $timeout, platformInfo, configService) {
var root = {};
/**
* Play a sound (when enabled in the configuration) using the Cordova Media-plugin (on Mobile) or html5-audio (on Desktop) relative to the www-root
* Make sure there is a .ogg file as well for NW.js (desktop) implementation
* @param soundFile
*/
root.play = function(soundFile) {
configService.whenAvailable(function(config) {
if (config.soundsEnabled) {
if (platformInfo.isCordova) {
if (platformInfo.isAndroid) {
var p = window.location.pathname;
var device_path = p.substring(0, p.lastIndexOf('/'));
soundFile = device_path + '/' + soundFile;
}
var audio = new Media(soundFile,
function () {
$log.debug("playAudio(bch_sent):Audio Success");
},
function (err) {
$log.debug("playAudio():Audio Error: " + err);
}
);
audio.play({playAudioWhenScreenIsLocked: false}); // XX SP: "Locked" is also the mute switch in iOS
} else {
if (platformInfo.isNW) {
soundFile = soundFile.substring(0, soundFile.lastIndexOf('.')) + ".ogg";
$log.debug("Playing .ogg file ("+soundFile+"), as NW.js has no mp3 support");
}
new Audio(soundFile).play();
}
}
});
};
return root;
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services')
.factory('storageService', function(appConfigService, logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, secureStorageService, $timeout) {
.factory('storageService', function(appConfigService, logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo, $timeout) {
var root = {};
var storage;
@ -121,11 +121,7 @@ angular.module('copayApp.services')
root.storeProfile = function(profile, cb) {
var profileString = profile.toObj();
if (platformInfo.isNW) {
storage.set('profile', profileString, cb);
} else {
secureStorageService.set('profile', profileString, cb);
}
storage.set('profile', profileString, cb);
};
/**
@ -205,48 +201,19 @@ angular.module('copayApp.services')
* @param {getProfileCallback} cb
*/
root.getProfile = function(cb) {
if (platformInfo.isNW) {
storage.get('profile', function(getErr, getStr) {
_onOldProfileRetrieved(getErr, getStr, cb);
});
return
}
secureStorageService.get('profile', function(secureErr, secureStr) {
var secureProfile;
var oldProfile;
if (secureErr) {
return cb(secureErr, null);
storage.get('profile', function(getErr, getStr) {
if (getErr) {
cb(getErr, null);
return;
}
if (secureStr) {
try {
secureProfile = Profile.fromString(secureStr);
$log.debug('profile: ' + JSON.stringify(secureProfile));
} catch (e) {
$log.error(e);
return cb(e, null);
}
if (!getStr) {
cb(null, null);
return;
}
storage.get('profile', function(getErr, getStr) {
_onOldProfileRetrieved(getErr, getStr, function(oldErr, oldProfile){
if (oldErr) {
return cb(oldErr, null);
}
if (!oldProfile) {
if (secureProfile) {
return cb(null, secureProfile);
} else {
// No profiles found. No errors either.
return cb(null, null);
}
}
_migrateProfiles(oldProfile, secureProfile, cb);
});
});
var profile = Profile.fromString(getStr);
cb(null, profile);
});
};

View file

@ -72,11 +72,19 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
var config = configService.getSync().wallet.settings;
var val = function() {
var v1 = parseFloat((rateService.toFiat(satoshis, config.alternativeIsoCode, coin)).toFixed(2));
v1 = $filter('formatFiatAmount')(v1);
var fiatAmount = rateService.toFiat(satoshis, config.alternativeIsoCode, coin);
var roundedStr = fiatAmount.toFixed(2);
var roundedNum = parseFloat(roundedStr);
var subcent = roundedNum === 0 && fiatAmount > 0;
var lessThanPrefix = '';
if (subcent) {
roundedNum = 0.01;
lessThanPrefix = '< ';
}
var v1 = $filter('formatFiatAmount')(roundedNum);
if (!v1) return null;
return v1 + ' ' + config.alternativeIsoCode;
return lessThanPrefix + v1 + ' ' + config.alternativeIsoCode;
};
// Async version

View file

@ -0,0 +1,68 @@
describe('txFormatService', function(){
var configServiceMock,
rateServiceMock,
txFormatService;
beforeEach(function(){
module('ngLodash');
module('bwcModule');
module('copayApp.filters');
module('copayApp.services');
configServiceMock = {
getSync: jasmine.createSpy()
};
rateServiceMock = {
isAvailable: jasmine.createSpy(),
toFiat: jasmine.createSpy()
};
module(function($provide) {
$provide.value('configService', configServiceMock);
$provide.value('rateService', rateServiceMock);
});
inject(function($injector){
txFormatService = $injector.get('txFormatService');
});
});
it('formatAlternativeStr 0.49 cents.', function() {
configServiceMock.getSync.and.returnValue({
wallet: {
settings: {
alternativeIsoCode: 'USD'
}
}
});
rateServiceMock.isAvailable.and.returnValue(true);
rateServiceMock.toFiat.and.returnValue(0.00499);
var formatted = txFormatService.formatAlternativeStr('bch', 123);
expect(formatted).toBe('< 0.01 USD');
});
it('formatAlternativeStr 0.5 cents.', function() {
configServiceMock.getSync.and.returnValue({
wallet: {
settings: {
alternativeIsoCode: 'USD'
}
}
});
rateServiceMock.isAvailable.and.returnValue(true);
rateServiceMock.toFiat.and.returnValue(0.005);
var formatted = txFormatService.formatAlternativeStr('bch', 123);
expect(formatted).toBe('0.01 USD');
});
});