diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index cdced6df59..102643dd6a 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -27,6 +27,7 @@ import {IntegrationManagers} from "../integrations/IntegrationManagers"; import {ModalManager} from "../Modal"; import SettingsStore from "../settings/SettingsStore"; import {ActiveRoomObserver} from "../ActiveRoomObserver"; +import {Notifier} from "../Notifier"; declare global { interface Window { @@ -47,6 +48,7 @@ declare global { mxIntegrationManagers: typeof IntegrationManagers; singletonModalManager: ModalManager; mxSettingsStore: SettingsStore; + mxNotifier: typeof Notifier; } // workaround for https://github.com/microsoft/TypeScript/issues/30933 @@ -79,4 +81,8 @@ declare global { interface PromiseConstructor { allSettled(promises: Promise[]): Promise | ISettledRejected>>; } + + interface HTMLAudioElement { + type?: string; + } } diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index acf72a986c..1d28aa7f9a 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -155,6 +155,8 @@ export default abstract class BasePlatform { loudNotification(ev: Event, room: Object) { } + clearNotification(notif: Notification) { + } /** * Returns a promise that resolves to a string representing the current version of the application. diff --git a/src/Notifier.js b/src/Notifier.ts similarity index 91% rename from src/Notifier.js rename to src/Notifier.ts index 2ed302267e..473de6c161 100644 --- a/src/Notifier.js +++ b/src/Notifier.ts @@ -17,6 +17,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; + import { MatrixClientPeg } from './MatrixClientPeg'; import SdkConfig from './SdkConfig'; import PlatformPeg from './PlatformPeg'; @@ -28,9 +31,7 @@ import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; import SettingsStore from "./settings/SettingsStore"; -import { - hideToast as hideNotificationsToast, -} from "./toasts/DesktopNotificationsToast"; +import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast"; import {SettingLevel} from "./settings/SettingLevel"; /* @@ -55,7 +56,7 @@ const typehandlers = { }, }; -const Notifier = { +export const Notifier = { notifsByRoom: {}, // A list of event IDs that we've received but need to wait until @@ -63,14 +64,14 @@ const Notifier = { // or not pendingEncryptedEventIds: [], - notificationMessageForEvent: function(ev) { + notificationMessageForEvent: function(ev: MatrixEvent) { if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) { return typehandlers[ev.getContent().msgtype](ev); } return TextForEvent.textForEvent(ev); }, - _displayPopupNotification: function(ev, room) { + _displayPopupNotification: function(ev: MatrixEvent, room: Room) { const plaf = PlatformPeg.get(); if (!plaf) { return; @@ -125,7 +126,7 @@ const Notifier = { } }, - getSoundForRoom: function(roomId) { + getSoundForRoom: function(roomId: string) { // We do no caching here because the SDK caches setting // and the browser will cache the sound. const content = SettingsStore.getValue("notificationSound", roomId); @@ -153,12 +154,13 @@ const Notifier = { }; }, - _playAudioNotification: async function(ev, room) { + _playAudioNotification: async function(ev: MatrixEvent, room: Room) { const sound = this.getSoundForRoom(room.roomId); console.log(`Got sound ${sound && sound.name || "default"} for ${room.roomId}`); try { - const selector = document.querySelector(sound ? `audio[src='${sound.url}']` : "#messageAudio"); + const selector = + document.querySelector(sound ? `audio[src='${sound.url}']` : "#messageAudio"); let audioElement = selector; if (!selector) { if (!sound) { @@ -207,7 +209,7 @@ const Notifier = { return plaf && plaf.supportsNotifications(); }, - setEnabled: function(enable, callback) { + setEnabled: function(enable: boolean, callback?: () => void) { const plaf = PlatformPeg.get(); if (!plaf) return; @@ -277,10 +279,11 @@ const Notifier = { }, isAudioEnabled: function() { - return this.isEnabled() && SettingsStore.getValue("audioNotificationsEnabled"); + // We don't route Audio via the HTML Notifications API so it is possible regardless of other things + return SettingsStore.getValue("audioNotificationsEnabled"); }, - setToolbarHidden: function(hidden, persistent = true) { + setToolbarHidden: function(hidden: boolean, persistent = true) { this.toolbarHidden = hidden; Analytics.trackEvent('Notifier', 'Set Toolbar Hidden', hidden); @@ -289,7 +292,7 @@ const Notifier = { // update the info to localStorage for persistent settings if (persistent && global.localStorage) { - global.localStorage.setItem("notifications_hidden", hidden); + global.localStorage.setItem("notifications_hidden", String(hidden)); } }, @@ -312,7 +315,7 @@ const Notifier = { return this.toolbarHidden; }, - onSyncStateChange: function(state) { + onSyncStateChange: function(state: string) { if (state === "SYNCING") { this.isSyncing = true; } else if (state === "STOPPED" || state === "ERROR") { @@ -320,7 +323,7 @@ const Notifier = { } }, - onEvent: function(ev) { + onEvent: function(ev: MatrixEvent) { if (!this.isSyncing) return; // don't alert for any messages initially if (ev.sender && ev.sender.userId === MatrixClientPeg.get().credentials.userId) return; @@ -338,7 +341,7 @@ const Notifier = { this._evaluateEvent(ev); }, - onEventDecrypted: function(ev) { + onEventDecrypted: function(ev: MatrixEvent) { // 'decrypted' means the decryption process has finished: it may have failed, // in which case it might decrypt soon if the keys arrive if (ev.isDecryptionFailure()) return; @@ -350,7 +353,7 @@ const Notifier = { this._evaluateEvent(ev); }, - onRoomReceipt: function(ev, room) { + onRoomReceipt: function(ev: MatrixEvent, room: Room) { if (room.getUnreadNotificationCount() === 0) { // ideally we would clear each notification when it was read, // but we have no way, given a read receipt, to know whether @@ -383,8 +386,8 @@ const Notifier = { }, }; -if (!global.mxNotifier) { - global.mxNotifier = Notifier; +if (!window.mxNotifier) { + window.mxNotifier = Notifier; } -export default global.mxNotifier; +export default window.mxNotifier; diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 49d060a6b2..714d80f983 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -19,7 +19,6 @@ import { MatrixClient } from 'matrix-js-sdk/src/client'; import { _td } from '../languageHandler'; import { - AudioNotificationsEnabledController, NotificationBodyEnabledController, NotificationsEnabledController, } from "./controllers/NotificationControllers"; @@ -460,7 +459,6 @@ export const SETTINGS: {[setting: string]: ISetting} = { "audioNotificationsEnabled": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: true, - controller: new AudioNotificationsEnabledController(), }, "enableWidgetScreenshots": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, diff --git a/src/settings/controllers/NotificationControllers.ts b/src/settings/controllers/NotificationControllers.ts index fc50af6096..bf5971d02e 100644 --- a/src/settings/controllers/NotificationControllers.ts +++ b/src/settings/controllers/NotificationControllers.ts @@ -79,12 +79,3 @@ export class NotificationBodyEnabledController extends SettingController { return calculatedValue; } } - -export class AudioNotificationsEnabledController extends SettingController { - public getValueOverride(level: SettingLevel, roomId: string, calculatedValue: any): any { - if (!getNotifier().isPossible()) return false; - - // Note: Audio notifications are *not* enabled by default. - return calculatedValue; - } -}