diff --git a/_locales/en/messages.json b/_locales/en/messages.json index fd47ad16..098533be 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -5,12 +5,12 @@ "warningTitle": { "message": "Warning" }, + "noticeTitle": { + "message": "Notice" + }, "options_title": { "message": "Application Options" }, - "options_receive_app_notifications": { - "message": "Receive desktop notification when application updates" - }, "connect": { "message": "Connect" }, @@ -35,6 +35,12 @@ "permanentExpertMode": { "message": "Permanently enable Expert Mode" }, + "checkForConfiguratorUnstableVersions": { + "message": "Show update notifications for unstable versions of the configurator" + }, + "configuratorUpdateNotice": { + "message": "You are using an outdated version of the Betaflight Configurator.
Version $1 is available online, please visit the release page to download and install the latest version with fixes and improvements.
Please close the configurator window before updating." + }, "deviceRebooting": { "message": "Device - Rebooting" }, diff --git a/eventPage.js b/eventPage.js index 54043e5b..f7d57159 100755 --- a/eventPage.js +++ b/eventPage.js @@ -84,22 +84,18 @@ chrome.runtime.onInstalled.addListener(function (details) { // only fire up notification sequence when one of the major version numbers changed if (currentVersionArr[0] > previousVersionArr[0] || currentVersionArr[1] > previousVersionArr[1]) { - chrome.storage.local.get('update_notify', function (result) { - if (result.update_notify === 'undefined' || result.update_notify) { - var manifest = chrome.runtime.getManifest(); - var options = { - priority: 0, - type: 'basic', - title: manifest.name, - message: chrome.i18n.getMessage('notifications_app_just_updated_to_version', [getManifestVersion(manifest)]), - iconUrl: '/images/icon_128.png', - buttons: [{'title': chrome.i18n.getMessage('notifications_click_here_to_start_app')}] - }; + var manifest = chrome.runtime.getManifest(); + var options = { + priority: 0, + type: 'basic', + title: manifest.name, + message: chrome.i18n.getMessage('notifications_app_just_updated_to_version', [getManifestVersion(manifest)]), + iconUrl: '/images/icon_128.png', + buttons: [{'title': chrome.i18n.getMessage('notifications_click_here_to_start_app')}] + }; - chrome.notifications.create('baseflight_update', options, function (notificationId) { - // empty - }); - } + chrome.notifications.create('baseflight_update', options, function (notificationId) { + // empty }); } } diff --git a/gulpfile.js b/gulpfile.js index e5a115e7..6cb998f7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -181,6 +181,7 @@ gulp.task('dist', ['clean-dist'], function () { './js/RateCurve.js', './js/Features.js', './js/Beepers.js', + './js/release_checker.js', './tabs/adjustments.js', './tabs/auxiliary.js', './tabs/cli.js', diff --git a/js/gui.js b/js/gui.js index 78606af2..88a72d01 100644 --- a/js/gui.js +++ b/js/gui.js @@ -325,8 +325,7 @@ GUI_control.prototype.show_modal = function (title, message) { var popup = new jBox('Modal', { title: title, content: message, - closeButton: 'title', - closeOnClick: 'box' + closeButton: 'title' }); popup.open(); diff --git a/js/release_checker.js b/js/release_checker.js new file mode 100644 index 00000000..6e2076a8 --- /dev/null +++ b/js/release_checker.js @@ -0,0 +1,58 @@ + 'use strict;' + +var ReleaseChecker = function (releaseName, releaseUrl) { + var self = this; + + self._releaseName = releaseName; + self._releaseDataTag = `${self._releaseName}ReleaseData`; + self._releaseLastUpdateTag = `${self._releaseName}ReleaseLastUpdate` + self._releaseUrl = releaseUrl; + + +} + +ReleaseChecker.prototype.loadReleaseData = function (processFunction) { + var self = this; + chrome.storage.local.get([self._releaseLastUpdateTag, self._releaseDataTag], function (result) { + var releaseDataTimestamp = $.now(); + var cacheReleaseData = result[self._releaseDataTag]; + var cachedReleaseLastUpdate = result[self._releaseLastUpdateTag]; + if (!cacheReleaseData || !cachedReleaseLastUpdate || releaseDataTimestamp - cachedReleaseLastUpdate > 3600 * 1000) { + $.get(self._releaseUrl, function (releaseData) { + GUI.log(`Loaded release information for ${self._releaseName} from GitHub.`); + + var data = {}; + data[self._releaseDataTag] = releaseData + data[self._releaseLastUpdateTag] = releaseDataTimestamp + chrome.storage.local.set(data, function () {}); + + self._processReleaseData(releaseData, processFunction); + }).fail(function (data) { + var message = ''; + if (data['responseJSON']) { + message = data['responseJSON'].message; + } + GUI.log(`GitHub query for ${self._releaseName} releases failed, using cached information. Reason: ${message}`); + + self._processReleaseData(cacheReleaseData, processFunction); + }); + } else { + if (cacheReleaseData) { + GUI.log(`Using cached release information for ${self._releaseName} releases.`); + } + + self._processReleaseData(cacheReleaseData, processFunction); + } + }); +} + + +ReleaseChecker.prototype._processReleaseData = function (releaseData, processFunction) { + if (releaseData) { + processFunction(releaseData); + } else { + GUI.log(`No release information available for ${self._releaseName}.`); + + processFunction(); + } +} diff --git a/main.html b/main.html index ef68f325..b859ddce 100755 --- a/main.html +++ b/main.html @@ -73,6 +73,7 @@ + diff --git a/main.js b/main.js index 01f40338..e0a73c3c 100644 --- a/main.js +++ b/main.js @@ -28,35 +28,7 @@ $(document).ready(function () { break; } - // check for newer releases online to inform people in case they are running an old release - - chrome.storage.local.get(['lastVersionChecked', 'lastVersionAvailableOnline'], function (result) { - if (typeof result.lastVersionChecked === undefined || ($.now() - result.lastVersionChecked) > 3600 * 1000) { - try { - var url = 'https://api.github.com/repos/betaflight/betaflight-configurator/tags'; - $.get(url).done(function (data) { - var versions = data.sort(function (v1, v2) { - try { - return semver.compare(v2.name, v1.name); - } catch (e) { - return false; - } - }); - chrome.storage.local.set({ - 'lastVersionChecked': $.now(), - 'lastVersionAvailableOnline': versions[0].name - }, function (result) { - console.log("Latest version available online: " + versions[0].name); - }); - notifyOutdatedVersion(versions[0].name); - }); - } catch (e) { - // Just to catch and supress warnings if no internet connection is available - } - } else if (result.lastVersionAvailableOnline) { - notifyOutdatedVersion(result.lastVersionAvailableOnline); - } - }); + checkForConfiguratorUpdates(); chrome.storage.local.get('logopen', function (result) { if (result.logopen) { @@ -212,19 +184,6 @@ $(document).ready(function () { // translate to user-selected language localize(); - // if notifications are enabled, or wasn't set, check the notifications checkbox - chrome.storage.local.get('update_notify', function (result) { - if (typeof result.update_notify === 'undefined' || result.update_notify) { - $('div.notifications input').prop('checked', true); - } - - $('div.notifications input').change(function () { - var check = $(this).is(':checked'); - - chrome.storage.local.set({'update_notify': check}); - }); - }); - chrome.storage.local.get('permanentExpertMode', function (result) { if (result.permanentExpertMode) { $('div.permanentExpertMode input').prop('checked', true); @@ -243,6 +202,21 @@ $(document).ready(function () { }).change(); }); + chrome.storage.local.get('checkForConfiguratorUnstableVersions', function (result) { + $('div.checkForConfiguratorUnstableVersions input').change(function () { + var checked = $(this).is(':checked'); + + chrome.storage.local.set({'checkForConfiguratorUnstableVersions': checked}); + + $('input[name="checkForConfiguratorUnstableVersions"]').prop('checked', checked).change(); + checkForConfiguratorUpdates(); + }); + + if (result.checkForConfiguratorUnstableVersions) { + $('div.checkForConfiguratorUnstableVersions input').prop('checked', true); + } + }); + function close_and_cleanup(e) { if (e.type == 'click' && !$.contains($('div#options-window')[0], e.target) || e.type == 'keyup' && e.keyCode == 27) { $(document).unbind('click keyup', close_and_cleanup); @@ -377,10 +351,36 @@ $(document).ready(function () { }); }); -function notifyOutdatedVersion(version) { - if (semver.lt(getManifestVersion(), version)) { - GUI.log('You are using an old version of ' + chrome.runtime.getManifest().name + '. Version ' + version + ' is available online with possible improvements and fixes.'); - } +function checkForConfiguratorUpdates() { + var releaseChecker = new ReleaseChecker('configurator', 'https://api.github.com/repos/betaflight/betaflight-configurator/releases'); + + releaseChecker.loadReleaseData(notifyOutdatedVersion); +} + +function notifyOutdatedVersion(releaseData) { + chrome.storage.local.get('checkForConfiguratorUnstableVersions', function (result) { + var showUnstableReleases = false; + if (result.checkForConfiguratorUnstableVersions) { + showUnstableReleases = true; + } + var versions = releaseData.filter(function (version) { + var semVerVersion = semver.parse(version.tag_name); + if (semVerVersion && (showUnstableReleases || semVerVersion.prerelease.length === 0)) { + return version; + } + }).sort(function (v1, v2) { + try { + return semver.compare(v2.tag_name, v1.tag_name); + } catch (e) { + return false; + } + }); + + if (versions.length > 0 && semver.lt(getManifestVersion(), versions[0].tag_name)) { + GUI.show_modal(chrome.i18n.getMessage('noticeTitle'), chrome.i18n.getMessage('configuratorUpdateNotice', [versions[0].tag_name, versions[0].html_url])); + GUI.log(chrome.i18n.getMessage('configuratorUpdateNotice', [versions[0].tag_name, versions[0].html_url])); + } + }); } function update_packet_error(caller) { diff --git a/tabs/firmware_flasher.js b/tabs/firmware_flasher.js index 41aa165e..7e01c585 100755 --- a/tabs/firmware_flasher.js +++ b/tabs/firmware_flasher.js @@ -2,6 +2,7 @@ TABS.firmware_flasher = { releases: null, + releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases') }; TABS.firmware_flasher.initialize = function (callback) { @@ -30,144 +31,108 @@ TABS.firmware_flasher.initialize = function (callback) { } function buildBoardOptions(releaseData) { - var boards_e = $('select[name="board"]').empty(); - var showDevReleases = ($('input.show_development_releases').is(':checked')); - boards_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectBoard')))); - - var versions_e = $('select[name="firmware_version"]').empty(); - versions_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); - - var releases = {}; - var sortedTargets = []; - var unsortedTargets = []; - releaseData.forEach(function(release){ - release.assets.forEach(function(asset){ - var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/; - var match = targetFromFilenameExpression.exec(asset.name); - - if ((!showDevReleases && release.prerelease) || !match) { - return; - } - var target = match[2]; - if($.inArray(target, unsortedTargets) == -1) { - unsortedTargets.push(target); - } - }); - sortedTargets = unsortedTargets.sort(); - }); - sortedTargets.forEach(function(release) { - releases[release] = []; - }); - - releaseData.forEach(function(release){ - var versionFromTagExpression = /v?(.*)/; - var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name); - var version = matchVersionFromTag[1]; - - release.assets.forEach(function(asset){ - var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/; - var match = targetFromFilenameExpression.exec(asset.name); - - if ((!showDevReleases && release.prerelease) || !match) { - return; - } - - var target = match[2]; - var format = match[4]; - - if (format != 'hex') { - return; - } - - var date = new Date(release.published_at); - var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0"+(date.getMonth()+1)).slice(-2) + "-" + - date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2); - - var descriptor = { - "releaseUrl": release.html_url, - "name" : version, - "version" : version, - "url" : asset.browser_download_url, - "file" : asset.name, - "target" : target, - "date" : formattedDate, - "notes" : release.body, - "status" : release.prerelease ? "release-candidate" : "stable" - }; - releases[target].push(descriptor); - }); - }); - var selectTargets = []; - Object.keys(releases) - .sort() - .forEach(function(target, i) { - var descriptors = releases[target]; - descriptors.forEach(function(descriptor){ - if($.inArray(target, selectTargets) == -1) { - selectTargets.push(target); - var select_e = - $("".format( - descriptor.target - )).data('summary', descriptor); - boards_e.append(select_e); - } - }); - }); - TABS.firmware_flasher.releases = releases; - chrome.storage.local.get('selected_board', function (result) { - if (result.selected_board) { - $('select[name="board"]').val(result.selected_board); - $('select[name="board"]').trigger("change"); - } - }); - }; - - function loadReleaseData() { - chrome.storage.local.get(['releaseDataLastUpdate', 'releaseData'], function (result) { - var releaseDataTimestamp = $.now(); - if (!result.releaseData || !result.releaseDataLastUpdate || releaseDataTimestamp - result.releaseDataLastUpdate > 3600 * 1000) { - $.get('https://api.github.com/repos/betaflight/betaflight/releases', function (releaseData) { - GUI.log("Loaded release information from GitHub."); - - chrome.storage.local.set({'releaseDataLastUpdate': releaseDataTimestamp, 'releaseData': releaseData}, function () {}); - - processReleaseData(releaseData); - }).fail(function (data){ - processReleaseData(result.releaseData); - - var message = ''; - if (data["responseJSON"]) { - message = data["responseJSON"].message; - } - GUI.log("GitHub query failed: {0}".format(message)); - }); - } else { - if (result.releaseData) { - GUI.log("Using cached release information."); - } - - processReleaseData(result.releaseData); - } - }); - } - - function processReleaseData(releaseData) { - if (releaseData) { - buildBoardOptions(releaseData); - } else { - GUI.log("No release information available."); - + if (!releaseData) { $('select[name="board"]').empty().append(''); $('select[name="firmware_version"]').empty().append(''); + } else { + var boards_e = $('select[name="board"]').empty(); + var showDevReleases = ($('input.show_development_releases').is(':checked')); + boards_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectBoard')))); + + var versions_e = $('select[name="firmware_version"]').empty(); + versions_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); + + var releases = {}; + var sortedTargets = []; + var unsortedTargets = []; + releaseData.forEach(function(release){ + release.assets.forEach(function(asset){ + var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/; + var match = targetFromFilenameExpression.exec(asset.name); + + if ((!showDevReleases && release.prerelease) || !match) { + return; + } + var target = match[2]; + if($.inArray(target, unsortedTargets) == -1) { + unsortedTargets.push(target); + } + }); + sortedTargets = unsortedTargets.sort(); + }); + sortedTargets.forEach(function(release) { + releases[release] = []; + }); + + releaseData.forEach(function(release){ + var versionFromTagExpression = /v?(.*)/; + var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name); + var version = matchVersionFromTag[1]; + + release.assets.forEach(function(asset){ + var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/; + var match = targetFromFilenameExpression.exec(asset.name); + + if ((!showDevReleases && release.prerelease) || !match) { + return; + } + + var target = match[2]; + var format = match[4]; + + if (format != 'hex') { + return; + } + + var date = new Date(release.published_at); + var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0"+(date.getMonth()+1)).slice(-2) + "-" + date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2); + + var descriptor = { + "releaseUrl": release.html_url, + "name" : version, + "version" : version, + "url" : asset.browser_download_url, + "file" : asset.name, + "target" : target, + "date" : formattedDate, + "notes" : release.body, + "status" : release.prerelease ? "release-candidate" : "stable" + }; + releases[target].push(descriptor); + }); + }); + var selectTargets = []; + Object.keys(releases) + .sort() + .forEach(function(target, i) { + var descriptors = releases[target]; + descriptors.forEach(function(descriptor){ + if($.inArray(target, selectTargets) == -1) { + selectTargets.push(target); + var select_e = + $("".format( + descriptor.target + )).data('summary', descriptor); + boards_e.append(select_e); + } + }); + }); + TABS.firmware_flasher.releases = releases; + chrome.storage.local.get('selected_board', function (result) { + if (result.selected_board) { + $('select[name="board"]').val(result.selected_board); + $('select[name="board"]').trigger("change"); + } + }); } - } + }; // translate to user-selected language localize(); // bind events $('input.show_development_releases').click(function () { - loadReleaseData(); + self.releaseChecker.loadReleaseData(buildBoardOptions); }); $('select[name="board"]').change(function() { @@ -518,7 +483,7 @@ TABS.firmware_flasher.initialize = function (callback) { $('input.show_development_releases').prop('checked', false); } - loadReleaseData(); + self.releaseChecker.loadReleaseData(buildBoardOptions); $('input.show_development_releases').change(function () { chrome.storage.local.set({'show_development_releases': $(this).is(':checked')}); diff --git a/tabs/options.html b/tabs/options.html index d99c3b5b..2a926365 100644 --- a/tabs/options.html +++ b/tabs/options.html @@ -1,6 +1,6 @@ -
- -
+
+ +