UX: reduces idle time to 0 on chat (#27158)
We consider that you should always receive a notification sound when someone speaks directly with you in chat. This commit also refactors the way we play audio in chat to make it simpler and throttle it to 3 seconds. We also added a safeguard to ensure we won't play sounds for old messages, this case can happen when message bus is catching up the backlog (eg: in an inactive tab for example).
This commit is contained in:
parent
c39a4de139
commit
d5066336ec
|
@ -139,23 +139,23 @@ function setupNotifications(appEvents) {
|
|||
}
|
||||
|
||||
function resetIdle() {
|
||||
lastAction = Date.now();
|
||||
lastAction = Date.now() - 10;
|
||||
}
|
||||
|
||||
function isIdle() {
|
||||
return lastAction + idleThresholdTime < Date.now();
|
||||
function isIdle(idleThreshold = idleThresholdTime) {
|
||||
return lastAction + idleThreshold <= Date.now();
|
||||
}
|
||||
|
||||
function setLastAction(time) {
|
||||
lastAction = time;
|
||||
}
|
||||
|
||||
function canUserReceiveNotifications(user) {
|
||||
function canUserReceiveNotifications(user, options = { idleThresholdTime }) {
|
||||
if (!primaryTab) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isIdle()) {
|
||||
if (!isIdle(options.idleThresholdTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,12 @@ export default {
|
|||
name: "chat-audio",
|
||||
|
||||
initialize(container) {
|
||||
const chatService = container.lookup("service:chat");
|
||||
const chat = container.lookup("service:chat");
|
||||
|
||||
if (!chatService.userCanChat) {
|
||||
if (!chat.userCanChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
const chatAudioManager = container.lookup("service:chat-audio-manager");
|
||||
chatAudioManager.setup();
|
||||
|
||||
withPluginApi("0.12.1", (api) => {
|
||||
api.registerDesktopNotificationHandler((data, siteSettings, user) => {
|
||||
if (user.isInDoNotDisturb()) {
|
||||
|
@ -28,6 +25,9 @@ export default {
|
|||
}
|
||||
|
||||
if (CHAT_NOTIFICATION_TYPES.includes(data.notification_type)) {
|
||||
const chatAudioManager = container.lookup(
|
||||
"service:chat-audio-manager"
|
||||
);
|
||||
chatAudioManager.play(user.chat_sound);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,50 +9,26 @@ export const CHAT_SOUNDS = {
|
|||
|
||||
const DEFAULT_SOUND_NAME = "bell";
|
||||
|
||||
const createAudioCache = (sources) => {
|
||||
const audio = new Audio();
|
||||
audio.pause();
|
||||
sources.forEach(({ type, src }) => {
|
||||
const source = document.createElement("source");
|
||||
source.type = type;
|
||||
source.src = getURLWithCDN(src);
|
||||
audio.appendChild(source);
|
||||
});
|
||||
return audio;
|
||||
};
|
||||
const THROTTLE_TIME = 3000; // 3 seconds
|
||||
|
||||
export default class ChatAudioManager extends Service {
|
||||
_audioCache = {};
|
||||
canPlay = true;
|
||||
|
||||
setup() {
|
||||
Object.keys(CHAT_SOUNDS).forEach((soundName) => {
|
||||
this._audioCache[soundName] = createAudioCache(CHAT_SOUNDS[soundName]);
|
||||
});
|
||||
async play(name) {
|
||||
if (this.canPlay) {
|
||||
await this.#tryPlay(name);
|
||||
this.canPlay = false;
|
||||
setTimeout(() => {
|
||||
this.canPlay = true;
|
||||
}, THROTTLE_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
super.willDestroy(...arguments);
|
||||
|
||||
this._audioCache = {};
|
||||
}
|
||||
|
||||
async play(soundName) {
|
||||
if (isTesting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const audio =
|
||||
this._audioCache[soundName] || this._audioCache[DEFAULT_SOUND_NAME];
|
||||
|
||||
if (!audio.paused) {
|
||||
audio.pause();
|
||||
if (typeof audio.fastSeek === "function") {
|
||||
audio.fastSeek(0);
|
||||
} else {
|
||||
audio.currentTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
async #tryPlay(name) {
|
||||
const src = getURLWithCDN(
|
||||
(CHAT_SOUNDS[name] || CHAT_SOUNDS[DEFAULT_SOUND_NAME])[0].src
|
||||
);
|
||||
const audio = new Audio(src);
|
||||
try {
|
||||
await audio.play();
|
||||
} catch (e) {
|
||||
|
|
|
@ -8,7 +8,11 @@ export default class ChatChannelNotificationSound extends Service {
|
|||
@service site;
|
||||
|
||||
async play(channel) {
|
||||
if (!canUserReceiveNotifications(this.currentUser)) {
|
||||
if (
|
||||
!canUserReceiveNotifications(this.currentUser, {
|
||||
idleThresholdTime: 0,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,13 @@ export default class ChatSubscriptionsManager extends Service {
|
|||
channel.tracking.unreadCount++;
|
||||
}
|
||||
|
||||
this.chatChannelNotificationSound.play(channel);
|
||||
const secondsPassed = moment().diff(
|
||||
moment(busData.message.created_at),
|
||||
"seconds"
|
||||
);
|
||||
if (secondsPassed < 10) {
|
||||
this.chatChannelNotificationSound.play(channel);
|
||||
}
|
||||
|
||||
// Thread should be considered unread if not already.
|
||||
if (busData.thread_id && channel.threadingEnabled) {
|
||||
|
|
|
@ -133,7 +133,7 @@ acceptance(
|
|||
const channel = buildDirectMessageChannel(getOwner(this));
|
||||
resetIdle();
|
||||
|
||||
assert.deepEqual(await this.subject.play(channel), false);
|
||||
assert.deepEqual(await this.subject.play(channel), true);
|
||||
});
|
||||
|
||||
test("notifications disabled", async function (assert) {
|
||||
|
|
Loading…
Reference in New Issue