Skip to content

Commit

Permalink
notifications: Implement functionality for reaction notifications.
Browse files Browse the repository at this point in the history
This commit implements the functionality for reaction notifications
based on the user settings  enable_dm_reaction_notifications and
streams_reaction_notification.
  • Loading branch information
akarsh-jain-790 committed Apr 27, 2024
1 parent 40fca9b commit e22fb92
Show file tree
Hide file tree
Showing 5 changed files with 463 additions and 1 deletion.
17 changes: 16 additions & 1 deletion web/src/message_notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import * as user_topics from "./user_topics";

function get_notification_content(message) {
let content;

if (message.reaction_label) {
return message.reaction_label;
}

// Convert the content to plain text, replacing emoji with their alt text
const $content = $("<div>").html(message.content);
ui_util.replace_emoji_with_text($content);
Expand Down Expand Up @@ -69,6 +74,11 @@ function debug_notification_source_value(message) {
function get_notification_key(message) {
let key;

if (message.current_reaction_key) {
key = message.current_reaction_key;
return key;
}

if (message.type === "private" || message.type === "test-notification") {
key = message.display_reply_to;
} else {
Expand All @@ -89,6 +99,10 @@ function get_notification_title(message, msg_count) {
let title = message.sender_full_name;
let other_recipients;

if (message.reacted_by) {
title = message.reacted_by;
}

if (msg_count > 1) {
title = msg_count + " messages from " + title;
}
Expand Down Expand Up @@ -128,6 +142,7 @@ export function process_notification(notification) {
const message = notification.message;
const content = get_notification_content(message);
const key = get_notification_key(message);
const notification_tag = message.current_reaction_key ? message.id + key : message.id;
let notification_object;
let msg_count = 1;

Expand All @@ -146,7 +161,7 @@ export function process_notification(notification) {
notification_object = new desktop_notifications.NotificationAPI(title, {
icon: icon_url,
body: content,
tag: message.id,
tag: notification_tag,
});
desktop_notifications.notice_memory.set(key, {
obj: notification_object,
Expand Down
150 changes: 150 additions & 0 deletions web/src/reaction_notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import $ from "jquery";

import * as desktop_notifications from "./desktop_notifications";
import {$t} from "./i18n";
import * as message_notifications from "./message_notifications";
import * as message_store from "./message_store";
import * as people from "./people";
import {get_local_reaction_id} from "./reactions";
import * as settings_config from "./settings_config";
import {current_user} from "./state_data";
import * as ui_util from "./ui_util";
import {user_settings} from "./user_settings";
import * as user_topics from "./user_topics";

function generate_notification_title(emoji_name, user_ids) {
const usernames = people.get_display_full_names(
user_ids.filter((user_id) => user_id !== current_user.user_id),
);

const current_user_reacted = user_ids.length !== usernames.length;

const context = {
emoji_name: ":" + emoji_name + ":",
};

if (user_ids.length === 1) {
context.username = usernames[0];
return $t({defaultMessage: "{username} reacted with {emoji_name}."}, context);
}

if (user_ids.length === 2 && current_user_reacted) {
context.other_username = usernames[0];
return $t(
{
defaultMessage: "You and {other_username} reacted with {emoji_name}.",
},
context,
);
}

context.total_reactions = usernames.length;
context.last_username = usernames.at(-1);

return $t(
{
defaultMessage:
"{last_username} and {total_reactions} others reacted with {emoji_name}.",
},
context,
);
}

export function reaction_is_notifiable(message) {
// If the current user reacted, no need for notification.
if (message.current_user_reacted) {
return false;
}

// If the message is not sent by the current user, no need for notification.
if (!message.sent_by_me) {
return false;
}

// Notify for reactions in private messages if the user has enabled DM reaction notifications.
if (message.type === "private" && user_settings.enable_dm_reaction_notifications) {
return true;
}

// Notify for reactions in stream messages if the user has set stream reaction notifications to "Always".
if (
message.type === "stream" &&
user_settings.streams_reaction_notification ===
settings_config.streams_reaction_notification_values.always.code
) {
return true;
}

// Do not notify for reactions in stream messages if the user has set stream reaction notifications to "Never".
if (
message.type === "stream" &&
user_settings.streams_reaction_notification ===
settings_config.streams_reaction_notification_values.never.code
) {
return false;
}

// Notify for reactions in stream messages if the message's topic is followed by the user
// and the user has set stream reaction notifications to "Followed topics".
if (
message.type === "stream" &&
user_topics.is_topic_followed(message.stream_id, message.topic) &&
user_settings.streams_reaction_notification ===
settings_config.streams_reaction_notification_values.followed_topics.code
) {
return true;
}

// Notify for reactions in stream messages if the message's topic is unmuted by the user
// and the user has set stream reaction notifications to "Unmuted topics".
if (
message.type === "stream" &&
user_topics.is_topic_unmuted(message.stream_id, message.topic) &&
user_settings.streams_reaction_notification ===
settings_config.streams_reaction_notification_values.unmuted_topics.code
) {
return true;
}

// Everything else is on the table; next filter based on notification
// settings.
return false;
}

export function received_reaction(event) {
const message_id = event.message_id;
const message = message_store.get(message_id);

if (message === undefined) {
// If we don't have the message in cache, do nothing; if we
// ever fetch it from the server, it'll come with the
// latest reactions attached
return;
}

const user_id = event.user_id;
const local_id = get_local_reaction_id(event);
const clean_reaction_object = message.clean_reactions.get(local_id);

message.current_user_reacted = user_id === current_user.user_id;
message.current_reaction_key = clean_reaction_object.emoji_name;
message.reaction_label = generate_notification_title(
clean_reaction_object.emoji_name,
clean_reaction_object.user_ids,
);
message.reacted_by = people.get_full_name(user_id);

if (!reaction_is_notifiable(message)) {
return;
}

if (message_notifications.should_send_desktop_notification(message)) {
message_notifications.process_notification({
message,
desktop_notify: desktop_notifications.granted_desktop_notifications_permission(),
});
}
if (message_notifications.should_send_audible_notification(message)) {
ui_util.play_audio($("#user-notification-sound-audio").get(0));
}
}
2 changes: 2 additions & 0 deletions web/src/server_events_dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import * as overlays from "./overlays";
import * as peer_data from "./peer_data";
import * as people from "./people";
import * as pm_list from "./pm_list";
import {received_reaction} from "./reaction_notifications";
import * as reactions from "./reactions";
import * as realm_icon from "./realm_icon";
import * as realm_logo from "./realm_logo";
Expand Down Expand Up @@ -189,6 +190,7 @@ export function dispatch_normal_event(event) {
switch (event.op) {
case "add":
reactions.add_reaction(event);
received_reaction(event);
break;
case "remove":
reactions.remove_reaction(event);
Expand Down
Loading

0 comments on commit e22fb92

Please sign in to comment.