diff --git a/browser-extensions/chrome/initial.js b/browser-extensions/chrome/initial.js
new file mode 100644
index 000000000..fc12301b5
--- /dev/null
+++ b/browser-extensions/chrome/initial.js
@@ -0,0 +1,8 @@
+chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.app.window.create('index.html', {
+ 'bounds': {
+ 'width': 1200,
+ 'height': 800
+ }
+ });
+});
diff --git a/browser-extensions/chrome/manifest.json b/browser-extensions/chrome/manifest.json
index 7b8e6517f..6c9388801 100644
--- a/browser-extensions/chrome/manifest.json
+++ b/browser-extensions/chrome/manifest.json
@@ -3,17 +3,16 @@
"name": "Copay",
"description": "A multisignature bitcoin wallet",
"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": [
- "tabs", "storage", "notifications"
+ "storage",
+ "notifications",
+ "videoCapture"
],
- "options_page": "index.html#/settings",
+ "app": {
+ "background": {
+ "scripts": ["initial.js"]
+ }
+ },
"icons": {
"128": "img/icons/icon.png"
}
diff --git a/browser-extensions/include b/browser-extensions/include
index 346645ba0..5a43929ed 100644
--- a/browser-extensions/include
+++ b/browser-extensions/include
@@ -6,9 +6,11 @@ sound
views
config.js
init.js
+initial.js
version.js
index.html
popup.html
lib/angular/angular-csp.css
lib/angular/angular.min.js.map
lib/angular-route/angular-route.min.js.map
+lib/angular-touch/angular-touch.min.js.map
diff --git a/css/src/main.css b/css/src/main.css
index 4a4b32666..e83fc982d 100644
--- a/css/src/main.css
+++ b/css/src/main.css
@@ -22,6 +22,7 @@
color: #B7C2CD;
}
+
#qr-canvas { display: none; }
#qrcode-scanner-video {
display: block;
@@ -60,6 +61,7 @@ body, html{
height:100%;
width:100%;
color: #2C3E50;
+ -webkit-user-select: text;
}
header {
diff --git a/index.html b/index.html
index 5aac51371..b349ec383 100644
--- a/index.html
+++ b/index.html
@@ -21,6 +21,7 @@
+
diff --git a/init.js b/init.js
index c4cb7298a..c56005eb9 100644
--- a/init.js
+++ b/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 ns6 = document.getElementById && !document.all;
-var ie4 = document.all;
+var ns6 = !isChromeApp && document.getElementById && !document.all;
+var ie4 = !isChromeApp && document.all;
if (ns4) {
ld = document.loading;
} else if (ns6) {
@@ -15,6 +20,10 @@ function init() {
ld.visibility = "hidden";
} else if (ns6 || ie4) {
ld.display = "none";
+ } else {
+ ld = document.getElementById("loading").style;
+ ld.visibility = "hidden";
+ ld.display = "none";
}
}
init();
diff --git a/initial.js b/initial.js
new file mode 100644
index 000000000..fc12301b5
--- /dev/null
+++ b/initial.js
@@ -0,0 +1,8 @@
+chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.app.window.create('index.html', {
+ 'bounds': {
+ 'width': 1200,
+ 'height': 800
+ }
+ });
+});
diff --git a/js/app.js b/js/app.js
index 4ff3e5ba9..e2ef9e359 100644
--- a/js/app.js
+++ b/js/app.js
@@ -3,18 +3,25 @@
var copay = require('copay');
var _ = require('lodash');
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));
-if (localConfig) {
- var cmv = copay.version.split('.')[1];
- var lmv = localConfig.version ? localConfig.version.split('.')[1] : '-1';
- if (cmv === lmv) {
- _.each(localConfig, function(value, key) {
- config[key] = value;
- });
+
+ls.getItem('config', function(err, data) {
+ localConfig = JSON.parse(data);
+ if (localConfig) {
+ var cmv = copay.version.split('.')[1];
+ var lmv = localConfig.version ? localConfig.version.split('.')[1] : '-1';
+ if (cmv === lmv) {
+ _.each(localConfig, function(value, key) {
+ config[key] = value;
+ });
+ }
}
-}
+});
var modules = [
'ngRoute',
@@ -47,9 +54,10 @@ copayApp.config(function($sceDelegateProvider) {
});
angular.module('ui.gravatar').config([
- 'gravatarServiceProvider', function(gravatarServiceProvider) {
+ 'gravatarServiceProvider',
+ function(gravatarServiceProvider) {
gravatarServiceProvider.defaults = {
- size : 35
+ size: 35
};
// Use https endpoint
gravatarServiceProvider.secure = true;
diff --git a/js/controllers/head.js b/js/controllers/head.js
index 58ff90dbc..4d32b7331 100644
--- a/js/controllers/head.js
+++ b/js/controllers/head.js
@@ -4,6 +4,8 @@ angular.module('copayApp.controllers').controller('HeadController', function($sc
$scope.username = $rootScope.iden.getName();
$scope.hoverMenu = false;
+ var isChromeApp = typeof window !== "undefined" && window.chrome && chrome.runtime && chrome.runtime.id;
+
$scope.hoverIn = function() {
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() {
$scope.signout();
};
$scope.$on('$destroy', function() {
+ if (isChromeApp) return;
window.onbeforeunload = undefined;
});
diff --git a/js/controllers/settings.js b/js/controllers/settings.js
index 012605b0a..05da4110c 100644
--- a/js/controllers/settings.js
+++ b/js/controllers/settings.js
@@ -11,7 +11,6 @@ angular.module('copayApp.controllers').controller('SettingsController', function
$scope.availableLogLevels = [];
-
for (var key in logLevels) {
$scope.availableLogLevels.push({
'name': key
@@ -63,7 +62,6 @@ angular.module('copayApp.controllers').controller('SettingsController', function
$scope.insightLivenet = copay.Insight.setCompleteUrl($scope.insightLivenet);
$scope.insightTestnet = copay.Insight.setCompleteUrl($scope.insightTestnet);
-
var insightSettings = {
livenet: {
url: $scope.insightLivenet,
@@ -95,6 +93,7 @@ angular.module('copayApp.controllers').controller('SettingsController', function
}), function() {
applicationService.restart();
});
+
};
diff --git a/js/plugins/LocalStorage.js b/js/plugins/LocalStorage.js
index 8e4ee75e3..10b84293b 100644
--- a/js/plugins/LocalStorage.js
+++ b/js/plugins/LocalStorage.js
@@ -1,58 +1,109 @@
'use strict';
var _ = require('lodash');
var preconditions = require('preconditions').singleton();
+var isChromeApp = typeof window !== "undefined" && window.chrome && chrome.runtime && chrome.runtime.id;
+
function LocalStorage(opts) {
this.type = 'DB';
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,
'localstorage not available, cannot run plugin');
};
-LocalStorage.prototype.init = function() {
-};
+LocalStorage.prototype.init = function() {};
LocalStorage.prototype.setCredentials = function(email, password, opts) {
// NOP
};
-LocalStorage.prototype.getItem = function(k,cb) {
- preconditions.checkArgument(_.isFunction(cb));
- return cb(null, this.ls.getItem(k));
+LocalStorage.prototype.getItem = function(k, cb) {
+ if (isChromeApp) {
+ 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
*/
LocalStorage.prototype.createItem = function(name, value, callback) {
- preconditions.checkArgument(_.isFunction(callback));
- if (this.ls.getItem(name)) {
- return callback('EEXISTS');
+ var self = this;
+ self.getItem(name,
+ 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) {
- preconditions.checkArgument(_.isFunction(cb));
- this.ls.setItem(k,v);
+LocalStorage.prototype.removeItem = function(k, cb) {
+ if (isChromeApp) {
+ 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();
};
-LocalStorage.prototype.removeItem = function(k,cb) {
- preconditions.checkArgument(_.isFunction(cb));
- this.ls.removeItem(k);
- return cb();
+LocalStorage.prototype.allKeys = function(cb) {
+ if (isChromeApp) {
+ chrome.storage.local.get(null, function(items) {
+ 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;
diff --git a/js/routes.js b/js/routes.js
index 12d8b93f2..39a207902 100644
--- a/js/routes.js
+++ b/js/routes.js
@@ -1,5 +1,8 @@
'use strict';
+var LS = require('../js/plugins/LocalStorage');
+var ls = new LS();
+
//Setting up route
angular
.module('copayApp')
@@ -118,7 +121,9 @@ angular
uriHandler.register();
}
$rootScope.$on('$routeChangeStart', function(event, next, current) {
- if (!localStorage || localStorage.length < 1) {
+
+
+ if (!ls || ls.length < 1) {
$location.path('unsupported');
} else {
if (!$rootScope.iden && next.logged) {
diff --git a/js/services/applicationService.js b/js/services/applicationService.js
index 3612bf0d1..4c3bade19 100644
--- a/js/services/applicationService.js
+++ b/js/services/applicationService.js
@@ -1,17 +1,23 @@
'use strict';
angular.module('copayApp.services')
.factory('applicationService', function() {
- var root = {};
+ var root = {};
+ var isChromeApp = window.chrome && chrome.runtime && chrome.runtime.id;
- root.restart = function() {
- // Go home reloading the application
- var hashIndex = window.location.href.indexOf('#!/');
+ root.restart = function() {
+
+ // 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);
- };
+ }
+ };
- root.reload = function() {
- window.location.reload();
- };
+ root.reload = function() {
+ window.location.reload();
+ };
- return root;
+ return root;
});
diff --git a/js/services/notifications.js b/js/services/notifications.js
index 3f5b324ea..7e602c4f9 100644
--- a/js/services/notifications.js
+++ b/js/services/notifications.js
@@ -1,12 +1,21 @@
'use strict';
+var LS = require('../js/plugins/LocalStorage');
+var ls = new LS();
+
angular.module('copayApp.services').
factory('notification', ['$timeout',
function($timeout) {
- var notifications = JSON.parse(localStorage.getItem('notifications')) || [],
- queue = [];
+ var notifications = [];
+ ls.getItem('notifications', function(err, data) {
+ if (data) {
+ notifications = JSON.parse(data);
+ }
+ });
+
+ var queue = [];
var settings = {
info: {
duration: 6000,
diff --git a/js/util/log.js b/js/util/log.js
index 220fc2a02..31a5a3ba5 100644
--- a/js/util/log.js
+++ b/js/util/log.js
@@ -5,7 +5,7 @@ var ls;
try {
var LS = require('../js/plugins/LocalStorage');
ls = new LS();
-} catch(e) {};
+} catch (e) {};
/**
* @desc
@@ -126,6 +126,8 @@ var error = new Error();
var logLevel = config.logLevel || 'info';
+
+
if (ls && ls.getItem) {
ls.getItem("config", function(err, value) {
if (err) return;
diff --git a/views/settings.html b/views/settings.html
index 9c2d20fdd..5f962a066 100644
--- a/views/settings.html
+++ b/views/settings.html
@@ -64,7 +64,7 @@
- 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
+ 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