diff --git a/ionic.project b/ionic.project index b392585b59b03a4e0e0bdf711ae35813ba9b64d9..60c28f09c62e40b096b55ecb5d342cae63fdff93 100644 --- a/ionic.project +++ b/ionic.project @@ -17,4 +17,4 @@ "version": "12.41.296.5" } ] -} +} \ No newline at end of file diff --git a/package.json b/package.json index 79a22a016a50c4fccabb5e9b5b42c70233280a44..491e05ec606d12a9e956d809336692471b8bcd14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "0.0.3", + "version": "0.1.0", "description": "A webapp client for Duniter network", "dependencies": { "gulp": "^3.9.1", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 8a94c1cfcce6551eca7d04759729d4ad6a10b459..f5a3e4346ef16bcc1de935476f4a3df3396e0dd2 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -57,9 +57,10 @@ "TECHNICAL_SETTINGS": "Technical settings", "NODE": "Duniter Node", "NODE_HELP": "server.domain.com:port", + "USE_LOCAL_STORAGE": "Enable local storage", "POPUP_NODE": { - "TITLE" : "Node settings", - "HELP" : "Fill address of the Duniter node to use" + "TITLE" : "Duniter Node", + "HELP" : "Set the address of the node to use:" } }, "CURRENCY": { @@ -273,6 +274,7 @@ "ALL_SOURCES_USED": "Please wait the next block computation (All transaction sources has been used).", "NOT_ENOUGH_SOURCES": "Please wait the next block computation (Not enough transaction sources).", "ACCOUNT_CREATION_FAILED": "Error while creating your member account.", + "RESTORE_WALLET_DATA_ERROR": "Error while reloading settings from local storage", "LOAD_WALLET_DATA_ERROR": "Error while loading wallet data.", "COPY_CLIPBOARD_FAILED": "Could not copy to clipboard", "TAKE_PICTURE_FAILED": "Could not get picture.", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 2b906a5ff506b00c45401db651f508f429ec33a6..42cc282799cd5423eab4f63abf7723cfda53b827 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -55,11 +55,12 @@ "SETTINGS": { "TITLE": "Paramètres", "TECHNICAL_SETTINGS": "Paramètres techniques", - "NODE": "Noeud", + "NODE": "Noeud Duniter", "NODE_HELP": "server.domain.com:port", + "USE_LOCAL_STORAGE": "Activer le stockage local", "POPUP_NODE": { - "TITLE" : "Paramétrage du noeud", - "HELP" : "Saisissez l'adresse du noeud Duniter que vous voulez utiliser" + "TITLE" : "Noeud Duniter", + "HELP" : "Saisissez l'adresse du noeud que vous voulez utiliser :" } }, "CURRENCY": { @@ -273,6 +274,7 @@ "ALL_SOURCES_USED": "Veuillez attendre le calcul du prochain bloc (Toutes vos sources de monnaie ont été utilisées).", "NOT_ENOUGH_SOURCES": "Veuillez attendre le calcul du prochain bloc (Pas assez de sources de monnaie).", "ACCOUNT_CREATION_FAILED": "Echec de la création du compte membre.", + "RESTORE_WALLET_DATA_ERROR": "Echec du rechargement des paramètres depuis le stockage local", "LOAD_WALLET_DATA_ERROR": "Echec du chargement des données du portefeuille.", "COPY_CLIPBOARD_FAILED": "Copie de la valeur impossible.", "TAKE_PICTURE_FAILED": "Echec de la récupération de la photo.", diff --git a/www/js/config.js b/www/js/config.js index ef0cf356a74744a59fda9eb8070df201206f5335..c56c1be4d8bdd83e75b10cfcb2c9977033bbac73 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -14,8 +14,8 @@ angular.module("cesium.config", []) "TIMEOUT": 4000, "DEBUG": false, "NATIVE_TRANSITION": false, - "VERSION": "0.0.3", - "BUILD_DATE": "2016-05-26T17:36:25.682Z" + "VERSION": "0.1.0", + "BUILD_DATE": "2016-05-26T20:53:57.821Z" }) ; \ No newline at end of file diff --git a/www/js/controllers/app-controllers.js b/www/js/controllers/app-controllers.js index d6fd3b3f61e52f207d729c6aea1e1eff00afc860..c8acf22f5e286cedb7e63b796c4632b92daa758e 100644 --- a/www/js/controllers/app-controllers.js +++ b/www/js/controllers/app-controllers.js @@ -68,16 +68,31 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti // Login and load wallet $scope.loadWallet = function() { return $q(function(resolve, reject){ + if (!Wallet.isLogin()) { $timeout(function() { - $scope.login(function() { - $rootScope.viewFirstEnter = false; - Wallet.loadData() - .then(function(walletData){ - resolve(walletData); - }) - .catch(UIUtils.onError('ERROR.LOAD_WALLET_DATA_ERROR', reject)); - }); + Wallet.restore() // try to restore wallet + .then(function(){ + if (Wallet.isLogin()) { // Maybe now login + $rootScope.viewFirstEnter = false; + Wallet.loadData() + .then(function(walletData){ + resolve(walletData); + }) + .catch(UIUtils.onError('ERROR.LOAD_WALLET_DATA_ERROR', reject)); + } + else { + $scope.login(function() { + $rootScope.viewFirstEnter = false; + Wallet.loadData() + .then(function(walletData){ + resolve(walletData); + }) + .catch(UIUtils.onError('ERROR.LOAD_WALLET_DATA_ERROR', reject)); + }); + } + }) + .catch(UIUtils.onError('ERROR.RESTORE_WALLET_DATA_ERROR', reject)); }, $rootScope.viewFirstEnter ? 10 : 2000); } else if (!Wallet.data.loaded) { @@ -157,13 +172,13 @@ function LoginModalController($scope, $rootScope, $ionicModal, Wallet, CryptoUti // Logout $scope.logout = function() { UIUtils.loading.show(); - Wallet.logout().then( - function() { - UIUtils.loading.hide(); - $ionicSideMenuDelegate.toggleLeft(); - $state.go('app.home'); - } - ); + Wallet.logout() + .then(function() { + $ionicSideMenuDelegate.toggleLeft(); + UIUtils.loading.hide() + $state.go('app.home'); + }) + .catch(UIUtils.onError()); }; // Open new account diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js index 43d2a136f049357703b315a9c9fc14cc498aa9c5..986ecb6ade08fd769f405b3a78386d70fd4a1caa 100644 --- a/www/js/controllers/settings-controllers.js +++ b/www/js/controllers/settings-controllers.js @@ -19,28 +19,32 @@ angular.module('cesium.settings.controllers', ['cesium.services', 'cesium.curren .controller('SettingsCtrl', SettingsController) ; -function SettingsController($scope, $state, UIUtils, $translate, BMA, $q, $ionicPopup) { +function SettingsController($scope, $state, UIUtils, Wallet, $translate, BMA, $q, $ionicPopup, $timeout, localStorage) { - $scope.walletData = {}; - $scope.formData = { - locales: [ + $scope.locales = [ {id:'fr-FR', label:'Français'}, {id:'en', label:'English'} - ], - node: BMA.node.server, - newNode: null - }; + ]; + $scope.formData = { // Init with default settings + useRelative: Wallet.defaultSettings.useRelative, + node: Wallet.defaultSettings.node, + useLocalStorage: Wallet.defaultSettings.useLocalStorage + } + $scope.formData.locale = _.findWhere($scope.locales, {id: $translate.use()}); + $scope.loading = true; $scope.$on('$ionicView.enter', function(e, $state) { + $scope.loading = true; // to avoid the call of Wallet.store() $scope.loadWallet() - .then(function(wallet) { - $scope.walletData = wallet; - var currentLocale = $translate.use(); - $scope.walletData.settings.locale = $scope.formData.locales.reduce(function(array, l, index) { - return l.id == currentLocale ? array.concat(l) : array; - }, [])[0]; + .then(function(walletData) { + $scope.formData.useRelative = walletData.settings.useRelative; + $scope.formData.node = walletData.settings.node; + $scope.formData.useLocalStorage = walletData.settings.useLocalStorage; + $scope.formData.locale = _.findWhere($scope.locales, {id: walletData.settings.locale.id}); UIUtils.loading.hide(); - }); + $scope.loading = false; + }) + .catch(UIUtils.onError()); }); $scope.setSettingsForm = function(settingsForm) { @@ -51,18 +55,6 @@ function SettingsController($scope, $state, UIUtils, $translate, BMA, $q, $ionic $translate.use(langKey); }; - $scope.toogleUnit = function() { - $scope.walletData.settings.useRelative = !$scope.walletData.settings.useRelative; - }; - - $scope.onNodeChanged = function() { - BMA.instance($scope.formData.node); - }; - - $scope.onNodeChanged = function() { - BMA.instance($scope.formData.node); - }; - // Change node $scope.changeNode= function(node) { if (!node) { @@ -70,11 +62,12 @@ function SettingsController($scope, $state, UIUtils, $translate, BMA, $q, $ionic } $scope.showNodePopup(node) .then(function(node) { + if (node == $scope.formData.node) { + return; // same node = nothing to do + } UIUtils.loading.show(); - var nodeBMA = BMA.instance(node); - - nodeBMA.node.summary() + nodeBMA.node.summary() // ping the node .then(function() { UIUtils.loading.hide(); $scope.formData.node = node; @@ -132,4 +125,24 @@ function SettingsController($scope, $state, UIUtils, $translate, BMA, $q, $ionic }); }); }; + + $scope.onSettingsChanged = function() { + if (!$scope.loading) { + Wallet.data.settings.useRelative = $scope.formData.useRelative; + Wallet.data.settings.node = $scope.formData.node; + Wallet.data.settings.locale.id = $scope.formData.locale.id; + Wallet.data.settings.useLocalStorage = $scope.formData.useLocalStorage; + Wallet.store(); + } + }; + $scope.$watch('formData.useRelative', $scope.onSettingsChanged, true); + $scope.$watch('formData.node', $scope.onSettingsChanged, true); + $scope.$watch('formData.locale', $scope.onSettingsChanged, true); + $scope.$watch('formData.useLocalStorage', $scope.onSettingsChanged, true); + + // Set Ink + $timeout(function() { + // Set Ink + UIUtils.ink({selector: '.item'}); + }, 10); } diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index df1810125fefc8accf15293eed75966e08e0b664..e63a7ad8202d95e2c0db2258ab834b5477f881ae 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -128,7 +128,7 @@ angular.module('cesium.bma.services', ['ngResource', return { node: { summary: getResource('http://' + server + '/node/summary'), - server: server + url: server }, wot: { lookup: getResource('http://' + server + '/wot/lookup/:search'), diff --git a/www/js/services/utils-services.js b/www/js/services/utils-services.js index 2b4480f7656d3a669ee9d534c26701e09d3186d8..a90e71b390a1ce5c005583274618b3d420e20223 100644 --- a/www/js/services/utils-services.js +++ b/www/js/services/utils-services.js @@ -79,6 +79,9 @@ angular.module('cesium.utils.services', ['ngResource']) fullMsg = err.message; subtitle = msg; } + else if (!msg){ + fullMsg = err; + } // If reject has been given, use it if (!!reject) { reject(fullMsg); diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 9a74c9d30179cd25670d4bca8c2d07a96b62cd66..9de6a2c2b9db6d29703bdf056a353b51008dee08 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -1,8 +1,8 @@ //var Base58, Base64, scrypt_module_factory = null, nacl_factory = null; -angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', 'cesium.crypto.services', 'cesium.registry.services']) +angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', 'cesium.crypto.services', 'cesium.registry.services', 'cesium.utils.services']) -.factory('Wallet', ['$q', 'CryptoUtils', 'BMA', 'Registry', '$translate', function($q, CryptoUtils, BMA, Registry, $translate) { +.factory('Wallet', ['$q', 'CryptoUtils', 'BMA', 'Registry', '$translate', 'localStorage', function($q, CryptoUtils, BMA, Registry, $translate, localStorage) { Wallet = function(id) { @@ -10,7 +10,9 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' defaultSettings = { useRelative: true, - timeWarningExpire: 129600 /*TODO: =1.5j est-ce suffisant ?*/ + timeWarningExpire: 129600 /*TODO: =1.5j est-ce suffisant ?*/, + useLocalStorage: false, + node: BMA.node.url }, data = { @@ -37,11 +39,13 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' settings: { useRelative: defaultSettings.useRelative, timeWarningExpire: defaultSettings.timeWarningExpire, - locale: {id: $translate.use()} + locale: {id: $translate.use()}, + useLocalStorage: defaultSettings.useLocalStorage, + node: defaultSettings.node } }, - resetData = function() { + resetData = function(resetSettings) { data.pubkey= null; data.keypair ={ signSk: null, @@ -50,7 +54,6 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' data.uid = null; data.balance = 0; data.sources = null; - data.useRelative = defaultSettings.useRelative; // TODO : a remplacer par settings.useRelative data.currency= null; data.parameters = null; data.currentUD = null; @@ -62,10 +65,14 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' data.blockUid = null; data.members = []; data.avatar = null; - data.settings = { - useRelative: defaultSettings.useRelative, - timeWarningExpire: defaultSettings.timeWarningExpire - }; + if (!!resetSettings) { + data.settings = { + useRelative: defaultSettings.useRelative, + timeWarningExpire: defaultSettings.timeWarningExpire, + useLocalStorage: defaultSettings.useLocalStorage, + node: BMA.node.url // If changed, use the updated url + }; + } }, reduceTxAndPush = function(txArray, result, processedTxMap) { @@ -147,16 +154,75 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' }, logout = function(username, password) { - return $q(function(resolve, reject) { - resetData(); - resolve(); - }); + return $q(function(resolve, reject) { + + var resetSettings = !data.settings.useLocalStorage; + resetData(resetSettings); + if (data.settings.useLocalStorage) { + store(); + } + resolve(); + }); }, isLogin = function() { return !!data.pubkey; }, + store = function() { + if (data.settings.useLocalStorage) { + localStorage.setObject('CESIUM_SETTINGS', data.settings); + + if (isLogin()) { + var dataToStore = { + keypair: data.keypair, + pubkey: data.pubkey + }; + localStorage.setObject('CESIUM_DATA', dataToStore); + } + else { + localStorage.setObject('CESIUM_DATA', null); + } + } + else { + localStorage.setObject('CESIUM_SETTINGS', null); + localStorage.setObject('CESIUM_DATA', null); + } + }, + + restore = function() { + return $q(function(resolve, reject){ + var settings = localStorage.getObject('CESIUM_SETTINGS'); + var dataStr = localStorage.get('CESIUM_DATA'); + if (!settings && !dataStr) { + resolve(); + return; + } + var nodeChanged = (settings && settings.node) && (data.settings.node != settings.node); + if (nodeChanged) { + BMA.copy(BMA.instance(settings.node)); // reload BMA + data.loaded = false; + } + if (settings) { + data.settings = settings; + } + if (dataStr) { + fromJson(dataStr, false) + .then(function(storedData){ + if (storedData && storedData.keypair && storedData.pubkey) { + data.keypair = storedData.keypair; + data.pubkey = storedData.pubkey; + } + resolve(); + }) + .catch(function(err){reject(err)}); + } + else { + resolve(); + } + }); + }, + getData = function() { return data; }, @@ -633,30 +699,36 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' /** * De-serialize from JSON string */ - fromJson = function(json) { + fromJson = function(json, failIfInvalid) { + if (failIfInvalid === "undefined") { + failIfInvalid = true; + } return $q(function(resolve, reject) { var obj = JSON.parse(json || '{}'); - if (obj.keypair) { - var keypair = obj.keypair; + if (obj && obj.keypair && obj.keypair.signPk && obj.keypair.signSk) { + var keypair = {}; var i; // Convert to Uint8Array type var signPk = new Uint8Array(32); - for (i = 0; i < 32; i++) signPk[i] = keypair.signPk[i]; + for (i = 0; i < 32; i++) signPk[i] = obj.keypair.signPk[i]; keypair.signPk = signPk; var signSk = new Uint8Array(64); - for (i = 0; i < 64; i++) signSk[i] = keypair.signSk[i]; + for (i = 0; i < 64; i++) signSk[i] = obj.keypair.signSk[i]; keypair.signSk = signSk; - data.pubkey = obj.pubkey; - data.keypair = keypair; - - resolve(); + resolve({ + pubkey: obj.pubkey, + keypair: keypair + }); } - else { + else if (failIfInvalid) { reject('Not a valid Wallet.data object'); } + else { + resolve(); + } }); }; @@ -678,6 +750,8 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' out: membership(false) }, certify: certify, + store: store, + restore: restore, // serialization toJson: toJson, fromJson: fromJson, @@ -686,7 +760,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'cesium.bma.services', ' }; var service = Wallet('default'); - service.instance = service; + service.instance = Wallet; return service; }]) ; diff --git a/www/templates/settings/settings.html b/www/templates/settings/settings.html index 6d851eb050b4c699085f1dc20b4237df72802a3d..e4fce26d1a9c34e03ca752f15183abbc4c5b42c0 100644 --- a/www/templates/settings/settings.html +++ b/www/templates/settings/settings.html @@ -6,7 +6,7 @@ <div class="item item-toggle dark"> {{'COMMON.BTN_RELATIVE_UNIT' | translate}} <label class="toggle toggle-royal"> - <input type="checkbox" ng-model="walletData.settings.useRelative"> + <input type="checkbox" ng-model="formData.useRelative"> <div class="track"> <div class="handle"></div> </div> @@ -17,9 +17,9 @@ <div class="input-label"> {{'COMMON.LANGUAGE' | translate}} </div> - <select ng-model="walletData.settings.locale" - ng-change="changeLanguage(walletData.settings.locale.id)" - ng-options="l as l.label for l in formData.locales track by l.id"> + <select ng-model="formData.locale" + ng-change="changeLanguage(formData.locale.id)" + ng-options="l as l.label for l in locales track by l.id"> </select> </label> @@ -27,10 +27,20 @@ {{'SETTINGS.TECHNICAL_SETTINGS' | translate}} </span> - <div class="item" ng-click="changeNode()"> + <div class="item ink" ng-click="changeNode()"> {{'SETTINGS.NODE' | translate}} <span class="item-note">{{formData.node}}</span> </div> + <div class="item item-toggle dark"> + {{'SETTINGS.USE_LOCAL_STORAGE' | translate}} + <label class="toggle toggle-royal"> + <input type="checkbox" ng-model="formData.useLocalStorage" > + <div class="track"> + <div class="handle"></div> + </div> + </label> + </div> + </ion-content> </ion-view>