diff --git a/locales/en/messages.json b/locales/en/messages.json index e6b9710981..80ae745340 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -7408,6 +7408,14 @@ "showNotifications": { "message": "Show notifications for long operations" }, + "notificationsDeniedTitle": { + "message": "Notifications blocked", + "description": "Title when Notifications has no or denied permissions" + }, + "notificationsDenied": { + "message": "Notifications are blocked. Please enable them in your browser settings. Otherwise, you will not receive notifications about long operations. If you are using Chrome, you can enable notifications by clicking on the lock icon in the address bar and selecting 'Site settings'.", + "description": "Message when Notifications has no or denied permissions" + }, "flashEraseDoneNotification": { "message": "Dataflash erase has been completed", "description": "Notification message when flash erase is done" diff --git a/src/js/main.js b/src/js/main.js index 132e951118..e6826222a1 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -86,7 +86,9 @@ function appReady() { initializeSerialBackend(); }); - if (getConfig('showNotifications') && NotificationManager.checkPermission() === 'default') { + + const showNotifications = getConfig('showNotifications', false).showNotifications; + if (showNotifications && NotificationManager.checkPermission() === 'default') { NotificationManager.requestPermission(); } } diff --git a/src/js/protocols/webstm32.js b/src/js/protocols/webstm32.js index ece1b124a0..2ed8348e3b 100644 --- a/src/js/protocols/webstm32.js +++ b/src/js/protocols/webstm32.js @@ -805,7 +805,7 @@ class STM32Protocol { TABS.firmware_flasher.flashingMessage(i18n.getMessage('stm32ProgrammingSuccessful'), TABS.firmware_flasher.FLASH_MESSAGE_TYPES.VALID); // Show notification - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('programmingSuccessfulNotification'), icon: "/images/pwa/favicon.ico"}); } @@ -817,7 +817,7 @@ class STM32Protocol { TABS.firmware_flasher.flashingMessage(i18n.getMessage('stm32ProgrammingFailed'), TABS.firmware_flasher.FLASH_MESSAGE_TYPES.INVALID); // Show notification - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('programmingFailedNotification'), icon: "/images/pwa/favicon.ico"}); } diff --git a/src/js/protocols/webusbdfu.js b/src/js/protocols/webusbdfu.js index 7db8bcdc37..e7ecb9d728 100644 --- a/src/js/protocols/webusbdfu.js +++ b/src/js/protocols/webusbdfu.js @@ -1067,7 +1067,7 @@ class WEBUSBDFU_protocol extends EventTarget { TABS.firmware_flasher.flashingMessage(i18n.getMessage('stm32ProgrammingSuccessful'), TABS.firmware_flasher.FLASH_MESSAGE_TYPES.VALID); // Show notification - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('programmingSuccessfulNotification'), icon: "/images/pwa/favicon.ico"}); } @@ -1079,7 +1079,7 @@ class WEBUSBDFU_protocol extends EventTarget { TABS.firmware_flasher.flashingMessage(i18n.getMessage('stm32ProgrammingFailed'), TABS.firmware_flasher.FLASH_MESSAGE_TYPES.INVALID); // Show notification - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('programmingFailedNotification'), icon: "/images/pwa/favicon.ico"}); } diff --git a/src/js/tabs/onboard_logging.js b/src/js/tabs/onboard_logging.js index 6d24316ef3..be228aa7a3 100644 --- a/src/js/tabs/onboard_logging.js +++ b/src/js/tabs/onboard_logging.js @@ -383,7 +383,7 @@ onboard_logging.initialize = function (callback) { $(".dataflash-saving").addClass("done"); - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('flashDownloadDoneNotification'), icon: "/images/pwa/favicon.ico"}); } } @@ -504,7 +504,7 @@ onboard_logging.initialize = function (callback) { if (CONFIGURATOR.connectionValid && !eraseCancelled) { if (FC.DATAFLASH.ready) { $(".dataflash-confirm-erase")[0].close(); - if (getConfig('showNotifications')) { + if (getConfig('showNotifications').showNotifications) { NotificationManager.showNotification("Betaflight Configurator", {body: i18n.getMessage('flashEraseDoneNotification'), icon: "/images/pwa/favicon.ico"}); } } else { diff --git a/src/js/tabs/options.js b/src/js/tabs/options.js index 67f1800020..dedde3c0df 100644 --- a/src/js/tabs/options.js +++ b/src/js/tabs/options.js @@ -7,7 +7,7 @@ import DarkTheme, { setDarkTheme } from '../DarkTheme'; import { checkForConfiguratorUpdates } from '../utils/checkForConfiguratorUpdates'; import { checkSetupAnalytics } from '../Analytics'; import $ from 'jquery'; -import CONFIGURATOR from '../data_storage'; +import NotificationManager from '../utils/notifications'; const options = {}; options.initialize = function (callback) { @@ -186,8 +186,44 @@ options.initShowNotifications = function () { const result = getConfig("showNotifications"); $("div.showNotifications input") .prop("checked", !!result.showNotifications) - .change(function () { - setConfig({ showNotifications: $(this).is(":checked") }); + .on('change', function () { + const element = $(this); + const enabled = element.is(':checked'); + + if (enabled) { + const informationDialog = { + title : i18n.getMessage("notificationsDeniedTitle"), + text: i18n.getMessage("notificationsDenied"), + buttonConfirmText: i18n.getMessage("OK"), + }; + + switch (NotificationManager.checkPermission()) { + case 'granted': + setConfig({ showNotifications: enabled }); + break; + case 'denied': + // disable notifications if permission is denied + GUI.showInformationDialog(informationDialog); + element.prop('checked', false); + break; + case 'default': + // need to request permission first before enabling notifications + element.prop('checked', false); + NotificationManager.requestPermission().then((permission) => { + if (permission === 'granted') { + // enable notifications if permission is granted + setConfig({ showNotifications: enabled }); + // trigger change event to update the switchery + element.prop('checked', true).trigger('change'); + } else { + GUI.showInformationDialog(informationDialog); + } + }); + } + + } + + setConfig({ showNotifications: element.is(":checked") }); }) .change(); };