diff --git a/public/sound/notification.ogg b/public/sound/notification.ogg
new file mode 100755
index 0000000..93b3a01
Binary files /dev/null and b/public/sound/notification.ogg differ
diff --git a/src/app/organisms/settings/Settings.jsx b/src/app/organisms/settings/Settings.jsx
index f9cc631..87f2766 100644
--- a/src/app/organisms/settings/Settings.jsx
+++ b/src/app/organisms/settings/Settings.jsx
@@ -7,7 +7,7 @@ import cons from '../../../client/state/cons';
import settings from '../../../client/state/settings';
import {
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
- toggleNotifications,
+ toggleNotifications, toggleNotificationSounds,
} from '../../../client/action/settings';
import logout from '../../../client/action/logout';
import { usePermission } from '../../hooks/usePermission';
@@ -158,6 +158,16 @@ function NotificationsSection() {
options={renderOptions()}
content={Show notifications when new messages arrive.}
/>
+ { toggleNotificationSounds(); updateState({}); }}
+ />
+ )}
+ content={Play a sound when new messages arrive.}
+ />
);
}
@@ -200,7 +210,7 @@ function AboutSection() {
diff --git a/src/client/action/settings.js b/src/client/action/settings.js
index 1192341..7b539c8 100644
--- a/src/client/action/settings.js
+++ b/src/client/action/settings.js
@@ -36,3 +36,9 @@ export function toggleNotifications() {
type: cons.actions.settings.TOGGLE_NOTIFICATIONS,
});
}
+
+export function toggleNotificationSounds() {
+ appDispatcher.dispatch({
+ type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
+ });
+}
diff --git a/src/client/state/Notifications.js b/src/client/state/Notifications.js
index 11fd665..7bcd950 100644
--- a/src/client/state/Notifications.js
+++ b/src/client/state/Notifications.js
@@ -6,6 +6,8 @@ import cons from './cons';
import navigation from './navigation';
import settings from './settings';
+import NotificationSound from '../../../public/sound/notification.ogg';
+
function isNotifEvent(mEvent) {
const eType = mEvent.getType();
if (!cons.supportEventTypes.includes(eType)) return false;
@@ -185,7 +187,7 @@ class Notifications extends EventEmitter {
}
async _displayPopupNoti(mEvent, room) {
- if (!settings.showNotifications) return;
+ if (!settings.showNotifications && !settings.isNotificationSounds) return;
const actions = this.matrixClient.getPushActionsForEvent(mEvent);
if (!actions?.notify) return;
@@ -196,28 +198,43 @@ class Notifications extends EventEmitter {
await mEvent.attemptDecryption(this.matrixClient.crypto);
}
- let title;
- if (!mEvent.sender || room.name === mEvent.sender.name) {
- title = room.name;
- } else if (mEvent.sender) {
- title = `${mEvent.sender.name} (${room.name})`;
+ if (settings.showNotifications) {
+ let title;
+ if (!mEvent.sender || room.name === mEvent.sender.name) {
+ title = room.name;
+ } else if (mEvent.sender) {
+ title = `${mEvent.sender.name} (${room.name})`;
+ }
+
+ const iconSize = 36;
+ const icon = await renderAvatar({
+ text: mEvent.sender.name,
+ bgColor: cssColorMXID(mEvent.getSender()),
+ imageSrc: mEvent.sender?.getAvatarUrl(this.matrixClient.baseUrl, iconSize, iconSize, 'crop'),
+ size: iconSize,
+ borderRadius: 8,
+ scale: 8,
+ });
+
+ const noti = new window.Notification(title, {
+ body: mEvent.getContent().body,
+ icon,
+ silent: settings.isNotificationSounds,
+ });
+ if (settings.isNotificationSounds) {
+ noti.onshow = () => this._playNotiSounds();
+ }
+ noti.onclick = () => selectRoom(room.roomId, mEvent.getId());
+ } else {
+ this._playNotiSounds();
}
+ }
- const iconSize = 36;
- const icon = await renderAvatar({
- text: mEvent.sender.name,
- bgColor: cssColorMXID(mEvent.getSender()),
- imageSrc: mEvent.sender?.getAvatarUrl(this.matrixClient.baseUrl, iconSize, iconSize, 'crop'),
- size: iconSize,
- borderRadius: 8,
- scale: 8,
- });
-
- const noti = new window.Notification(title, {
- body: mEvent.getContent().body,
- icon,
- });
- noti.onclick = () => selectRoom(room.roomId, mEvent.getId());
+ _playNotiSounds() {
+ if (!this._notiAudio) {
+ this._notiAudio = new Audio(NotificationSound);
+ }
+ this._notiAudio.play();
}
_listenEvents() {
diff --git a/src/client/state/cons.js b/src/client/state/cons.js
index 6ec6c27..862bf5c 100644
--- a/src/client/state/cons.js
+++ b/src/client/state/cons.js
@@ -67,6 +67,7 @@ const cons = {
TOGGLE_MEMBERSHIP_EVENT: 'TOGGLE_MEMBERSHIP_EVENT',
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
+ TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
},
},
events: {
@@ -135,6 +136,7 @@ const cons = {
MEMBERSHIP_EVENTS_TOGGLED: 'MEMBERSHIP_EVENTS_TOGGLED',
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
+ NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
},
},
};
diff --git a/src/client/state/settings.js b/src/client/state/settings.js
index 25d0b2d..0f476ef 100644
--- a/src/client/state/settings.js
+++ b/src/client/state/settings.js
@@ -29,6 +29,7 @@ class Settings extends EventEmitter {
this.hideMembershipEvents = this.getHideMembershipEvents();
this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
this._showNotifications = this.getShowNotifications();
+ this.isNotificationSounds = this.getIsNotificationSounds();
this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
}
@@ -125,6 +126,15 @@ class Settings extends EventEmitter {
return settings.showNotifications;
}
+ getIsNotificationSounds() {
+ if (typeof this.isNotificationSounds === 'boolean') return this.isNotificationSounds;
+
+ const settings = getSettings();
+ if (settings === null) return true;
+ if (typeof settings.isNotificationSounds === 'undefined') return true;
+ return settings.isNotificationSounds;
+ }
+
setter(action) {
const actions = {
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
@@ -164,6 +174,11 @@ class Settings extends EventEmitter {
setSettings('showNotifications', this._showNotifications);
this.emit(cons.events.settings.NOTIFICATIONS_TOGGLED, this._showNotifications);
},
+ [cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS]: () => {
+ this.isNotificationSounds = !this.isNotificationSounds;
+ setSettings('isNotificationSounds', this.isNotificationSounds);
+ this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
+ },
};
actions[action.type]?.();
diff --git a/webpack.common.js b/webpack.common.js
index dd45a06..9ff58da 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -39,7 +39,7 @@ module.exports = {
use: ['html-loader'],
},
{
- test: /\.(png|jpe?g|gif|otf|ttf|woff|woff2)$/,
+ test: /\.(png|jpe?g|gif|otf|ttf|woff|woff2|ogg)$/,
type: 'asset/resource',
},
{