diff --git a/www/css/style.css b/www/css/style.css index 986697a80ffc564cc69a01e8fff69a0dd83425fc..ca9c9237896afe700eab2d75aeda392490c1307a 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -43,6 +43,7 @@ left: 0; top: 0; border-radius: 5px; + transition: width 0.2s ease; } #home .progress-text { font-size: 12px; @@ -268,6 +269,7 @@ left: 0; top: 0; border-radius: 5px; + transition: width 0.2s ease; } .list .item-peer .col-sandboxes .progress-text { width: 100%; diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js index 8f018a5e8108609aa0b3ecf0b83dee4c061aa713..be727b9fda90a460afa4f2a622ce0a047a914320 100644 --- a/www/js/controllers/home-controllers.js +++ b/www/js/controllers/home-controllers.js @@ -64,16 +64,18 @@ function HomeController($scope, $state, $timeout, $interval, $ionicHistory, $tra var interval = $interval(function(){ var duration = Date.now() - startTime; var timeout = Math.max(csNetwork.data.timeout, duration); - console.debug('[home] Start duration: ' + duration); // Waiting to start if (!$scope.loadingMessage) { - $scope.loadingPct = Math.min($scope.loadingPct+2, 99); + $scope.loadingPct = Math.min($scope.loadingPct + 0.5, 98); } - if (duration < timeout) { - var loadingPct = duration / timeout * 100; - $scope.loadingPct = Math.min(loadingPct, 99); + else if (duration < timeout) { + var loadingPct = Math.min(duration / timeout * 100, 98); + if (loadingPct > $scope.loadingPct) { + $scope.loadingPct = loadingPct; + } } - }, 100); + $scope.$broadcast('$$rebind::loading'); // force rebind loading + }, 200); // Wait platform to be ready csPlatform.ready() @@ -88,6 +90,7 @@ function HomeController($scope, $state, $timeout, $interval, $ionicHistory, $tra $scope.loading = false; $scope.loadingMessage = ''; $scope.loadingPct = 100; + $scope.$broadcast('$$rebind::loading'); // force rebind loading }); } }; diff --git a/www/js/platform.js b/www/js/platform.js index 4a288974e483d74b40b9cfbdbe71f082cc044bf5..b31f7a23bb65b71574d7e7a3a8cd243885a9091e 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -398,11 +398,12 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] return startPromise || start(); } - function restart() { - console.debug('[platform] restarting csPlatform'); + function restart(startDelayMs) { + console.debug('[platform] Restarting ...'); return stop() .then(function () { - return $timeout(start, 200); + if (startDelayMs === 0) return start(); + return $timeout(start, startDelayMs || 200); }); } @@ -460,18 +461,22 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] } function stop() { - if (!started) return $q.when(); + if (!started && !startPromise) return $q.when(); removeListeners(); - csWallet.stop(); - csCurrency.stop(); - BMA.stop(); + return $q.all([ + csWallet.stop({emitEvent: false}), + csCurrency.stop({emitEvent: false}), + BMA.stop() + ]) + .then(function() { + return $timeout(function() { + enableChangeState(); + started = false; + startPromise = null; + }, 200); + }); - return $timeout(function() { - enableChangeState(); - started = false; - startPromise = null; - }, 500); } api.registerEvent('start', 'message'); diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 565e53adb95d2eea7315a10f3c33421fa3668a4a..100ee9788161ce83146fd2d51778b16aa8ec78a2 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -106,10 +106,10 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. console.debug('[BMA] Enable SSL (forced by config or detected in URL)'); } - if (host) init(host, port, path, useSsl); + if (host) init(host, port, path, useSsl, timeout); that.useCache = angular.isDefined(useCache) ? useCache : true; // need here because used in get() function - function init(host, port, path, useSsl) { + function init(host, port, path, useSsl, timeout) { if (that.started) that.stop(); that.alive = false; @@ -134,6 +134,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. that.useSsl = angular.isDefined(useSsl) ? useSsl : (that.port == 443 || that.forceUseSsl); that.server = csHttp.getServer(that.host, that.port); that.url = csHttp.getUrl(that.host, that.port, that.path, that.useSsl); + that.timeout = timeout || (csSettings.data.expertMode && csSettings.data.timeout > 0 ? csSettings.data.timeout : Device.network.timeout()); } function exact(regexpContent) { @@ -160,16 +161,33 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. csCache.clear(cachePrefix); // Clean raw requests by path cache + cleanRawRequests(); + } + + /** + * Clean raw requests by path cache + */ + function cleanRawRequests() { that.raw.getByPath = {}; that.raw.getCountByPath = {}; that.raw.postByPath = {}; that.raw.wsByPath = {}; } + function setTimeout(newTimeout) { + if (that.timeout === newTimeout && newTimeout > 0) return; // Skip if same, or invalid + + console.debug('[BMA] Using timeout: {0}ms'.format(newTimeout)); + that.timeout = newTimeout; + + // Clean raw requests by path cache + cleanRawRequests(); + } + function getCacheable(path, cacheTime, forcedTimeout) { cacheTime = that.useCache && cacheTime || 0 /* no cache*/ ; - forcedTimeout = forcedTimeout || timeout; + forcedTimeout = forcedTimeout || that.timeout; var cacheKey = path + (cacheTime ? ('#'+cacheTime) : ''); // Store requestFn into a variable a function, to be able to call it to loop @@ -347,13 +365,15 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }; } - that.isAlive = function(node, timeout) { + that.isAlive = function(node, forcedTimeout) { node = node || that; + forcedTimeout = forcedTimeout || that.timeout; + // WARN: // - Cannot use previous get() function, because // node can be !=that, or not be started yet // - Do NOT use cache here - return csHttp.get(node.host, node.port, (node.path || '') + '/node/summary', node.useSsl || that.forceUseSsl, timeout)() + return csHttp.get(node.host, node.port, (node.path || '') + '/node/summary', node.useSsl || that.forceUseSsl, forcedTimeout)() .then(function(json) { var software = json && json.duniter && json.duniter.software; var isCompatible = true; @@ -408,7 +428,8 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. function addListeners() { listeners = [ // Listen if node changed - csSettings.api.data.on.changed($rootScope, onSettingsChanged, this) + csSettings.api.data.on.changed($rootScope, onSettingsChanged, this), + Device.api.network.on.changed($rootScope, onNetworkChanged, this) ]; } @@ -419,6 +440,13 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }, 1000); } + function onNetworkChanged(connectionType) { + connectionType = connectionType || Device.network.connectionType(); + if (connectionType !== 'none') { + setTimeout(Device.network.timeout()); + } + } + that.isStarted = function() { return that.started; }; @@ -476,7 +504,6 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. if (!that.started && !that._startPromise) return $q.when(); // Skip multiple call console.debug('[BMA] Stopping...'); - removeListeners(); delete that._startPromise; @@ -494,8 +521,10 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }; that.restart = function() { - that.stop(); - return $timeout(that.start, 200) + return that.stop() + .then(function() { + return $timeout(that.start, 200); + }) .then(function(alive) { if (alive) { that.api.node.raise.restart(); @@ -504,8 +533,8 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }); }; - that.filterAliveNodes = function(fallbackNodes, timeout) { - timeout = timeout || csSettings.data.timeout; + that.filterAliveNodes = function(fallbackNodes, forcedTimeout) { + forcedTimeout = forcedTimeout || csSettings.data.timeout > 0 ? csSettings.data.timeout : that.timeout; // Filter to exclude the current BMA node fallbackNodes = _.filter(fallbackNodes || [], function(node) { @@ -515,7 +544,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. return !same; }); - console.debug('[BMA] Getting alive fallback nodes... {timeout: {0}}'.format(timeout)); + console.debug('[BMA] Getting alive fallback nodes... {timeout: {0}}'.format(forcedTimeout)); var aliveNodes = []; return $q.all(_.map(fallbackNodes, function(node) { @@ -1180,7 +1209,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. service.lightInstance = function(host, port, path, useSsl, timeout) { port = port || 80; useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443); - timeout = timeout || csSettings.data.timeout; + timeout = timeout || (csSettings.data.expertMode && csSettings.data.timeout > 0 ? csSettings.data.timeout : Device.network.timeout()); path = path || (host.indexOf('/') !== -1 ? host.substring(host.indexOf('/')) : ''); if (!path.startsWith('/')) path = '/' + path; // Add starting slash if (path.endsWith('/')) path = path.substring(0, path.length - 1); // Remove trailing slash @@ -1194,7 +1223,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. url: csHttp.getUrl(host, port, path, useSsl), node: { summary: csHttp.getWithCache(host, port, path + '/node/summary', useSsl, csCache.constants.MEDIUM, false/*autoRefresh*/, timeout), - sandboxes: csHttp.get(host, port, path + '/node/sandboxes', useSsl, timeout), + sandboxes: csHttp.get(host, port, path + '/node/sandboxes', useSsl, Math.max(1000, timeout)), // sandboxes request can be long }, network: { peering: { diff --git a/www/js/services/currency-services.js b/www/js/services/currency-services.js index 4efb6fac8be54798e59c200a85c9d468f5cc9f46..3090e48a75bece126ec7819a916752e992cbf045 100644 --- a/www/js/services/currency-services.js +++ b/www/js/services/currency-services.js @@ -212,15 +212,26 @@ angular.module('cesium.currency.services', ['ngApi', 'cesium.bma.services']) return (startPromise || start()); } - function stop() { + function stop(options) { + if (!started && !startPromise) return $q.when(); + console.debug('[currency] Stopping...'); removeListeners(); - resetData(); + + // Clean data + if (!options || options.emitEvent !== false) { + resetData(); + } + + return $q.when(); } - function restart() { - stop(); - return $timeout(start, 200); + function restart(startDelayMs) { + return stop() + .then(function () { + if (startDelayMs === 0) return start(); + return $timeout(start, startDelayMs || 200); + }); } function start(bmaAlive) { diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js index deb32a42f3c258e5e5e7ce3189b26694f9bae420..7aff73be20445762f3e6731142d6a71dd452c688 100644 --- a/www/js/services/device-services.js +++ b/www/js/services/device-services.js @@ -151,47 +151,59 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti }; exports.network = { connectionType: function () { + try { + // If mobile: use the Cordova network plugin + if (exports.network.enable) { + return navigator.connection.type || 'unknown'; + } - // If desktop: use ethernet as default connection type - if (exports.isDesktop()) { - return 'ethernet'; - } + // Continue using browser API + if (navigator.onLine === false) { + return 'none'; + } - try { - var connectionType = navigator.connection && (navigator.connection.effectiveType || navigator.connection.type) || 'unknown'; - console.debug('[device] Navigator connection type: ' + connectionType); - switch (connectionType) { - case 'slow-2g': - case '2g': - case 'cell_2g': - return 'cell_2g'; - case '3g': - case 'cell_3g': - return 'cell_3g'; - case 'cell': // iOS - case '4g': - case 'cell_4g': - return 'cell_4g'; - case '5g': - case 'cell_5g': - return 'cell_5g'; - case 'wifi': - return 'wifi'; - case 'ethernet': - return 'ethernet'; - case 'none': - return 'none'; - default: - return 'unknown'; + var connection = navigator.connection; + var connectionType = connection && connection.effectiveType || 'unknown'; + + // Si la vitesse de liaison descendante est de 0 mais que le type est '4g', cela signifie probablement que nous sommes hors ligne + if (connection && connection.downlink === 0) { + //console.debug('[device] Navigator connection type: none (downlink=0)'); + return 'none'; } - } catch (err) { + else { + //console.debug('[device] Navigator connection type: ' + connectionType); + switch (connectionType) { + case 'slow-2g': + case '2g': + return 'cell_2g'; + case '3g': + return 'cell_3g'; + case '4g': + if (exports.isDesktop()) return 'ethernet'; + return 'cell_4g'; + case '5g': + if (exports.isDesktop()) return 'ethernet'; + return 'cell_5g'; + case 'unknown': + if (exports.isDesktop()) return 'ethernet'; + return 'unknown'; + default: + return connectionType + } + } + + } + catch(err) { console.error('[device] Cannot get connection type: ' + (err && err.message || err), err); return 'unknown'; } }, isOnline: function () { try { - return exports.network.connectionType() !== 'none'; + if (exports.network.enable) { + return navigator.connection.type !== Connection.NONE; + } + return angular.isDefined(navigator.onLine) ? navigator.onLine : true; } catch (err) { console.error('[device] Cannot check if online: ' + (err && err.message || err), err); return true; @@ -199,7 +211,10 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti }, isOffline: function () { try { - return exports.network.connectionType() === 'none'; + if (exports.network.enable) { + return navigator.connection.type === Connection.NONE; + } + return angular.isDefined(navigator.onLine) ? !navigator.onLine : false; } catch (err) { console.error('[device] Cannot check if offline: ' + (err && err.message || err), err); return true; @@ -224,13 +239,13 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti break; case 'cell': // (e.g. iOS) case 'cell_4g': - timeout = 5000; + timeout = 4000; // 4s break; case 'cell_3g': - timeout = 10000; // 10s + timeout = 5000; // 5s break; case 'cell_2g': - timeout = 30000; // 30s + timeout = 10000; // 10s break; case 'none': timeout = 0; @@ -240,7 +255,9 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti timeout = defaultTimeout; break; } - console.debug('[device] Using timeout: {1}ms (connection type: \'{0}\')'.format(connectionType, timeout)); + + // DEBUG + //console.debug('[device] Using timeout: {1}ms (connection type: \'{0}\')'.format(connectionType, timeout)); return timeout; } catch (err) { @@ -537,12 +554,12 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti console.debug('[device] Windows plugins: ' + Object.keys(window.plugins)); exports.camera.enable = !!navigator.camera; - exports.keyboard.enable = cordova && cordova.plugins && !!cordova.plugins.Keyboard; - exports.barcode.enable = cordova && cordova.plugins && !!cordova.plugins.barcodeScanner && (!exports.isOSX() || exports.isIOS()); - exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard; - exports.intent.enable = window && !!window.plugins.launchmyapp; - exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard; - exports.network.enable = navigator.connection && !!navigator.connection.type; + exports.keyboard.enable = cordova && cordova.plugins && !!cordova.plugins.Keyboard || false; + exports.barcode.enable = cordova && cordova.plugins && !!cordova.plugins.barcodeScanner && (!exports.isOSX() || exports.isIOS()) || false; + exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard || false; + exports.intent.enable = window && !!window.plugins.launchmyapp || false; + exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard || false; + exports.network.enable = navigator.connection && !!navigator.connection.type || false; exports.file.enable = !!cordova.file && (exports.isAndroid() || exports.isIOS()); if (exports.keyboard.enable) { @@ -566,17 +583,37 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti // Add network listeners if (exports.network.enable) { - document.addEventListener("offline", function () { + document.addEventListener('offline', function () { console.info('[device] Network is offline'); api.network.raise.offline(); }, false); - document.addEventListener("online", function () { + document.addEventListener('online', function () { console.info('[device] Network is online'); api.network.raise.online(); }, false); } + } else { console.debug('[device] Ionic platform ready - no device detected.'); + + // Add network listeners + window.addEventListener('offline', function () { + console.info('[device] Network is offline'); + api.network.raise.offline(); + }, false); + window.addEventListener('online', function () { + console.info('[device] Network is online'); + api.network.raise.online(); + }, false); + + // Listen connection type change + if (navigator.connection) { + navigator.connection.addEventListener('change', function() { + var connectionType = exports.network.connectionType(); + console.info('[device] Network connection type changed: ' + connectionType); + api.network.raise.changed(connectionType); + }); + } } started = true; @@ -589,6 +626,7 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti api.registerEvent('intent', 'new'); api.registerEvent('network', 'offline'); api.registerEvent('network', 'online'); + api.registerEvent('network', 'changed'); // Export the event api (see ngApi) exports.api = api; diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index 0569e443273f6ed72e1ec16b85f8a70c57a9ac5a..501dba84cbe508f18d4efd8dec173a227afaa9dd 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -62,7 +62,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', }, resetData = function() { - data.starCounter = 0; + // Keep previous PID + //data.pid = 0; data.bma = null; data.listeners = []; data.peers.splice(0); @@ -90,7 +91,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', data.searchingPeersOnNetwork = false; data.difficulties = null; data.ws2pHeads = null; - data.timeout = getDefaultTimeout(); + data.timeout = data.timeout || getDefaultTimeout(); data.startTime = null; }, @@ -544,7 +545,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', return $q.when(peer); } - var timeout = Math.max(500, remainingTime()); // >= 500ms + var timeout = Math.max(data.timeout / 2, remainingTime()); // >= 500ms peer.api = peer.api || BMA.lightInstance(peer.getHost(), peer.getPort(), peer.getPath(), peer.isSsl(), timeout); // Get current block @@ -908,8 +909,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', }, close = function(pid) { - console.info(pid > 0 ? '[network] [#{0}] Stopping...'.format(pid) : '[network] Stopping...'); if (data.bma) { + console.info(pid > 0 ? '[network] [#{0}] Stopping...'.format(pid) : '[network] Stopping...'); removeListeners(); resetData(); } diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 5efc800d7035634fe2a17f28d936ce22393783eb..e8d7e87657dd3656a8619622c27b35c7c55573ed 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -2425,16 +2425,29 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se return startPromise || start(); } - function stop() { + function stop(options) { + if (!started && !startPromise) return $q.when(); + var wasLogin = isLogin(); var wasAuth = isAuth(); + console.debug('[wallet] Stopping...'); removeListeners(); - resetData(); - // Send logout/unauth events - if (wasLogin) api.data.raise.logout(); - if (wasAuth) api.data.raise.unauth(); + if (!options || options.emitEvent !== false) { + // Reset all data + resetData(); + + // Send logout/unauth events + if (wasLogin) api.data.raise.logout(); + if (wasAuth) api.data.raise.unauth(); + } + else { + // Just mark as need to reload + data.loaded = false; + } + + return $q.when(); } function restart() { diff --git a/www/templates/home/home.html b/www/templates/home/home.html index d4c01c896e282fd872f00d4350055330b8bf9e2b..26cd84200e2265d06801c65db83aaadcefb203bf 100644 --- a/www/templates/home/home.html +++ b/www/templates/home/home.html @@ -1,4 +1,4 @@ -<ion-view id="home" bind-notifier="{locale:$root.settings.locale.id, feed: showFeed}"> +<ion-view id="home" bind-notifier="{locale:$root.settings.locale.id, feed: showFeed, loading: loading}"> <!-- no title --> <ion-nav-title></ion-nav-title> @@ -41,14 +41,14 @@ <div class="center padding" ng-if="loading"> <p class="text-center" translate>COMMON.LOADING</p> - <div class="progress-bar" ng-if="loadingPct"> - <div class="progress-fill" style="width: {{loadingPct + '%'}}"> + <div class="progress-bar" > + <div class="progress-fill" style="width: {{:loading:loadingPct + '%'}}"> </div> </div> - <p class="text-italic progress-text" ng-if="loadingPct"> - <span translate-values=":currency:{currency: $root.currency.name}" translate>{{loadingMessage}}</span> - <span>({{loadingPct|formatInteger}} %)</small> + <p class="text-italic progress-text"> + {{:loading:loadingMessage|translate:{currency: $root.currency.name} }} + <small>({{:loading:loadingPct|formatInteger}} %)</small> </p> </div>