Merge pull request #1976 from matiaspando/feature/chromeApp
Feature chrome application
This commit is contained in:
commit
a141a110b4
16 changed files with 176 additions and 63 deletions
8
browser-extensions/chrome/initial.js
Normal file
8
browser-extensions/chrome/initial.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
chrome.app.runtime.onLaunched.addListener(function() {
|
||||||
|
chrome.app.window.create('index.html', {
|
||||||
|
'bounds': {
|
||||||
|
'width': 1200,
|
||||||
|
'height': 800
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -3,17 +3,16 @@
|
||||||
"name": "Copay",
|
"name": "Copay",
|
||||||
"description": "A multisignature bitcoin wallet",
|
"description": "A multisignature bitcoin wallet",
|
||||||
"version": "APP_VERSION",
|
"version": "APP_VERSION",
|
||||||
"homepage_url": "http://bitpay.github.io/copay",
|
|
||||||
"browser_action": {
|
|
||||||
"default_title": "Copay",
|
|
||||||
"default_icon": "img/icons/icon.png",
|
|
||||||
"default_popup": "popup.html"
|
|
||||||
},
|
|
||||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"tabs", "storage", "notifications"
|
"storage",
|
||||||
|
"notifications",
|
||||||
|
"videoCapture"
|
||||||
],
|
],
|
||||||
"options_page": "index.html#/settings",
|
"app": {
|
||||||
|
"background": {
|
||||||
|
"scripts": ["initial.js"]
|
||||||
|
}
|
||||||
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"128": "img/icons/icon.png"
|
"128": "img/icons/icon.png"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ sound
|
||||||
views
|
views
|
||||||
config.js
|
config.js
|
||||||
init.js
|
init.js
|
||||||
|
initial.js
|
||||||
version.js
|
version.js
|
||||||
index.html
|
index.html
|
||||||
popup.html
|
popup.html
|
||||||
lib/angular/angular-csp.css
|
lib/angular/angular-csp.css
|
||||||
lib/angular/angular.min.js.map
|
lib/angular/angular.min.js.map
|
||||||
lib/angular-route/angular-route.min.js.map
|
lib/angular-route/angular-route.min.js.map
|
||||||
|
lib/angular-touch/angular-touch.min.js.map
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
color: #B7C2CD;
|
color: #B7C2CD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#qr-canvas { display: none; }
|
#qr-canvas { display: none; }
|
||||||
#qrcode-scanner-video {
|
#qrcode-scanner-video {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -60,6 +61,7 @@ body, html{
|
||||||
height:100%;
|
height:100%;
|
||||||
width:100%;
|
width:100%;
|
||||||
color: #2C3E50;
|
color: #2C3E50;
|
||||||
|
-webkit-user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
<link rel="shortcut icon" href="img/favicon.ico">
|
<link rel="shortcut icon" href="img/favicon.ico">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="loading" class="loadingpage">
|
<div id="loading" class="loadingpage">
|
||||||
<img src="img/ajax-loader.gif" alt="Loading...">
|
<img src="img/ajax-loader.gif" alt="Loading...">
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
15
init.js
15
init.js
|
|
@ -1,7 +1,12 @@
|
||||||
var ld = (document.all);
|
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
|
||||||
|
var ld;
|
||||||
|
if (!isChromeApp) {
|
||||||
|
ld = (document.all);
|
||||||
|
}
|
||||||
|
|
||||||
var ns4 = document.layers;
|
var ns4 = document.layers;
|
||||||
var ns6 = document.getElementById && !document.all;
|
var ns6 = !isChromeApp && document.getElementById && !document.all;
|
||||||
var ie4 = document.all;
|
var ie4 = !isChromeApp && document.all;
|
||||||
if (ns4) {
|
if (ns4) {
|
||||||
ld = document.loading;
|
ld = document.loading;
|
||||||
} else if (ns6) {
|
} else if (ns6) {
|
||||||
|
|
@ -15,6 +20,10 @@ function init() {
|
||||||
ld.visibility = "hidden";
|
ld.visibility = "hidden";
|
||||||
} else if (ns6 || ie4) {
|
} else if (ns6 || ie4) {
|
||||||
ld.display = "none";
|
ld.display = "none";
|
||||||
|
} else {
|
||||||
|
ld = document.getElementById("loading").style;
|
||||||
|
ld.visibility = "hidden";
|
||||||
|
ld.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
|
|
|
||||||
8
initial.js
Normal file
8
initial.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
chrome.app.runtime.onLaunched.addListener(function() {
|
||||||
|
chrome.app.window.create('index.html', {
|
||||||
|
'bounds': {
|
||||||
|
'width': 1200,
|
||||||
|
'height': 800
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
30
js/app.js
30
js/app.js
|
|
@ -3,18 +3,25 @@
|
||||||
var copay = require('copay');
|
var copay = require('copay');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var config = defaultConfig;
|
var config = defaultConfig;
|
||||||
var localConfig = JSON.parse(localStorage.getItem('config'));
|
var LS = require('../js/plugins/LocalStorage');
|
||||||
|
var ls = new LS();
|
||||||
|
|
||||||
|
var localConfig;
|
||||||
var defaults = JSON.parse(JSON.stringify(defaultConfig));
|
var defaults = JSON.parse(JSON.stringify(defaultConfig));
|
||||||
|
|
||||||
if (localConfig) {
|
|
||||||
var cmv = copay.version.split('.')[1];
|
ls.getItem('config', function(err, data) {
|
||||||
var lmv = localConfig.version ? localConfig.version.split('.')[1] : '-1';
|
localConfig = JSON.parse(data);
|
||||||
if (cmv === lmv) {
|
if (localConfig) {
|
||||||
_.each(localConfig, function(value, key) {
|
var cmv = copay.version.split('.')[1];
|
||||||
config[key] = value;
|
var lmv = localConfig.version ? localConfig.version.split('.')[1] : '-1';
|
||||||
});
|
if (cmv === lmv) {
|
||||||
|
_.each(localConfig, function(value, key) {
|
||||||
|
config[key] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
var modules = [
|
var modules = [
|
||||||
'ngRoute',
|
'ngRoute',
|
||||||
|
|
@ -47,9 +54,10 @@ copayApp.config(function($sceDelegateProvider) {
|
||||||
});
|
});
|
||||||
|
|
||||||
angular.module('ui.gravatar').config([
|
angular.module('ui.gravatar').config([
|
||||||
'gravatarServiceProvider', function(gravatarServiceProvider) {
|
'gravatarServiceProvider',
|
||||||
|
function(gravatarServiceProvider) {
|
||||||
gravatarServiceProvider.defaults = {
|
gravatarServiceProvider.defaults = {
|
||||||
size : 35
|
size: 35
|
||||||
};
|
};
|
||||||
// Use https endpoint
|
// Use https endpoint
|
||||||
gravatarServiceProvider.secure = true;
|
gravatarServiceProvider.secure = true;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ angular.module('copayApp.controllers').controller('HeadController', function($sc
|
||||||
$scope.username = $rootScope.iden.getName();
|
$scope.username = $rootScope.iden.getName();
|
||||||
$scope.hoverMenu = false;
|
$scope.hoverMenu = false;
|
||||||
|
|
||||||
|
var isChromeApp = typeof window !== "undefined" && window.chrome && chrome.runtime && chrome.runtime.id;
|
||||||
|
|
||||||
$scope.hoverIn = function() {
|
$scope.hoverIn = function() {
|
||||||
this.hoverMenu = true;
|
this.hoverMenu = true;
|
||||||
};
|
};
|
||||||
|
|
@ -30,12 +32,14 @@ angular.module('copayApp.controllers').controller('HeadController', function($sc
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensures a graceful disconnect
|
|
||||||
|
//Ensures a graceful disconnect
|
||||||
window.onbeforeunload = function() {
|
window.onbeforeunload = function() {
|
||||||
$scope.signout();
|
$scope.signout();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.$on('$destroy', function() {
|
$scope.$on('$destroy', function() {
|
||||||
|
if (isChromeApp) return;
|
||||||
window.onbeforeunload = undefined;
|
window.onbeforeunload = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
||||||
|
|
||||||
$scope.availableLogLevels = [];
|
$scope.availableLogLevels = [];
|
||||||
|
|
||||||
|
|
||||||
for (var key in logLevels) {
|
for (var key in logLevels) {
|
||||||
$scope.availableLogLevels.push({
|
$scope.availableLogLevels.push({
|
||||||
'name': key
|
'name': key
|
||||||
|
|
@ -63,7 +62,6 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
||||||
$scope.insightLivenet = copay.Insight.setCompleteUrl($scope.insightLivenet);
|
$scope.insightLivenet = copay.Insight.setCompleteUrl($scope.insightLivenet);
|
||||||
$scope.insightTestnet = copay.Insight.setCompleteUrl($scope.insightTestnet);
|
$scope.insightTestnet = copay.Insight.setCompleteUrl($scope.insightTestnet);
|
||||||
|
|
||||||
|
|
||||||
var insightSettings = {
|
var insightSettings = {
|
||||||
livenet: {
|
livenet: {
|
||||||
url: $scope.insightLivenet,
|
url: $scope.insightLivenet,
|
||||||
|
|
@ -95,6 +93,7 @@ angular.module('copayApp.controllers').controller('SettingsController', function
|
||||||
}), function() {
|
}), function() {
|
||||||
applicationService.restart();
|
applicationService.restart();
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,109 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var preconditions = require('preconditions').singleton();
|
var preconditions = require('preconditions').singleton();
|
||||||
|
var isChromeApp = typeof window !== "undefined" && window.chrome && chrome.runtime && chrome.runtime.id;
|
||||||
|
|
||||||
|
|
||||||
function LocalStorage(opts) {
|
function LocalStorage(opts) {
|
||||||
this.type = 'DB';
|
this.type = 'DB';
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
|
||||||
this.ls = opts.ls
|
|
||||||
|| ( (typeof localStorage !== 'undefined') ? localStorage : null );
|
|
||||||
|
|
||||||
|
this.ls = opts.ls ||
|
||||||
|
((typeof localStorage !== "undefined") ? localStorage : null);
|
||||||
|
|
||||||
|
if (isChromeApp && !this.ls) {
|
||||||
|
this.ls = localStorage = chrome.storage.local;
|
||||||
|
window.localStorage = chrome.storage.local;
|
||||||
|
}
|
||||||
|
|
||||||
preconditions.checkState(this.ls,
|
preconditions.checkState(this.ls,
|
||||||
'localstorage not available, cannot run plugin');
|
'localstorage not available, cannot run plugin');
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalStorage.prototype.init = function() {
|
LocalStorage.prototype.init = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
LocalStorage.prototype.setCredentials = function(email, password, opts) {
|
LocalStorage.prototype.setCredentials = function(email, password, opts) {
|
||||||
// NOP
|
// NOP
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalStorage.prototype.getItem = function(k,cb) {
|
LocalStorage.prototype.getItem = function(k, cb) {
|
||||||
preconditions.checkArgument(_.isFunction(cb));
|
if (isChromeApp) {
|
||||||
return cb(null, this.ls.getItem(k));
|
chrome.storage.local.get(k,
|
||||||
|
function(data) {
|
||||||
|
//TODO check for errors
|
||||||
|
return cb(null, data[k]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return cb(null, this.ls.getItem(k));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as setItem, but fails if an item already exists
|
* Same as setItem, but fails if an item already exists
|
||||||
*/
|
*/
|
||||||
LocalStorage.prototype.createItem = function(name, value, callback) {
|
LocalStorage.prototype.createItem = function(name, value, callback) {
|
||||||
preconditions.checkArgument(_.isFunction(callback));
|
var self = this;
|
||||||
if (this.ls.getItem(name)) {
|
self.getItem(name,
|
||||||
return callback('EEXISTS');
|
function(err, data) {
|
||||||
|
if (data) {
|
||||||
|
return callback('EEXISTS');
|
||||||
|
} else {
|
||||||
|
return self.setItem(name, value, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalStorage.prototype.setItem = function(k, v, cb) {
|
||||||
|
if (isChromeApp) {
|
||||||
|
var obj = {};
|
||||||
|
obj[k] = v;
|
||||||
|
|
||||||
|
chrome.storage.local.set(obj, cb);
|
||||||
|
} else {
|
||||||
|
this.ls.setItem(k, v);
|
||||||
|
return cb();
|
||||||
}
|
}
|
||||||
return this.setItem(name, value, callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalStorage.prototype.setItem = function(k,v,cb) {
|
LocalStorage.prototype.removeItem = function(k, cb) {
|
||||||
preconditions.checkArgument(_.isFunction(cb));
|
if (isChromeApp) {
|
||||||
this.ls.setItem(k,v);
|
chrome.storage.remove(k, cb);
|
||||||
|
} else {
|
||||||
|
this.ls.removeItem(k);
|
||||||
|
return cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalStorage.prototype.clear = function(cb) {
|
||||||
|
if (isChromeApp) {
|
||||||
|
chrome.storage.clear();
|
||||||
|
} else {
|
||||||
|
this.ls.clear();
|
||||||
|
}
|
||||||
return cb();
|
return cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalStorage.prototype.removeItem = function(k,cb) {
|
LocalStorage.prototype.allKeys = function(cb) {
|
||||||
preconditions.checkArgument(_.isFunction(cb));
|
if (isChromeApp) {
|
||||||
this.ls.removeItem(k);
|
chrome.storage.local.get(null, function(items) {
|
||||||
return cb();
|
return cb(null, _.keys(items));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var ret = [];
|
||||||
|
var l = this.ls.length;
|
||||||
|
|
||||||
|
for (var i = 0; i < l; i++)
|
||||||
|
ret.push(this.ls.key(i));
|
||||||
|
|
||||||
|
return cb(null, ret);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalStorage.prototype.clear = function(cb) {
|
|
||||||
preconditions.checkArgument(_.isFunction(cb));
|
|
||||||
this.ls.clear();
|
|
||||||
return cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = LocalStorage;
|
module.exports = LocalStorage;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var LS = require('../js/plugins/LocalStorage');
|
||||||
|
var ls = new LS();
|
||||||
|
|
||||||
//Setting up route
|
//Setting up route
|
||||||
angular
|
angular
|
||||||
.module('copayApp')
|
.module('copayApp')
|
||||||
|
|
@ -118,7 +121,9 @@ angular
|
||||||
uriHandler.register();
|
uriHandler.register();
|
||||||
}
|
}
|
||||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||||
if (!localStorage || localStorage.length < 1) {
|
|
||||||
|
|
||||||
|
if (!ls || ls.length < 1) {
|
||||||
$location.path('unsupported');
|
$location.path('unsupported');
|
||||||
} else {
|
} else {
|
||||||
if (!$rootScope.iden && next.logged) {
|
if (!$rootScope.iden && next.logged) {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
angular.module('copayApp.services')
|
angular.module('copayApp.services')
|
||||||
.factory('applicationService', function() {
|
.factory('applicationService', function() {
|
||||||
var root = {};
|
var root = {};
|
||||||
|
var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
|
||||||
|
|
||||||
root.restart = function() {
|
root.restart = function() {
|
||||||
// Go home reloading the application
|
|
||||||
var hashIndex = window.location.href.indexOf('#!/');
|
// Go home reloading the application
|
||||||
|
var hashIndex = window.location.href.indexOf('#!/');
|
||||||
|
if (isChromeApp) {
|
||||||
|
chrome.runtime.reload();
|
||||||
|
} else {
|
||||||
window.location = window.location.href.substr(0, hashIndex);
|
window.location = window.location.href.substr(0, hashIndex);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
root.reload = function() {
|
root.reload = function() {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var LS = require('../js/plugins/LocalStorage');
|
||||||
|
var ls = new LS();
|
||||||
|
|
||||||
angular.module('copayApp.services').
|
angular.module('copayApp.services').
|
||||||
factory('notification', ['$timeout',
|
factory('notification', ['$timeout',
|
||||||
function($timeout) {
|
function($timeout) {
|
||||||
|
|
||||||
var notifications = JSON.parse(localStorage.getItem('notifications')) || [],
|
var notifications = [];
|
||||||
queue = [];
|
|
||||||
|
|
||||||
|
ls.getItem('notifications', function(err, data) {
|
||||||
|
if (data) {
|
||||||
|
notifications = JSON.parse(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var queue = [];
|
||||||
var settings = {
|
var settings = {
|
||||||
info: {
|
info: {
|
||||||
duration: 6000,
|
duration: 6000,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ var ls;
|
||||||
try {
|
try {
|
||||||
var LS = require('../js/plugins/LocalStorage');
|
var LS = require('../js/plugins/LocalStorage');
|
||||||
ls = new LS();
|
ls = new LS();
|
||||||
} catch(e) {};
|
} catch (e) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc
|
* @desc
|
||||||
|
|
@ -126,6 +126,8 @@ var error = new Error();
|
||||||
|
|
||||||
var logLevel = config.logLevel || 'info';
|
var logLevel = config.logLevel || 'info';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ls && ls.getItem) {
|
if (ls && ls.getItem) {
|
||||||
ls.getItem("config", function(err, value) {
|
ls.getItem("config", function(err, value) {
|
||||||
if (err) return;
|
if (err) return;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<select class="form-control" ng-model="selectedLogLevel" ng-options="o.name for o in availableLogLevels" required>
|
<select class="form-control" ng-model="selectedLogLevel" ng-options="o.name for o in availableLogLevels" required>
|
||||||
</select>
|
</select>
|
||||||
<div translate class="small text-gray">
|
<div translate class="small text-gray">
|
||||||
Log level shows information on the console. This is usefull to find bugs and help users. 'debug' is the most verbose level while 'fatal' only shows unexcpected errors</a>
|
Log level shows information on the console. This is useful to find bugs and to help users. 'debug' is the most verbose level while 'fatal' only shows unexpected errors</a>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<button translate type="submit" class="button primary radius expand m0" ng-disabled="settingsForm.$invalid || loading" ng-click="save()">
|
<button translate type="submit" class="button primary radius expand m0" ng-disabled="settingsForm.$invalid || loading" ng-click="save()">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue