From 8d8c015011ad080b54560a173a6637c5ea323b12 Mon Sep 17 00:00:00 2001 From: Benoit Lavenier <benoit.lavenier@e-is.pro> Date: Mon, 27 Feb 2023 22:02:01 +0100 Subject: [PATCH] [wip] Add startup progression message, in home page [fix] Network scan: compute a timeout using the remaining time, to force network to finish in 10s. --- app/config.json | 2 +- dist/desktop | 2 +- www/i18n/locale-fr-FR.json | 23 ++-- www/js/config.js | 22 +--- www/js/controllers/home-controllers.js | 23 +++- www/js/controllers/network-controllers.js | 23 ++-- www/js/controllers/settings-controllers.js | 1 + www/js/entities/peer.js | 4 +- www/js/platform.js | 144 +++++++++++++-------- www/js/services/bma-services.js | 40 +++--- www/js/services/network-services.js | 100 ++++++++++---- www/js/services/settings-services.js | 25 +++- www/js/services/wot-services.js | 4 +- www/license/license_g1-es-CT.md | 96 ++++++++++++++ www/templates/home/home.html | 1 + www/templates/settings/popup_node.html | 2 +- www/templates/settings/settings.html | 53 +++++--- 17 files changed, 390 insertions(+), 175 deletions(-) create mode 100644 www/license/license_g1-es-CT.md diff --git a/app/config.json b/app/config.json index 442313101..89aeb8acb 100644 --- a/app/config.json +++ b/app/config.json @@ -41,7 +41,7 @@ "maxContentLength": 1300 }, "node": { - "host": "g1.duniter.org", + "host": "g111.duniter.org", "port": 443 }, "fallbackNodes": [ diff --git a/dist/desktop b/dist/desktop index c3688522f..6e01a54b4 160000 --- a/dist/desktop +++ b/dist/desktop @@ -1 +1 @@ -Subproject commit c3688522fc97557794341ab17810671380bdccc1 +Subproject commit 6e01a54b4fd3b6fd3b7a4b708643694ea45edc13 diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index b0a88d903..8a013ebcf 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -144,6 +144,7 @@ "PEER": "NÅ“ud Duniter", "PEER_SHORT": "NÅ“ud Duniter", "PEER_CHANGED_TEMPORARY": "Adresse utilisée temporairement", + "PEER_SELECTED_AUTOMATICALLY": "Sélectionné automatiquement au démarrage", "PERSIST_CACHE": "Conserver les données de navigation (expérimental)", "PERSIST_CACHE_HELP": "Permet une navigation plus rapide, en conservant localement les données reçues, pour les utiliser d'une session à l'autre.", "USE_LOCAL_STORAGE": "Activer le stockage local", @@ -191,7 +192,7 @@ "HOST": "Adresse", "HOST_HELP": "Adresse : serveur:port", "USE_SSL": "Sécurisé ?", - "USE_SSL_HELP": "(Chiffrement SSL)", + "USE_SSL_HELP": "Chiffrement SSL", "BTN_SHOW_LIST": "Liste des noeuds" } }, @@ -201,7 +202,7 @@ "HEADER_TITLE": "Bloc #{{number}}-{{hash|formatHash}}", "TITLE_CURRENT": "Bloc courant", "TITLE": "Bloc #{{number|formatInteger}}", - "COMPUTED_BY": "Calculé par le noeud de", + "COMPUTED_BY": "Calculé par le nÅ“ud de", "SHOW_RAW": "Voir le fichier brut", "TECHNICAL_DIVIDER": "Informations techniques", "VERSION": "Version du format", @@ -297,7 +298,6 @@ "NETWORK": { "VIEW": { "MEDIAN_TIME": "Heure de la blockchain", - "LOADING_PEERS": "Chargement des noeuds...", "NODE_ADDRESS": "Adresse :", "SOFTWARE": "Logiciel", "WARN_PRE_RELEASE": "Pré-version (dernière version stable : <b>{{version}}</b>)", @@ -309,11 +309,13 @@ "BMAS": "Interface sécurisée (SSL)", "BMATOR": "Interface réseau TOR", "WS2P": "Interface WS2P", - "ES_USER_API": "Noeud de données Cesium+" + "ES_USER_API": "NÅ“ud de données Cesium+" } }, "INFO": { - "ONLY_SSL_PEERS": "Les noeuds non SSL ont un affichage dégradé, car Cesium fonctionne en mode HTTPS." + "CONNECTING_TO_PEER": "Connexion au nÅ“ud réseau...", + "CHECKING_NETWORK_STATE": "Calcul de l'état du réseau {{currency|abbreviate}}...", + "ONLY_SSL_PEERS": "Les nÅ“uds non SSL ont un affichage dégradé, car Cesium fonctionne en mode HTTPS." } }, "PEER": { @@ -342,8 +344,8 @@ "KNOWN_PEERS": "NÅ“uds connus :", "GENERAL_DIVIDER": "Informations générales", "ERROR": { - "LOADING_TOR_NODE_ERROR": "Récupération des informations du noeud impossible. Le délai d'attente est dépassé.", - "LOADING_NODE_ERROR": "Récupération des informations du noeud impossible" + "LOADING_TOR_NODE_ERROR": "Récupération des informations du nÅ“ud impossible. Le délai d'attente est dépassé.", + "LOADING_NODE_ERROR": "Récupération des informations du nÅ“ud impossible" } } }, @@ -524,8 +526,8 @@ "INTRO_WARNING_SECURITY": "Vérifiez que le matériel que vous utilisez actuellement (ordinateur, tablette, téléphone) <b>est sécurisé et digne de confiance</b>.", "INTRO_WARNING_SECURITY_HELP": "Anti-virus à jour, pare-feu activé, session protégée par mot de passe ou code pin, etc.", "INTRO_HELP": "Cliquez sur <b>{{'COMMON.BTN_START'|translate}}</b> pour débuter la création de compte. Vous serez guidé étape par étape.", - "REGISTRATION_NODE": "Votre inscription sera enregistrée via le noeud Duniter <b>{{server}}</b>, qui le diffusera ensuite au reste du réseau de la monnaie.", - "REGISTRATION_NODE_HELP": "Si vous ne faites pas confiance en ce noeud, veuillez en changer <a ng-click=\"doQuickFix('settings')\">dans les paramètres</a> de Cesium.", + "REGISTRATION_NODE": "Votre inscription sera enregistrée via le nÅ“ud Duniter <b>{{server}}</b>, qui le diffusera ensuite au reste du réseau de la monnaie.", + "REGISTRATION_NODE_HELP": "Si vous ne faites pas confiance en ce nÅ“ud, veuillez en changer <a ng-click=\"doQuickFix('settings')\">dans les paramètres</a> de Cesium.", "SELECT_ACCOUNT_TYPE": "Choisissez le type de compte à créer :", "MEMBER_ACCOUNT": "Compte membre", "MEMBER_ACCOUNT_TITLE": "Création d'un compte membre", @@ -822,7 +824,8 @@ "REVOCATION_SENT": "Révocation envoyée", "REVOCATION_SENT_WAITING_PROCESS": "La <b>révocation de cette identité</b> a été demandée et est en attente de traitement.", "FEATURES_NOT_IMPLEMENTED": "Cette fonctionnalité est encore en cours de développement.<br/>Pourquoi ne pas <b>contribuer à Cesium</b>, pour l'obtenir plus rapidement ? ;)", - "EMPTY_TX_HISTORY": "Aucune opération à exporter" + "EMPTY_TX_HISTORY": "Aucune opération à exporter", + "LOADING_PENDING_TX": "Lecture des opérations en attente" }, "CONFIRM": { "CAN_CONTINUE": "<b>Êtes-vous sûr</b> de vouloir continuer ?", diff --git a/www/js/config.js b/www/js/config.js index ebf439e7f..b1356a965 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -15,7 +15,7 @@ angular.module("cesium.config", []) "fallbackLanguage": "en", "rememberMe": true, "showUDHistory": true, - "timeout": 3000, + "timeout": 40000, "timeWarningExpireMembership": 5184000, "timeWarningExpire": 7776000, "keepAuthIdle": 600, @@ -28,7 +28,7 @@ angular.module("cesium.config", []) "helptip": { "enable": true, "installDocUrl": { - "fr-FR": "https://duniter.org/fr/miner-des-blocs/installer/", + "fr-FR": "https://duniter.fr/wiki/doc/installer/", "en": "https://duniter.org/en/wiki/duniter/install/" } }, @@ -50,7 +50,7 @@ angular.module("cesium.config", []) "maxContentLength": 1300 }, "node": { - "host": "g1.duniter.org", + "host": "g11.duniter.org", "port": 443 }, "fallbackNodes": [ @@ -67,19 +67,11 @@ angular.module("cesium.config", []) "port": 443 }, { - "host": "g1.le-sou.org", + "host": "duniter.moul.re", "port": 443 }, { - "host": "g1.moul.re", - "port": 443 - }, - { - "host": "g1.cloud-libre.eu", - "port": 443 - }, - { - "host": "g1.texu.es", + "host": "g1.presles.fr", "port": 443 }, { @@ -120,8 +112,8 @@ angular.module("cesium.config", []) } }, "version": "1.7.0-rc2", - "build": "2023-02-27T10:05:45.363Z", + "build": "2023-02-27T10:33:03.091Z", "newIssueUrl": "https://git.duniter.org/clients/cesium-grp/cesium/issues/new" }) -; \ No newline at end of file +; diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js index e2a925de2..389e8e6da 100644 --- a/www/js/controllers/home-controllers.js +++ b/www/js/controllers/home-controllers.js @@ -29,18 +29,17 @@ function HomeController($scope, $state, $timeout, $ionicHistory, $translate, $ht 'ngInject'; $scope.loading = true; + $scope.loadingMessage = ''; $scope.locales = angular.copy(csSettings.locales); $scope.smallscreen = UIUtils.screen.isSmall(); $scope.showInstallHelp = false; $scope.enter = function(e, state) { - if (ionic.Platform.isIOS()) { - if(window.StatusBar) { - // needed to fix Xcode 9 / iOS 11 issue with blank space at bottom of webview - // https://github.com/meteor/meteor/issues/9041 - StatusBar.overlaysWebView(false); - StatusBar.overlaysWebView(true); - } + if (ionic.Platform.isIOS() && window.StatusBar) { + // needed to fix Xcode 9 / iOS 11 issue with blank space at bottom of webview + // https://github.com/meteor/meteor/issues/9041 + StatusBar.overlaysWebView(false); + StatusBar.overlaysWebView(true); } if (state && state.stateParams && state.stateParams.uri) { @@ -57,16 +56,20 @@ function HomeController($scope, $state, $timeout, $ionicHistory, $translate, $ht $scope.cleanLocationHref(state); } else { + + // Wait platform to be ready csPlatform.ready() .then(function() { $scope.loading = false; + $scope.loadingMessage = ''; $scope.loadFeeds(); }) .catch(function(err) { $scope.node = csCurrency.data.node; $scope.loading = false; $scope.error = err; + $scope.loadingMessage = ''; }); } }; @@ -193,6 +196,12 @@ function HomeController($scope, $state, $timeout, $ionicHistory, $translate, $ht } }; + + // Listen platform messages + csPlatform.api.start.on.message($scope, function(message) { + $scope.loadingMessage = message; + }); + // For DEV ONLY /*$timeout(function() { $scope.loginAndGo(); diff --git a/www/js/controllers/network-controllers.js b/www/js/controllers/network-controllers.js index a3ab788f6..51a53bb28 100644 --- a/www/js/controllers/network-controllers.js +++ b/www/js/controllers/network-controllers.js @@ -157,18 +157,18 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.load = function() { if ($scope.search.loading){ - $scope.refreshing = false; + $scope.updating = false; // Start network scan csNetwork.start($scope.node, $scope.computeOptions()) .then(function() { - $scope.refresh(); + $scope.onDataChanged(); }); // Catch event on new peers $scope.listeners.push( csNetwork.api.data.on.changed($scope, function(data) { - $scope.refresh(data); + $scope.onDataChanged(data); })); } @@ -176,16 +176,21 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.showHelpTip(); }; - $scope.refresh = function(data) { + $scope.onDataChanged = function(data) { data = csNetwork.data || data; - if (!data || $scope.refreshing /*|| !$scope.networkStarted*/) return; // Skip if no data, or already refreshing + if (!data || $scope.updating /*|| !$scope.networkStarted*/) return; // Skip if no data, or already updating - // Mark as refreshing - $scope.refreshing = true; + var now = Date.now(); + console.debug("[peers] Fetching name + avatar, on {0} peers...".format(data.peers && data.peers.length || 0)); + + // Mark as updating + $scope.updating = true; // Add name+avatar to peers csWot.extendAll(data.peers) .then(function() { + console.debug("[peers] Fetching name + avatar on peers [OK] in {0}ms".format(Date.now() - now)); + // Avoid to refresh if view has been leaving if ($scope.networkStarted) { $scope.updateView(data); @@ -196,7 +201,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win // Continue }) .then(function() { - $scope.refreshing = false; + $scope.updating = false; }); } @@ -223,7 +228,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.sort = function() { $scope.search.loading = true; - $scope.refreshing = true; + $scope.updating = true; csNetwork.sort($scope.computeOptions()); $scope.updateView(csNetwork.data); }; diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js index 2e7082d32..b6e756bde 100644 --- a/www/js/controllers/settings-controllers.js +++ b/www/js/controllers/settings-controllers.js @@ -150,6 +150,7 @@ function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $ti // Change node $scope.changeNode= function(node) { + var port = !!$scope.formData.node.port && $scope.formData.node.port != 80 && $scope.formData.node.port != 443 ? $scope.formData.node.port : undefined; node = node || { host: $scope.formData.node.host, diff --git a/www/js/entities/peer.js b/www/js/entities/peer.js index 6a2e1fbba..6b5afe039 100644 --- a/www/js/entities/peer.js +++ b/www/js/entities/peer.js @@ -123,8 +123,8 @@ Peer.prototype.getPort = function() { return bma.port ? parseInt(bma.port) : null; }; -Peer.prototype.getHost = function(getHost) { - bma = getHost || this.bma || this.getBMA(); +Peer.prototype.getHost = function(bma) { + bma = bma || this.bma || this.getBMA(); return ((bma.port == 443 || bma.useSsl) && bma.dns) ? bma.dns : (this.hasValid4(bma) ? bma.ipv4 : (bma.dns ? bma.dns : diff --git a/www/js/platform.js b/www/js/platform.js index 4a1a105ac..d1cd933c4 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -101,7 +101,7 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] .factory('csPlatform', function (ionicReady, $rootScope, $q, $state, $translate, $timeout, $ionicHistory, $window, - UIUtils, Modals, BMA, Device, + UIUtils, Modals, BMA, Device, Api, csHttp, csConfig, csCache, csSettings, csNetwork, csCurrency, csWallet) { 'ngInject'; @@ -110,7 +110,9 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] started = false, startPromise, listeners = [], - removeChangeStateListener; + removeChangeStateListener, + api = new Api(this, 'csPlatform') + ; // Fix csConfig values csConfig.demo = csConfig.demo === true || csConfig.demo === 'true' || false; @@ -141,57 +143,40 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] removeChangeStateListener = null; } - // Alert user if node not reached - fix issue # + // Alert user if node not reached function checkBmaNodeAlive(alive) { - if (alive) return true; + if (alive) return true; // Ok, current node is alive + var askUserConfirmation = checkBmaNodeAliveCounter === 0 && csSettings.data.expertMode; checkBmaNodeAliveCounter++; if (checkBmaNodeAliveCounter > 3) throw 'ERROR.CHECK_NETWORK_CONNECTION'; // Avoid infinite loop - return BMA.filterAliveNodes(csSettings.data.fallbackNodes, Math.min(csConfig.timeout, 3000)/*3s max*/) + api.start.raise.message('NETWORK.INFO.CONNECTING_TO_PEER'); + return BMA.filterAliveNodes(csSettings.data.fallbackNodes, csConfig.timeout) .then(function (fallbackNodes) { - if (!fallbackNodes.length) { - throw 'ERROR.CHECK_NETWORK_CONNECTION'; - } - var randomIndex = Math.floor(Math.random() * fallbackNodes.length); - var fallbackNode = fallbackNodes[randomIndex]; - return fallbackNode; + if (!fallbackNodes.length) throw 'ERROR.CHECK_NETWORK_CONNECTION'; + return _.sample(fallbackNodes); // Random select }) .then(function (fallbackNode) { - // Not expert mode: continue with the fallback node - if (!csSettings.data.expertMode) { - console.info("[platform] Switching to fallback node: {0}".format(fallbackNode.server)); - return fallbackNode; - } - - // If expert mode: ask user to confirm, before switching to fallback node - var confirmMsgParams = {old: BMA.server, new: fallbackNode.server}; - - // Force to show port/ssl, if this is the only difference - if (confirmMsgParams.old === confirmMsgParams.new) { - if (BMA.port != fallbackNode.port) { - confirmMsgParams.new += ':' + fallbackNode.port; - } else if (BMA.useSsl == false && (fallbackNode.useSsl || fallbackNode.port == 443)) { - confirmMsgParams.new += ' (SSL)'; - } + // Ask user before using the fallback node + if (askUserConfirmation) { + return askUseFallbackNode(fallbackNode); } - return $translate('CONFIRM.USE_FALLBACK_NODE', confirmMsgParams) - .then(UIUtils.alert.confirm) - .then(function (confirm) { - if (!confirm) return; // Stop - return fallbackNode; - }); + return fallbackNode; }) .then(function (fallbackNode) { if (!fallbackNode) return; // Skip - // Only change BMA node in settings - csSettings.data.node = fallbackNode; - - // Add a marker, for UI (only if not expert mode) - csSettings.data.node.temporary = !csSettings.data.expertMode; + console.info("[platform] Switching to fallback node: {0}".format(fallbackNode.server)); + var node = { + host: fallbackNode.host, + port: fallbackNode.port, + useSsl: fallbackNode.useSsl, + }; + csSettings.data.node = node; + csSettings.data.node.temporary = true; csHttp.cache.clear(); @@ -202,18 +187,32 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] } // Make sure the BMA node is synchronized (is on the main consensus block) - function checkBmaNodeSynchronized() { + function checkBmaNodeSynchronized(alive) { + if (!alive) return false; var now = Date.now(); + console.info("[platform] Checking if node is synchronized..."); + api.start.raise.message('NETWORK.INFO.CHECKING_NETWORK_STATE'); + + var askUserConfirmation = csSettings.data.expertMode; return csNetwork.getSynchronizedBmaPeers(BMA, { - timeout: Math.min(csConfig.timeout, 3000 /*3s max*/) + timeout: Math.min(csConfig.timeout, 10000 /*10s max*/) }) .then(function(peers) { - console.info("[platform] Network scanned in {0}ms, {1} peers (UP and synchronized) found".format(Date.now() - now, peers.length)); if (!peers.length) return; // No peer found: exit + // Not enough peers in network (isolated node). Should never occur. Make sure at least one known node exists + if (peers.length < 10) { + console.warn("[platform] Network scanned in {0}ms, only {1} peers (UP and synchronized) found. To few peers. Will peek another peer...".format(Date.now() - now, peers.length)); + // Retry using another peer + return checkBmaNodeAlive(false) + .then(checkBmaNodeSynchronized); // Loop + } + + console.info("[platform] Network scanned in {0}ms, {1} peers (UP and synchronized) found".format(Date.now() - now, peers.length)); + // TODO: store sync peers in storage ? //csSettings.data. @@ -242,19 +241,28 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] return true; } - // If Expert mode: ask user to select a node - if (csSettings.data.expertMode) { - return selectBmaNode(); - } - - var randomIndex = Math.floor(Math.random() * peers.length); - var randomPeer = peers[randomIndex]; - var node = { + var randomPeer = _.sample(peers); + var synchronizedNode = { host: randomPeer.getHost(), port: randomPeer.getPort(), useSsl: randomPeer.isSsl() }; - console.info("[platform] Randomly selected peer {0}".format(randomPeer.server)); + + // If Expert mode: ask user to select a node + if (askUserConfirmation) { + return askUseFallbackNode(synchronizedNode); + } + + return synchronizedNode; + }) + .then(function(node) { + if (node === true) return true; + if (!node) { + return selectBmaNode(); + } + + console.info("[platform] Switching to synchronized fallback peer {{0}:{1}}".format(node.host, node.port)); + // Only change BMA node in settings csSettings.data.node = node; @@ -262,7 +270,28 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] csSettings.data.node.temporary = true; return BMA.copy(node); - }); + }) + }); + } + + function askUseFallbackNode(fallbackNode) { + // Ask user to confirm, before switching to fallback node + var confirmMsgParams = {old: BMA.server, new: fallbackNode.server}; + + // Force to show port/ssl, if this is the only difference + if (confirmMsgParams.old === confirmMsgParams.new) { + if (BMA.port != fallbackNode.port) { + confirmMsgParams.new += ':' + fallbackNode.port; + } else if (BMA.useSsl == false && (fallbackNode.useSsl || fallbackNode.port == 443)) { + confirmMsgParams.new += ' (SSL)'; + } + } + + return $translate('CONFIRM.USE_FALLBACK_NODE', confirmMsgParams) + .then(UIUtils.alert.confirm) + .then(function (confirm) { + if (!confirm) return; // Stop + return fallbackNode; }); } @@ -324,8 +353,6 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] return $q.when(); } - - function addListeners() { // Listen if node changed listeners.push( @@ -358,6 +385,8 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] // Avoid change state disableChangeState(); + api.start.raise.message('COMMON.LOADING'); + // We use 'ionicReady()' instead of '$ionicPlatform.ready()', because this one is callable many times startPromise = ionicReady() @@ -370,7 +399,7 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] ])) // Load BMA - .then(function(){ + .then(function() { checkBmaNodeAliveCounter = 0; return BMA.ready() .then(checkBmaNodeAlive) @@ -416,6 +445,8 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] }, 500); } + api.registerEvent('start', 'message'); + return { disableChangeState: disableChangeState, isStarted: isStarted, @@ -425,7 +456,8 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] stop: stop, version: { latest: getLatestRelease - } + }, + api: api }; }) @@ -481,7 +513,7 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] // Ionic Platform Grade is not A, disabling views transitions if (ionic.Platform.grade.toLowerCase() !== 'a') { - console.info('[app] Disabling UI effects, because plateform\'s grade is [' + ionic.Platform.grade + ']'); + console.info('[app] Disabling UI effects, because platform\'s grade is {{0}}'.format(ionic.Platform.grade)); UIUtils.setEffects(false); } diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index e61558fd7..1a88a9ce5 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -97,16 +97,16 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. that.alive = false; // Use settings as default, if exists - if (csSettings.data && csSettings.data.node) { - host = host || csSettings.data.node.host; - port = port || csSettings.data.node.port; - - useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443 || csSettings.data.node.useSsl || that.forceUseSsl); + var node = csSettings.data && csSettings.data.node; + if (node) { + host = host || node.host; + port = port || node.port; + useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443 || node.useSsl || that.forceUseSsl); } - if (!host) { - return; // could not init yet - } + if (!host) return; // could not init yet + + that.host = host; that.port = port || 80; that.useSsl = angular.isDefined(useSsl) ? useSsl : (that.port == 443 || that.forceUseSsl); @@ -308,7 +308,8 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. if (that._startPromise) return that._startPromise; if (that.started) return $q.when(that.alive); - if (!that.host) { + // Load without argument: wait settings, then init using setting's data + if (!that.host || !csSettings.isStarted()) { return csSettings.ready() .then(function() { that.init(); @@ -320,32 +321,29 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }); } - console.debug("[BMA] Starting {0} {ssl: {1})...".format(that.server, that.useSsl)); + console.debug("[BMA] [{0}] Starting {ssl: {1})...".format(that.server, that.useSsl)); var now = Date.now(); - that._startPromise = $q.all([ - csSettings.ready(), - that.isAlive() - ]) - .then(function(res) { - that.alive = res[1]; + that._startPromise = that.isAlive() + .then(function(alive) { + that.alive = alive; if (!that.alive) { - console.error("[BMA] Could not start {0} : unreachable".format(that.server)); + console.error("[BMA] Could not start using peer {{0}}: unreachable".format(that.server)); that.started = true; delete that._startPromise; - return false; + return false; // Not alive } // Add listeners if (!listeners || !listeners.length) { addListeners(); } - console.debug('[BMA] Started in '+(Date.now()-now)+'ms'); + console.debug('[BMA] Started in {}ms'.format(Date.now()-now)); that.api.node.raise.start(); that.started = true; delete that._startPromise; - return true; + return true; // Alive }); return that._startPromise; }; @@ -383,6 +381,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }; that.filterAliveNodes = function(fallbackNodes, timeout) { + timeout = timeout || csConfig.timeout; var fallbackNodes = _.filter(fallbackNodes || [], function(node) { node.server = node.server || node.host + ((!node.port && node.port != 80 && node.port != 443) ? (':' + node.port) : ''); var same = that.node.same(node); @@ -1017,6 +1016,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. service.lightInstance = function(host, port, useSsl, timeout) { port = port || 80; useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443); + timeout = timeout || csConfig.timeout; return { host: host, port: port, diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index 64b14df49..83da91b18 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -42,7 +42,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', searchingPeersOnNetwork: false, difficulties: null, ws2pHeads: null, - timeout: csConfig.timeout + timeout: csConfig.timeout, + startTime: null }, // Return the block uid @@ -50,6 +51,15 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', return block && [block.number, block.hash].join('-'); }, + // Return the block uid + buidBlockNumber = function(buid) { + return (typeof buid === 'string') && parseInt(buid.split('-')[0]); + }, + + remainingTime = function() { + return Math.max(0, data.timeout - (Date.now() - data.startTime)); + }, + resetData = function() { data.bma = null; data.listeners = []; @@ -79,6 +89,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', data.difficulties = null; data.ws2pHeads = null; data.timeout = csConfig.timeout; + data.startTime = null; }, hasPeers = function() { @@ -119,7 +130,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', // When too many request, retry in 3s if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) { return $timeout(function() { - return loadW2spHeads(); + if (remainingTime() > 0) return loadW2spHeads(); }, 3000); } console.error(err); // can occur on duniter v1.6 @@ -140,7 +151,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', // When too many request, retry in 3s if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) { return $timeout(function() { - return loadDifficulties(); + if (remainingTime() > 0) return loadDifficulties(); }, 3000); } console.error(err); @@ -207,7 +218,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', _.forEach(res.peers, function(json) { // Exclude, if not UP or on a too old block if (json.status !== 'UP') return; - json.blockNumber = json.block && parseInt(json.block.split('-')[0]); + json.blockNumber = buidBlockNumber(json.block); if (json.blockNumber && json.blockNumber < data.minOnlineBlockNumber) { console.debug("[network] Exclude a too old peer document, on pubkey {0}".format(json.pubkey.substring(0,6))); return; @@ -219,7 +230,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', _.forEach(json.endpoints||[], function(ep) { if (ep.startsWith('WS2P')) { var key = json.pubkey + '-' + ep.split(' ')[1]; - if (data.ws2pHeads[key]) { + if (data.ws2pHeads && data.ws2pHeads[key]) { data.ws2pHeads[key].hasEndpoint = true; } } @@ -234,7 +245,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', _.forEach(privateWs2pHeads, function(head) { if (!head.hasEndPoint) { - var currentNumber = head.buid && parseInt(head.buid.split('-')[0]); + var currentNumber = buidBlockNumber(head.buid); // Exclude if on a too old block if (currentNumber && currentNumber < data.minOnlineBlockNumber) { console.debug("[network] Exclude a too old WS2P message, on pubkey {0}".format(head.pubkey.substring(0,6))); @@ -286,6 +297,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', } }) .then(function(){ + if (!isStarted()) return; // Skip if stopped data.searchingPeersOnNetwork = false; data.loading = false; if (newPeers.length) { @@ -349,7 +361,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', list = list || data.newPeers; // Analyze the peer document, and exclude using the online filter - json.blockNumber = json.block && parseInt(json.block.split('-')[0]); + json.blockNumber = buidBlockNumber(json.block); json.oldBlock = (json.status === 'UP' && json.blockNumber && json.blockNumber < data.minOnlineBlockNumber); var peers = createPeerEntities(json); @@ -439,7 +451,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', peer.server = peer.getServer(); peer.dns = peer.getDns(); peer.buid = peer.buid || peer.block; - peer.blockNumber = peer.buid && parseInt(peer.buid.split('-')[0]); + peer.blockNumber = buidBlockNumber(peer.buid); peer.uid = peer.pubkey && data.uidsByPubkeys[peer.pubkey]; peer.id = peer.keyID(); return [peer]; @@ -450,6 +462,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', // Apply filter if (!applyPeerFilter(peer)) return $q.when(); + var startRefreshTime = Date.now(); if (!data.filter.online || (!data.filter.online && peer.status === 'DOWN') || !peer.getHost() /*fix #537*/) { peer.online = false; return $q.when(peer); @@ -461,7 +474,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', delete data.ws2pHeads[ws2pHeadKey]; if (head) { peer.buid = head.buid; - peer.currentNumber=head.buid && parseInt(head.buid.split('-')[0]); + peer.currentNumber = buidBlockNumber(head.buid); peer.version = head.version; peer.powPrefix = head.powPrefix; } @@ -499,7 +512,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', return $q.when(peer); } - peer.api = peer.api || BMA.lightInstance(peer.getHost(), peer.getPort(), peer.isSsl(), data.timeout); + const timeout = Math.max(500, remainingTime()); // >= 500ms + peer.api = peer.api || BMA.lightInstance(peer.getHost(), peer.getPort(), peer.isSsl(), timeout); // Get current block return peer.api.blockchain.current(false/*no cache*/) @@ -525,10 +539,14 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', if (!peer.secondTry) { var bma = peer.bma || peer.getBMA(); if (bma.dns && peer.server.indexOf(bma.dns) === -1) { + var secondTryTimeout = remainingTime(); + // try again, using DNS instead of IPv4 / IPV6 - peer.secondTry = true; - peer.api = BMA.lightInstance(bma.dns, bma.port, bma.useSsl); - return refreshPeer(peer); // recursive call + if (secondTryTimeout > 0) { + peer.secondTry = true; + peer.api = BMA.lightInstance(bma.dns, bma.port, bma.useSsl, secondTryTimeout); + return refreshPeer(peer); // recursive call + } } } @@ -760,23 +778,33 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', }, start = function(bma, options) { + if (startPromise) { + console.warn('[network-service] Waiting previous start to be closed...'); + return startPromise.then(function() { + return start(bma, options) + }) + } + options = options || {}; - startPromise = BMA.ready() + bma = bma || BMA; + startPromise = bma.ready() .then(function() { close(); - data.bma = bma || BMA; + data.bma = bma; data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter; data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort; data.expertMode = angular.isDefined(options.expertMode) ? options.expertMode : data.expertMode; data.timeout = angular.isDefined(options.timeout) ? options.timeout : csConfig.timeout; + data.startTime = Date.now(); // Init a min block number - data.minOnlineBlockNumber = data.mainBlock && data.mainBlock.buid && (parseInt(data.mainBlock.buid.split('-')[0]) - constants.MAX_BLOCK_OFFSET) || undefined; + var mainBlockNumber = data.mainBlock && buidBlockNumber(data.mainBlock.buid); + data.minOnlineBlockNumber = mainBlockNumber && Math.max(0, (mainBlockNumber - constants.MAX_BLOCK_OFFSET)) || undefined; if (data.minOnlineBlockNumber === undefined) { return csCurrency.blockchain.current(true/*use cache*/) .then(function(current) { - data.minOnlineBlockNumber = current.number - constants.MAX_BLOCK_OFFSET; + data.minOnlineBlockNumber = Math.max(0, current.number - constants.MAX_BLOCK_OFFSET); }); } }) @@ -797,10 +825,11 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', close = function() { if (data.bma) { - console.info('[network-service] Stopping...'); + console.info('[network] Stopping...'); removeListeners(); resetData(); } + startPromise = null; }, isStarted = function() { @@ -809,13 +838,9 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', startIfNeed = function(bma, options) { if (startPromise) return startPromise; + // Start if need if (!isStarted()) { - // Start (then stop) if need - return start(bma, options) - .then(function() { - close(); - return data; - }); + return start(bma, options); } else { return $q.resolve(data); @@ -823,9 +848,12 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', }, getMainBlockUid = function(bma, options) { + var wasStarted = isStarted(); return startIfNeed(bma, options) .then(function(data) { - return data.mainBlock && data.mainBlock.buid; + var buid = data.mainBlock && data.mainBlock.buid; + if (!wasStarted) close(); + return buid; }); }, @@ -837,12 +865,32 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', options.filter.ssl = isHttpsMode ? true : undefined; options.filter.online = true; options.filter.expertMode = false; + console.info('[network] Getting synchronized BMA peers...'); + + var wasStarted = isStarted(); + var now = Date.now(); return startIfNeed(bma, options) .then(function(data){ - return _.filter(data.peers, function(peer) { + var peers = _.filter(data.peers, function(peer) { return peer.hasMainConsensusBlock && peer.isBma(); }); + + // Log + if (peers.length) { + console.info('[network] Found {0}/{1} BMA peers on main consensus block #{2} - in {3}ms'.format( + peers.length, + data.peers.length, + peers[0] && peers[0].buid, + Date.now() - now)); + } + else { + console.warn('[network] No synchronized BMA peers found, in {1}ms'.format(Date.now() - now)) + } + + if (!wasStarted) close(); + + return peers; }); }; diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js index 15e3db750..d962f4d3a 100644 --- a/www/js/services/settings-services.js +++ b/www/js/services/settings-services.js @@ -115,7 +115,11 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) "en": "license/license_g1-en", "fr-FR": "license/license_g1-fr-FR", "es-ES": "license/license_g1-es-ES", - "pt-PT": "license/license_g1-pt-PT" + "es-CT": "license/license_g1-es-CT", + "eo-EO": "license/license_g1-eo-EO", + "pt-PT": "license/license_g1-pt-PT", + "it-IT": "license/license_g1-it-IT", + "de-DE": "license/license_g1-de-DE" } }, fixedSettings, @@ -174,7 +178,7 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) var promise; if (data.useLocalStorage) { // When node is temporary (fallback node): keep previous node address - issue #476 - if (data.node.temporary === true) { + if (data.node && data.node.temporary === true) { promise = localStorage.getObject(constants.STORAGE_KEY) .then(function(previousSettings) { var savedData = angular.copy(data); @@ -212,6 +216,9 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) applyData = function(newData) { if (!newData) return; // skip empty + // DEBUG + //console.debug('[settings] Applying data', newData); + var localeChanged = false; if (newData.locale && newData.locale.id) { // Fix previously stored locale (could use bad format) @@ -225,11 +232,20 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) newData[key] = defaultSettings[key]; // This will apply fixed value (override by config.js file) }); + // If need select a random peer, from the config + if (!newData.node && _.size(csConfig.fallbackNodes) > 0) { + newData.node = _.sample(csConfig.fallbackNodes); + console.info('[settings] Random selected peer: [{0}:{1}]'.format(newData.node.host, newData.node.port||80)); + newData.node.temporary = true; + } + // Apply new settings angular.merge(data, newData); // Delete temporary properties, if false - if (newData && newData.node && !newData.node.temporary || !data.node.temporary) delete data.node.temporary; + if ((newData && newData.node && !newData.node.temporary) || (data.node && !data.node.temporary)) { + delete data.node.temporary; + } // Apply the new locale (only if need) // will produce an event cached by onLocaleChange(); @@ -251,10 +267,11 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) return; } + console.debug('[settings] Loaded from local storage in {0}ms'.format(Date.now()-now)); + // Apply stored data applyData(storedData); - console.debug('[settings] Loaded from local storage in '+(Date.now()-now)+'ms'); emitChangedEvent(); }); }, diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js index 8011f7361..8bf72a926 100644 --- a/www/js/services/wot-services.js +++ b/www/js/services/wot-services.js @@ -997,7 +997,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c var idtiesByBlock = {}; var idtiesByPubkey = {}; _.forEach(memberships, function(ms){ - if (ms.membership == 'IN' && !uids[ms.pubkey]) { + if (ms.membership === 'IN' && !uids[ms.pubkey]) { var idty = { uid: ms.uid, pubkey: ms.pubkey, @@ -1019,7 +1019,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c // Remove previous idty from map if (otherIdtySamePubkey) { idtiesByBlock[otherIdtySamePubkey.block] = idtiesByBlock[otherIdtySamePubkey.block].reduce(function(res, aidty){ - if (aidty.pubkey == otherIdtySamePubkey.pubkey) return res; // if match idty to remove, to NOT add + if (aidty.pubkey === otherIdtySamePubkey.pubkey) return res; // if match idty to remove, to NOT add return (res||[]).concat(aidty); }, null); if (idtiesByBlock[otherIdtySamePubkey.block] === null) { diff --git a/www/license/license_g1-es-CT.md b/www/license/license_g1-es-CT.md new file mode 100644 index 000000000..5da80f68b --- /dev/null +++ b/www/license/license_g1-es-CT.md @@ -0,0 +1,96 @@ +Licencia Äž1 - v0.2.9 +==================== + +:Date: 2017-04-04 12:59 +:Modified: 2023-01-01 18:33 + +**Licencia de la moneda y compromiso de responsabilidad.** + +Cualquier certificación de nueva membresÃa de Äž1 debe ir primero acompañada por la transmisión de esta licencia de moneda Äž1 cuyo certificador debe asegurar que ha sido estudiada, entendida y aceptada por la persona que será certificada. + +Cualquier evento de encuentro relacionado con Äž1 debe ir acompañado de la transmisión de esta licencia, que puede leerse en voz alta y transmitirse por cualquier medio. + +Red de confianza Äž1 (RdC Äž1) +------------------------------ + +** Aviso de advertencia :** Certificar no significa que simplemente has visto fÃsicamente a la persona candidata. Es asegurar a la comunidad Äž1 que la conoces lo suficientemente bien y que sabrás cómo contactarla y localizarla fácilmente, ser capaz de identificar una posible cuenta falsa o duplicada realizada por alguien que has certificado, u otro tipo de problema, efectuando verificaciones con la comunidad que detecten el problema. La seguridad de la Red de Confianza es descentralizada. + +**Consejos fuertemente recomendados** + +Conocer bien a una persona significa que puedes comunicarte con ella por varios medios distintos (fÃsicos, electrónicos, etc ...) pero también que conoces a varias personas que también la conocen bien y, por lo tanto, pueden contactar con ella igualmente. Además si no conoces bien a nadie de quienes ya le han certificado, es una clara indicación de que no conoces bien a la persona; una certificación de este tipo provoca una alerta hacia toda la comunidad Äž1. En caso de conocimiento insuficiente, es importante NO certificar. + +Nunca certifiques solo/a, sino acompáñate por al menos otro/a miembro de la RdC Äž1 para evitar cualquier error de manejo. En caso de error, advierte a quienes ya son miembros de la RdC Äž1 inmediatamente. + +Antes de cualquier certificación, asegúrate de verificar si su cuenta (tanto si es nueva candidatura o ya miembro) ha recibido ya una o más certificaciones. Si es necesario, solicite información para ponerte en contacto con quienes ya le hayan certificado para verificar juntos/as que conocéis bien la persona en cuestión concerniente, asà como su llave pública correspondiente. + +Comprueba que la persona a ser certificada domina bien el manejo de su cuenta: una buena manera de comprobar esto es transferir unas Äž1 a la cuenta destino, y luego pedir la devolución a tu propia cuenta. Esto asegura el buen manejo por quien va a ser certificado, de su llave privada. + +Comprueba que tus contactos hayan estudiado y comprendido la licencia Äž1 actualizada. + +Si te percatas de que un/a certificador/a real o potencial de la cuenta candidata no conoce a la persona interesada, avisa inmediatamente a quien tenga experiencia en el tema de tus contactos en la RdC Äž1, para que la RdC Äž1 verifique el proceso de validación. + +Cuando eres miembro de la RdC Äž1 y estás a punto de certificar una cuenta: + + +** Estás seguro de: ** + +1°) Conocer suficientemente bien a quien declara poseer esta llave pública (cuenta candidata a miembro). Lea los consejos fuertemente recomendados más arriba para asegurarte de que la "conoces bien". + +2°) Haber comprobado personalmente con esa persona de que se trata de esa llave pública que está a punto de certificar. + +3°) Haber verificado con la persona interesada, que ha generado y guardado su documento o archivo de revocación de cuenta Duniter que le permitirá, si es necesario, desactivar su estado de miembro y cocreación (en caso de robo de las contraseñas, cambio de seudónimo, cuenta creada incorrectamente, etc.). + +4a°) Para verificar el paso 2, para asegurarte de que la persona humana que conoces bien posee esa llave pública, es recomendable hacer esa validación in situ fÃsicamente. + +4b°) O bien se puede realizar la validación de forma remota de la llave pública, comunicándola por diferentes medios, como correo ordinario, electrónico, redes sociales, foro, videoconferencia, llamada telefónica (reconociendo la voz). Si alguien hackeara una cuenta de correo electrónico o una cuenta en un foro, es mucho más difÃcil imaginar que pueda hackear cuatro medios de comunicación separados, e imitar la apariencia (vÃdeo) e incluso la voz de alguien. + +La 4a° es preferible a la 4b° mientras que los puntos 1°, 2° y 3° son ante todo indispensables. + + +**Reglas abreviadas de la RdC :** + +Cada miembro tiene una reserva de 100 certificaciones posibles, que solo pueden hacerse efectivas a razón de 1 certificación cada 5 dÃas. + +Válida durante 2 meses, una certificación se toma en consideración definitivamente para una nueva candidatura de membresÃa si esta persona recibe al menos otras 4 certificaciones que cumplen la regla de distancia durante esos 2 meses, de lo contrario, el proceso de candidatura deberá reiniciarse sin perder acceso a la cuenta. + +Para convertirse en nuevo/a miembro de la RdC Äž1 es necesario obtener 5 certificaciones y estar a una distancia de <= 5 pasos con como mÃnimo un 80% del total de miembros referentes de la RdC. + +Alguien es miembro referente de la RdC Äž1 cuando ha recibido y también emitido al menos Y[N] certificaciones donde N es el total de miembros en la RdC e Y[N] = techo N^(1/5). Ejemplos: + +* Para 1024 < N ≤ 3125 se obtiene que Y[N] = 5 +* Para 7776 < N ≤ 16807 se obtiene que Y[N] = 7 +* para 59049 < N ≤ 100.000 se obtiene que Y[N] = 10 + +Una vez que alguien es nuevo/a miembro de la RdC Äž1, sus certificaciones serán válidas durante 2 años. + +Para seguir siendo miembro, se debe renovar el acuerdo regularmente mediante la llave privada (cada 12 meses) y asegurarse de que siempre se tenga al menos 5 certificaciones válidas después de los 2 años. + +Moneda Äž1 +---------- + +Äž1 se genera a través de un Dividendo Universal (DU) para cada ser humano miembro de la Red de Confianza Äž1, de la siguiente forma: + +* 1 DU por persona y por dÃa. + +La cantidad en Äž1 del DU diario es idéntica hasta pasado cada equinoccio(cada 6 meses) cuando se re-evaluará el DU según la fórmula : + +* DU diario (próximo equinoccio) = DU diario (equinoccio) + c² (M/N)(equinoccio) / (15778800 segundos) + +Teniendo como constantes: + +* c = 4,88% / equinoccio +* DU(0) = 10,00 Äž1 + +Y como variables : + +* *M* la masa monetaria total en el equinoccio +* *N* el número de miembros el dÃa del equinoccio + +Software Äž1 y licencia Äž1 +-------------------------- + +El software Äž1 que permita a los usuarios administrar su uso de Äž1 debe transmitir esta licencia y todos los parámetros técnicos de la moneda Äž1 y de la RdC Äž1 que han sido configurados en el bloque 0 de Äž1. El software que no cumpla con estas obligaciones de la licencia no es compatible con Äž1. + +Para más detalle en los aspectos técnicos, es posible consultar directamente el código de Duniter, que es un software libre asà como los datos de la cadena de bloques (blockchain) Äž1, recuperándolos a través de una instancia (o nodo) de Duniter Äž1. + +Más información en el sitio web del equipo Duniter https://www.duniter.org diff --git a/www/templates/home/home.html b/www/templates/home/home.html index df345cbbe..73765b5c5 100644 --- a/www/templates/home/home.html +++ b/www/templates/home/home.html @@ -40,6 +40,7 @@ <div class="center padding" ng-if="loading"> <ion-spinner icon="android" ></ion-spinner> + <p class="text-italic" translate-values=":currency:{currency: $root.currency.name}" translate>{{loadingMessage}}</p> </div> <div class="center padding animate-fade-in animate-show-hide ng-hide" ng-show="!loading && error"> diff --git a/www/templates/settings/popup_node.html b/www/templates/settings/popup_node.html index d3eda1d0a..9fb9b7723 100644 --- a/www/templates/settings/popup_node.html +++ b/www/templates/settings/popup_node.html @@ -24,7 +24,7 @@ <span class="input-label"> {{'SETTINGS.POPUP_PEER.USE_SSL' | translate}} </span> - <h4> + <h4 class="text-wrap"> <small class="gray" ng-bind-html="'SETTINGS.POPUP_PEER.USE_SSL_HELP' | translate"> </small> </h4> diff --git a/www/templates/settings/settings.html b/www/templates/settings/settings.html index 450db38b3..3f66378b9 100644 --- a/www/templates/settings/settings.html +++ b/www/templates/settings/settings.html @@ -202,21 +202,43 @@ <span class="item item-divider" translate>SETTINGS.NETWORK_SETTINGS</span> + <!-- Expert mode ?--> + <div class="item item-text-wrap item-toggle dark hidden-xs hidden-sm"> + <div class="input-label" ng-bind-html="'SETTINGS.EXPERT_MODE' | translate"></div> + <h4 class="gray" ng-bind-html="'SETTINGS.EXPERT_MODE_HELP' | translate"></h4> + <label class="toggle toggle-royal"> + <input type="checkbox" ng-model="formData.expertMode" > + <div class="track"> + <div class="handle"></div> + </div> + </label> + </div> + <!-- Duniter node --> - <div class="item ink item-text-wrap item-icon-right hidden-xs hidden-sm" ng-click="changeNode()"> + <div class="item ink item-text-wrap item-icon-right" ng-click="changeNode()"> <div class="input-label" translate>SETTINGS.PEER</div> - <!-- node temporary changed --> <ng-if ng-if="formData.node.temporary"> - <h4 class="gray text-wrap assertive" > - <i class="icon ion-alert-circled"></i> - <span ng-bind-html="'SETTINGS.PEER_CHANGED_TEMPORARY' | translate "></span> - </h4> - <div class="item-note assertive text-italic">{{bma.server}}</div> + <!-- node temporary changed --> + <ng-if ng-if="formData.expertMode"> + <h4 class="gray text-wrap assertive" > + <span class="ion-alert-circled"></span> + <span ng-bind-html="'SETTINGS.PEER_CHANGED_TEMPORARY' | translate "></span> + </h4> + <div class="badge badge-assertive">{{bma.server}}</div> + </ng-if> + <!-- node selected automatically --> + <ng-if ng-if="!formData.expertMode"> + <h4 class="gray text-wrap " > + <span class="ion-info-circled positive"></span> + <span ng-bind-html="'SETTINGS.PEER_SELECTED_AUTOMATICALLY' | translate "></span> + </h4> + <div class="badge badge-balanced">{{bma.server}}</div> + </ng-if> </ng-if> <div class="badge badge-balanced" ng-if="!formData.node.temporary">{{bma.server}}</div> - <i class="icon ion-ios-arrow-right"></i> + <i class="icon ion-ios-arrow-right" ng-if="formData.expertMode"></i> </div> <ion-item class="ink item-icon-right visible-xs visible-sm" ng-click="changeNode()"> <div class="input-label hidden-xs" translate>SETTINGS.PEER</div> @@ -225,26 +247,15 @@ <!-- node temporary changed --> <ng-if ng-if="formData.node.temporary"> <h4 class="gray text-wrap assertive" > - <b class="ion-alert-circled"></b> + <span class="ion-alert-circled"></span> <span ng-bind-html="'SETTINGS.PEER_CHANGED_TEMPORARY' | translate "></span> </h4> <div class="badge badge-assertive">{{bma.server}}</div> </ng-if> <div class="badge badge-balanced" ng-if="!formData.node.temporary">{{bma.server}}</div> - <i class="icon ion-ios-arrow-right"></i> + <i class="icon ion-ios-arrow-right" ng-if="formData.expertMode"></i> </ion-item> - <!-- Expert mode ?--> - <div class="item item-text-wrap item-toggle dark hidden-xs hidden-sm"> - <div class="input-label" ng-bind-html="'SETTINGS.EXPERT_MODE' | translate"></div> - <h4 class="gray" ng-bind-html="'SETTINGS.EXPERT_MODE_HELP' | translate"></h4> - <label class="toggle toggle-royal"> - <input type="checkbox" ng-model="formData.expertMode" > - <div class="track"> - <div class="handle"></div> - </div> - </label> - </div> <!-- Block validity window --> <label class="item item-input item-select item-text-wrap"> -- GitLab