diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index 2b8e0cd3cbf6b143d33baf17ee92699df2ac55de..18ba747d33d107f6881e5a37b02b93d23cef7b31 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -98,12 +98,12 @@ "ABOUT": { "TITLE": "About", "LICENSE": "<b>Free/libre software</b> (License GNU GPLv3).", + "LATEST_RELEASE": "There is a <b>newer version</ b> of {{'COMMON.APP_NAME' | translate}} (<b>v{{version}}</b>)", + "PLEASE_UPDATE": "Please update {{'COMMON.APP_NAME' | translate}} (latest version: <b>v{{version}}</b>)", "CODE": "Source code:", "DEVELOPERS": "Developers:", "FORUM": "Forum:", - "DEV_WARNING": "Warning", - "DEV_WARNING_MESSAGE": "This application is still in active development.<br/>Please report any issue to us!", - "DEV_WARNING_MESSAGE_SHORT": "This App is still unstable (still under development).", + "PLEASE_REPORT_ISSUE": "Please report any issue to us!", "REPORT_ISSUE": "Report an issue" }, "HOME": { diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 45a3e7022ec3626d4173b34bffd781c763a8481b..e71bf79ee16a2ac4fa6e0b2b67c62db7fddd32ed 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -98,12 +98,12 @@ "ABOUT": { "TITLE": "About", "LICENSE": "<b>Free/libre software</b> (License GNU GPLv3).", + "LATEST_RELEASE": "There is a <b>newer version</ b> of {{'COMMON.APP_NAME' | translate}} (<b>v{{version}}</b>)", + "PLEASE_UPDATE": "Please update {{'COMMON.APP_NAME' | translate}} (latest version: <b>v{{version}}</b>)", "CODE": "Source code:", "DEVELOPERS": "Developers:", "FORUM": "Forum:", - "DEV_WARNING": "Warning", - "DEV_WARNING_MESSAGE": "This application is still in active development.<br/>Please report any issue to us!", - "DEV_WARNING_MESSAGE_SHORT": "This App is still unstable (still under development).", + "PLEASE_REPORT_ISSUE": "Please report any issue to us!", "REPORT_ISSUE": "Report an issue" }, "HOME": { @@ -342,6 +342,9 @@ "NO_PENDING": "No pending registrations.", "NO_NEWCOMERS": "No members." }, + "CONTACTS": { + "TITLE": "Contacts" + }, "MODAL": { "TITLE": "Search" }, diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json index 23bfda351f692e36f2fa00ee29dd52ac2738b3e3..8b327d6d267a0d7efa197d205212537ed1c5fc12 100644 --- a/www/i18n/locale-es-ES.json +++ b/www/i18n/locale-es-ES.json @@ -98,12 +98,12 @@ "ABOUT": { "TITLE": "A propósito ", "LICENSE": "Aplicación <b>libre</b> (licencia GNU GPLv3).", + "LATEST_RELEASE": "Hay una <b>versión más nueva</b> de {{'COMMON.APP_NAME' | translate}} (<b>v{{version}}</b>)", + "PLEASE_UPDATE": "Por favor actualice {{'COMMON.APP_NAME' | translate}} (última versión: <b>v{{version}}</b>)", "CODE": "Codigo fuente :", "DEVELOPERS": "Desarrollado por :", "FORUM": "Foro :", - "DEV_WARNING": "Advertencia", - "DEV_WARNING_MESSAGE": "Esta applicación ya no es estabilizada (Desarrollo en proceso).<br/>No duda a informarnos de las anomalías encontradas !", - "DEV_WARNING_MESSAGE_SHORT": "Esta Ap ya no es estabilizada (Desarrollo en proceso).", + "PLEASE_REPORT_ISSUE": "No duda a informarnos de las anomalías encontradas", "REPORT_ISSUE": "Informar de un problema" }, "HOME": { @@ -342,6 +342,9 @@ "NO_PENDING": "Ninguna inscripción en espera.", "NO_NEWCOMERS": "Ningun miembro." }, + "CONTACTS": { + "TITLE": "Contactos" + }, "MODAL": { "TITLE": "Búsqueda" }, diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 831079a8a0dc6357129ae785b2e235908c8d25bd..25beb99a50170310df1a517734f5a152bb97d0a7 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -98,12 +98,12 @@ "ABOUT": { "TITLE": "À propos", "LICENSE": "Application <b>libre</b> (licence GNU GPLv3).", + "LATEST_RELEASE": "Il existe une <b>version plus récente</b> de {{'COMMON.APP_NAME'|translate}} (<b>v{{version}}</b>)", + "PLEASE_UPDATE": "Veuillez mettre à jour {{'COMMON.APP_NAME'|translate}} (dernière version : <b>v{{version}}</b>)", "CODE": "Code source :", "DEVELOPERS": "Développé par :", "FORUM": "Forum :", - "DEV_WARNING": "Avertissement", - "DEV_WARNING_MESSAGE": "Cette application est encore en plein développement.<br/>N'hésitez pas à nous remonter les anomalies rencontrées !", - "DEV_WARNING_MESSAGE_SHORT": "Cette App est en plein développement.", + "PLEASE_REPORT_ISSUE": "N'hésitez pas à nous remonter les anomalies rencontrées", "REPORT_ISSUE": "Remonter un problème" }, "HOME": { diff --git a/www/js/controllers/app-controllers.js b/www/js/controllers/app-controllers.js index b36b2823542e2eecc03e080c516a36d2b5d1c934..b83361552bc8362f06931ed2fb8034773d51acf3 100644 --- a/www/js/controllers/app-controllers.js +++ b/www/js/controllers/app-controllers.js @@ -411,6 +411,7 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $ $scope.doMotion = function(options) { return $scope.motion.show(options); }; + } diff --git a/www/js/platform.js b/www/js/platform.js index d2d00e3b2a41bb15f36537b1de4ae4b1dd9f1703..0c314f914021fb6908b0cd84d5ec47ae8ee194d6 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -161,6 +161,30 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] return started; } + + function getLatestRelease() { + var latestRelease = csSettings.data.latestReleaseUrl && csHttp.uri.parse(csSettings.data.latestReleaseUrl); + if (latestRelease) { + return csHttp.get(latestRelease.host, latestRelease.port, "/" + latestRelease.pathname)() + .then(function (json) { + //console.debug(json); + if (json && json.name && json.tag_name && json.html_url) { + return { + version: json.name, + url: json.html_url, + isNewer: (csHttp.version.compare(csConfig.version, json.name) < 0) + }; + } + }) + .catch(function(err) { + // silent (just log it) + console.error('[platform] Failed to get latest version', err); + }) + ; + } + return $q.when(); + } + function addListeners() { listeners = [ // Listen if node changed @@ -254,7 +278,10 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] ready: ready, restart: restart, start: start, - stop: stop + stop: stop, + version: { + latest: getLatestRelease + } }; }) @@ -318,6 +345,18 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] StatusBar.styleDefault(); } + // Get latest release + csPlatform.version.latest() + .then(function(release) { + if (release.isNewer) { + console.info('[app] New release detected: {0}'.format(release.version)); + $rootScope.newRelease = release; + } + else { + console.info('[app] Already use latest release {0}'.format(csConfig.version)); + } + }); + // Make sure platform is started return csPlatform.ready(); }); diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js index 455ab75396f1a139d1ebea2d4ef26ae906a6f2b9..60c4de561afde54be76608ac2f1c0d7be4fd4d14 100644 --- a/www/js/services/device-services.js +++ b/www/js/services/device-services.js @@ -19,6 +19,7 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti // workaround to quickly no is device or not (even before the ready() event) enable: true }, + cache = {}, started = false, startPromise; @@ -204,12 +205,19 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti }; exports.isDesktop = function() { - try { - // Has NodeJs + NW ? - return !!process && !!App; - } catch (err) { - return false; + if (!angular.isDefined(cache.isDesktop)) { + try { + // Should have NodeJs and NW + cache.isDesktop = !exports.enable && !!process && !!App; + } catch (err) { + cache.isDesktop = false; + } } + return cache.isDesktop; + }; + + exports.isWeb = function() { + return !exports.enable && !exports.isDesktop(); }; exports.ready = function() { diff --git a/www/js/services/http-services.js b/www/js/services/http-services.js index 4803235358ff3190f1108714fb572e0c2059fbdc..892cf86a4bcffaef557043b843b0a6ba0e168c36 100644 --- a/www/js/services/http-services.js +++ b/www/js/services/http-services.js @@ -346,10 +346,71 @@ angular.module('cesium.http.services', ['cesium.cache.services']) return Math.floor(moment().utc().valueOf() / 1000); } + function isPositiveInteger(x) { + // http://stackoverflow.com/a/1019526/11236 + return /^\d+$/.test(x); + } + + /** + * Compare two software version numbers (e.g. 1.7.1) + * Returns: + * + * 0 if they're identical + * negative if v1 < v2 + * positive if v1 > v2 + * Nan if they in the wrong format + * + * E.g.: + * + * assert(version_number_compare("1.7.1", "1.6.10") > 0); + * assert(version_number_compare("1.7.1", "1.7.10") < 0); + * + * "Unit tests": http://jsfiddle.net/ripper234/Xv9WL/28/ + * + * Taken from http://stackoverflow.com/a/6832721/11236 + */ + function compareVersionNumbers(v1, v2){ + var v1parts = v1.split('.'); + var v2parts = v2.split('.'); + + // First, validate both numbers are true version numbers + function validateParts(parts) { + for (var i = 0; i < parts.length; ++i) { + if (!isPositiveInteger(parts[i])) { + return false; + } + } + return true; + } + if (!validateParts(v1parts) || !validateParts(v2parts)) { + return NaN; + } + + for (var i = 0; i < v1parts.length; ++i) { + if (v2parts.length === i) { + return 1; + } + + if (v1parts[i] === v2parts[i]) { + continue; + } + if (v1parts[i] > v2parts[i]) { + return 1; + } + return -1; + } + + if (v1parts.length != v2parts.length) { + return -1; + } + + return 0; + } + function isVersionCompatible(minVersion, actualVersion) { // TODO: add implementation console.debug('[http] TODO: implement check version [{0}] compatible with [{1}]'.format(actualVersion, minVersion)); - return true; + return compareVersionNumbers(minVersion, actualVersion) <= 0; } var cache = angular.copy(csCache.constants); @@ -374,6 +435,7 @@ angular.module('cesium.http.services', ['cesium.cache.services']) now: getDateNow }, version: { + compare: compareVersionNumbers, isCompatible: isVersionCompatible }, cache: cache diff --git a/www/js/services/modal-services.js b/www/js/services/modal-services.js index 3ad9f7cb029e44b487afafcf8d607f28ad3e4cc9..39de3652c7c703c9f0143a487ce0e6a8f79b2a31 100644 --- a/www/js/services/modal-services.js +++ b/www/js/services/modal-services.js @@ -1,11 +1,26 @@ angular.module('cesium.modal.services', []) // Useful for modal with no controller -.controller('EmptyModalCtrl', function ($scope, parameters) { +.controller('EmptyModalCtrl', function () { 'ngInject'; }) +.controller('AboutModalCtrl', function ($scope, UIUtils, csHttp) { + 'ngInject'; + + $scope.openLink = function(event, uri, options) { + options = options || {}; + + // If unable to open, just copy value + options.onError = function() { + return UIUtils.popover.copy(event, uri); + }; + + return csHttp.uri.open(uri, options); + }; +}) + .factory('ModalUtils', function($ionicModal, $rootScope, $q, $injector, $controller, $timeout) { 'ngInject'; @@ -164,7 +179,7 @@ angular.module('cesium.modal.services', []) } function showAbout(parameters) { - return ModalUtils.show('templates/modal_about.html','EmptyModalCtrl', + return ModalUtils.show('templates/modal_about.html','AboutModalCtrl', parameters); } diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js index a1e1656dd70b4a91c2875fd78a12a0ba545946aa..26def58c9e734951bdfd3efaa7ff4fdf2d30d426 100644 --- a/www/js/services/settings-services.js +++ b/www/js/services/settings-services.js @@ -68,6 +68,7 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) uiEffects: true, minVersion: '1.1.0', newIssueUrl: "https://git.duniter.org/clients/cesium/cesium/issues/new", + latestReleaseUrl: "https://api.github.com/repos/duniter/cesium/releases/latest", helptip: { enable: true, installDocUrl: "https://duniter.org/en/wiki/duniter/install/", @@ -191,6 +192,8 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) data.timeWarningExpireMembership = defaultSettings.timeWarningExpireMembership; data.cacheTimeMs = defaultSettings.cacheTimeMs; data.timeout = defaultSettings.timeout; + data.minVersion = defaultSettings.minVersion; + data.latestReleaseUrl = defaultSettings.latestReleaseUrl; // Apply the new locale (only if need) if (localeChanged) { diff --git a/www/templates/menu.html b/www/templates/menu.html index aa01419da3f8ea694e939964ee9291d6ada4747c..7221d87c703f975715dedbf00acc464c80d559a2 100644 --- a/www/templates/menu.html +++ b/www/templates/menu.html @@ -200,14 +200,24 @@ <ion-footer-bar class="bar-stable footer hidden-xs hidden-sm" > <a class="pull-left icon-help" menu-toggle="left" title="{{:locale:'HOME.BTN_HELP'|translate}}" ui-sref="app.help"></a> - <a class="title gray" ng-click="showAboutModal()" title="{{:locale:'HOME.BTN_ABOUT'|translate}}"> + <a class="title gray" ng-click="showAboutModal()" > + <!-- version --> - {{:locale:'COMMON.APP_VERSION'|translate:{version: config.version} }} + <span title="{{:locale:'HOME.BTN_ABOUT'|translate}}" + ng-class="{'assertive': $root.newRelease}"> + <!-- warning icon, if new version available --> + <i ng-if="$root.newRelease" class="ion-alert-circled assertive"></i> + + {{:locale:'COMMON.APP_VERSION'|translate:{version: config.version} }} + </span> | <!-- about --> - {{:locale:'HOME.BTN_ABOUT'|translate}} + <span title="{{:locale:'HOME.BTN_ABOUT'|translate}}"> + {{:locale:'HOME.BTN_ABOUT'|translate}} + </span> </a> + </ion-footer-bar> <!-- endRemoveIf(device) --> </ion-side-menu> diff --git a/www/templates/modal_about.html b/www/templates/modal_about.html index 9dd7649913d9876298d7f3aee06d16f148d101a0..9955c7a972b97ba4f06bbbf645346d8588af3c74 100644 --- a/www/templates/modal_about.html +++ b/www/templates/modal_about.html @@ -7,50 +7,61 @@ <ion-content class="text-center" scroll="true"> - <div class="list item-wrap-text"> - <div class="item item-complex item-icon-left item-text-wrap"> - <div class="item-content"> - <span>{{'COMMON.APP_NAME'|translate}} {{'COMMON.APP_VERSION'|translate:$root.config}}</span> - <h3 ng-if="$root.config.build" class="gray">{{'COMMON.APP_BUILD'|translate:$root.config}}</h3> - <span translate>ABOUT.LICENSE</span> - </div> - </div> - <div class="item item-complex item-icon-left"> - <div class="item-content"> - <i class="item-image icon ion-social-github"></i> - {{'ABOUT.CODE' | translate}} - <h3><a href="https://git.duniter.org/clients/cesium/cesium" target="_system">https://git.duniter.org/clients/cesium/cesium</a></h3> - </div> - </div> - <div class="item item-complex item-icon-left"> - <div class="item-content"> - <i class="item-image icon ion-chatbubbles"></i> - {{'ABOUT.FORUM' | translate}} - <h3><a href="https://forum.duniter.org" target="_system">https://forum.duniter.org</a> - </div> - </div> - <div class="item item-complex item-icon-left"> - <div class="item-content"> - <i class="item-image icon ion-chatbubbles"></i> - {{'ABOUT.DEVELOPERS' | translate}} - <h3> - <a href="https://github.com/c-geek" target="_system">cgeek</a>, - <a href="https://github.com/devingfx" target="_system">DiG</a>, - <a href="https://github.com/blavenie" target="_system">Benoit Lavenier</a> - </h3> - </div> - </div> - <div class="item item-complex item-icon-left item-text-wrap"> - <div class="item-content"> - <i class="item-image icon ion-bug"></i> - <h2>{{'ABOUT.DEV_WARNING'|translate}}</h2> - <span translate>ABOUT.DEV_WARNING_MESSAGE</span> - <br/> - <a href="{{$root.config.newIssueUrl}}" - target="_system" - translate>ABOUT.REPORT_ISSUE</a> - </div> - </div> + <ion-list class="item-wrap-text"> + <ion-item class="item-icon-left item-text-wrap"> + {{'COMMON.APP_NAME'|translate}} <b>{{'COMMON.APP_VERSION'|translate:$root.config}}</b> + <i ng-if="$root.newRelease" class="assertive ion-alert-circled"></i> + <h3 ng-if="$root.config.build" class="gray">{{'COMMON.APP_BUILD'|translate:$root.config}}</h3> + <span translate>ABOUT.LICENSE</span> + </ion-item> + + <!-- new version --> + <ion-item class="item-icon-left" ng-if="$root.newRelease"> + <i class="item-image icon ion-alert-circled assertive"></i> + + <span ng-if="!$root.device.isWeb()" ng-bind-html="'ABOUT.PLEASE_UPDATE' | translate:$root.newRelease "></span> + <span ng-if="$root.device.isWeb()" ng-bind-html="'ABOUT.LATEST_RELEASE' | translate:$root.newRelease "></span> + + <!-- link to release page --> + <h3 ng-if="!$root.device.enable"> + <a ng-click="openLink($event, $root.newRelease.url)" translate>{{$root.newRelease.url}}</a> + </h3> + </ion-item> + + <!-- report issue --> + <ion-item class="item-icon-left item-text-wrap"> + <i class="item-image icon ion-bug"></i> + <span translate>ABOUT.PLEASE_REPORT_ISSUE</span> + <h3> + <a ng-click="openLink($event, $root.config.newIssueUrl)" translate>ABOUT.REPORT_ISSUE</a> + </h3> + </ion-item> + + + <!-- source code --> + <ion-item class="item-icon-left"> + <i class="item-image icon ion-network"></i> + {{'ABOUT.CODE' | translate}} + <h3><a ng-click="openLink($event, 'https://git.duniter.org/clients/cesium/cesium')">https://git.duniter.org/clients/cesium/cesium</a></h3> + </ion-item> + + <!-- forum --> + <ion-item class="item-icon-left"> + <i class="item-image icon ion-chatbubbles"></i> + {{'ABOUT.FORUM' | translate}} + <h3><a ng-click="openLink($event, 'https://forum.duniter.org')">https://forum.duniter.org</a></h3> + </ion-item> + + <!-- team --> + <ion-item class="item-icon-left"> + <i class="item-image icon ion-person-stalker"></i> + {{'ABOUT.DEVELOPERS' | translate}} + <h3> + <a href="https://github.com/c-geek" target="_system">cgeek</a>, + <a href="https://github.com/devingfx" target="_system">DiG</a>, + <a href="https://github.com/blavenie" target="_system">Benoit Lavenier</a> + </h3> + </ion-item> <div class="padding hidden-xs text-center"> <button class="button button-positive ink" type="submit"