Notification: Fix sound playback conditions (#5734)
This commit is contained in:
parent
37eb65344c
commit
a65d6e0697
@ -24,13 +24,14 @@ import type {
|
|||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { pick, pickTruthy } from '../../../util/iteratees';
|
import { pick, pickTruthy } from '../../../util/iteratees';
|
||||||
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
import { getServerTimeOffset } from '../../../util/serverTime';
|
||||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||||
import { serializeBytes } from '../helpers/misc';
|
import { serializeBytes } from '../helpers/misc';
|
||||||
import {
|
import {
|
||||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||||
} from './common';
|
} from './common';
|
||||||
import { omitVirtualClassFields } from './helpers';
|
import { omitVirtualClassFields } from './helpers';
|
||||||
|
import { buildApiPeerNotifySettings } from './misc';
|
||||||
import {
|
import {
|
||||||
buildApiEmojiStatus,
|
buildApiEmojiStatus,
|
||||||
buildApiPeerColor,
|
buildApiPeerColor,
|
||||||
@ -119,10 +120,8 @@ export function buildApiChatFromDialog(
|
|||||||
): ApiChat {
|
): ApiChat {
|
||||||
const {
|
const {
|
||||||
peer, folderId, unreadMark, unreadCount, unreadMentionsCount, unreadReactionsCount,
|
peer, folderId, unreadMark, unreadCount, unreadMentionsCount, unreadReactionsCount,
|
||||||
notifySettings: { silent, muteUntil },
|
|
||||||
readOutboxMaxId, readInboxMaxId, draft, viewForumAsMessages,
|
readOutboxMaxId, readInboxMaxId, draft, viewForumAsMessages,
|
||||||
} = dialog;
|
} = dialog;
|
||||||
const isMuted = silent || (typeof muteUntil === 'number' && getServerTime() < muteUntil);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: getApiChatIdFromMtpPeer(peer),
|
id: getApiChatIdFromMtpPeer(peer),
|
||||||
@ -134,8 +133,6 @@ export function buildApiChatFromDialog(
|
|||||||
unreadCount,
|
unreadCount,
|
||||||
unreadMentionsCount,
|
unreadMentionsCount,
|
||||||
unreadReactionsCount,
|
unreadReactionsCount,
|
||||||
isMuted,
|
|
||||||
muteUntil,
|
|
||||||
...(unreadMark && { hasUnreadMark: true }),
|
...(unreadMark && { hasUnreadMark: true }),
|
||||||
...(draft instanceof GramJs.DraftMessage && { draftDate: draft.date }),
|
...(draft instanceof GramJs.DraftMessage && { draftDate: draft.date }),
|
||||||
...(viewForumAsMessages && { isForumAsMessages: true }),
|
...(viewForumAsMessages && { isForumAsMessages: true }),
|
||||||
@ -579,9 +576,7 @@ export function buildApiTopic(forumTopic: GramJs.TypeForumTopic): ApiTopic | und
|
|||||||
unreadMentionsCount,
|
unreadMentionsCount,
|
||||||
unreadReactionsCount,
|
unreadReactionsCount,
|
||||||
fromId,
|
fromId,
|
||||||
notifySettings: {
|
notifySettings,
|
||||||
silent, muteUntil,
|
|
||||||
},
|
|
||||||
} = forumTopic;
|
} = forumTopic;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -600,8 +595,7 @@ export function buildApiTopic(forumTopic: GramJs.TypeForumTopic): ApiTopic | und
|
|||||||
unreadMentionsCount,
|
unreadMentionsCount,
|
||||||
unreadReactionsCount,
|
unreadReactionsCount,
|
||||||
fromId: getApiChatIdFromMtpPeer(fromId),
|
fromId: getApiChatIdFromMtpPeer(fromId),
|
||||||
isMuted: silent || (typeof muteUntil === 'number' ? getServerTime() < muteUntil : undefined),
|
notifySettings: buildApiPeerNotifySettings(notifySettings),
|
||||||
muteUntil,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -163,6 +163,7 @@ export function buildApiMessageFromNotification(
|
|||||||
chatId: SERVICE_NOTIFICATIONS_USER_ID,
|
chatId: SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
date: notification.inboxDate || currentDate,
|
date: notification.inboxDate || currentDate,
|
||||||
content,
|
content,
|
||||||
|
isInvertedMedia: notification.invertMedia,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import type {
|
|||||||
ApiLanguage,
|
ApiLanguage,
|
||||||
ApiOldLangString,
|
ApiOldLangString,
|
||||||
ApiPeerColors,
|
ApiPeerColors,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
ApiPrivacyKey,
|
ApiPrivacyKey,
|
||||||
ApiSession,
|
ApiSession,
|
||||||
ApiTimezone,
|
ApiTimezone,
|
||||||
@ -21,7 +22,6 @@ import { numberToHexColor } from '../../../util/colors';
|
|||||||
import {
|
import {
|
||||||
buildCollectionByCallback, omit, omitUndefined, pick,
|
buildCollectionByCallback, omit, omitUndefined, pick,
|
||||||
} from '../../../util/iteratees';
|
} from '../../../util/iteratees';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
|
||||||
import { addUserToLocalDb } from '../helpers/localDb';
|
import { addUserToLocalDb } from '../helpers/localDb';
|
||||||
import { omitVirtualClassFields } from './helpers';
|
import { omitVirtualClassFields } from './helpers';
|
||||||
import { buildApiDocument, buildMessageTextContent } from './messageContent';
|
import { buildApiDocument, buildMessageTextContent } from './messageContent';
|
||||||
@ -106,40 +106,20 @@ export function buildPrivacyKey(key: GramJs.TypePrivacyKey): ApiPrivacyKey | und
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildApiNotifyException(
|
export function buildApiPeerNotifySettings(
|
||||||
notifySettings: GramJs.TypePeerNotifySettings, peer: GramJs.TypePeer,
|
notifySettings: GramJs.TypePeerNotifySettings,
|
||||||
) {
|
): ApiPeerNotifySettings {
|
||||||
const {
|
const {
|
||||||
silent, muteUntil, showPreviews, otherSound,
|
silent, muteUntil, showPreviews, otherSound,
|
||||||
} = notifySettings;
|
} = notifySettings;
|
||||||
|
|
||||||
const hasSound = Boolean(otherSound && !(otherSound instanceof GramJs.NotificationSoundNone));
|
const hasSound = !(otherSound instanceof GramJs.NotificationSoundNone);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatId: getApiChatIdFromMtpPeer(peer),
|
hasSound,
|
||||||
isMuted: silent || (typeof muteUntil === 'number' && getServerTime() < muteUntil),
|
isSilentPosting: silent,
|
||||||
...(!hasSound && { isSilent: true }),
|
mutedUntil: muteUntil,
|
||||||
...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }),
|
shouldShowPreviews: showPreviews,
|
||||||
muteUntil,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildApiNotifyExceptionTopic(
|
|
||||||
notifySettings: GramJs.TypePeerNotifySettings, peer: GramJs.TypePeer, topicId: number,
|
|
||||||
) {
|
|
||||||
const {
|
|
||||||
silent, muteUntil, showPreviews, otherSound,
|
|
||||||
} = notifySettings;
|
|
||||||
|
|
||||||
const hasSound = Boolean(otherSound && !(otherSound instanceof GramJs.NotificationSoundNone));
|
|
||||||
|
|
||||||
return {
|
|
||||||
chatId: getApiChatIdFromMtpPeer(peer),
|
|
||||||
topicId,
|
|
||||||
isMuted: silent || (typeof muteUntil === 'number' && getServerTime() < muteUntil),
|
|
||||||
...(!hasSound && { isSilent: true }),
|
|
||||||
...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }),
|
|
||||||
muteUntil,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import type {
|
|||||||
ApiMessage,
|
ApiMessage,
|
||||||
ApiMissingInvitedUser,
|
ApiMissingInvitedUser,
|
||||||
ApiPeer,
|
ApiPeer,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
ApiPhoto,
|
ApiPhoto,
|
||||||
ApiTopic,
|
ApiTopic,
|
||||||
ApiUser,
|
ApiUser,
|
||||||
@ -31,7 +32,7 @@ import {
|
|||||||
SERVICE_NOTIFICATIONS_USER_ID,
|
SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
TOPICS_SLICE,
|
TOPICS_SLICE,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey, omitUndefined } from '../../../util/iteratees';
|
||||||
import {
|
import {
|
||||||
buildApiChatBotCommands,
|
buildApiChatBotCommands,
|
||||||
buildApiChatFolder,
|
buildApiChatFolder,
|
||||||
@ -52,6 +53,7 @@ import {
|
|||||||
} from '../apiBuilders/chats';
|
} from '../apiBuilders/chats';
|
||||||
import { buildApiBotVerification, buildApiPhoto } from '../apiBuilders/common';
|
import { buildApiBotVerification, buildApiPhoto } from '../apiBuilders/common';
|
||||||
import { buildApiMessage, buildMessageDraft } from '../apiBuilders/messages';
|
import { buildApiMessage, buildMessageDraft } from '../apiBuilders/messages';
|
||||||
|
import { buildApiPeerNotifySettings } from '../apiBuilders/misc';
|
||||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||||
import { buildStickerSet } from '../apiBuilders/symbols';
|
import { buildStickerSet } from '../apiBuilders/symbols';
|
||||||
import { buildApiUser, buildApiUserStatuses } from '../apiBuilders/users';
|
import { buildApiUser, buildApiUserStatuses } from '../apiBuilders/users';
|
||||||
@ -96,6 +98,7 @@ type ChatListData = {
|
|||||||
orderedPinnedIds: string[] | undefined;
|
orderedPinnedIds: string[] | undefined;
|
||||||
totalChatCount: number;
|
totalChatCount: number;
|
||||||
messages: ApiMessage[];
|
messages: ApiMessage[];
|
||||||
|
notifyExceptionById: Record<string, ApiPeerNotifySettings>;
|
||||||
lastMessageByChatId: Record<string, number>;
|
lastMessageByChatId: Record<string, number>;
|
||||||
nextOffsetId?: number;
|
nextOffsetId?: number;
|
||||||
nextOffsetPeerId?: string;
|
nextOffsetPeerId?: string;
|
||||||
@ -150,6 +153,7 @@ export async function fetchChats({
|
|||||||
|
|
||||||
const chats: ApiChat[] = [];
|
const chats: ApiChat[] = [];
|
||||||
const draftsById: Record<string, ApiDraft> = {};
|
const draftsById: Record<string, ApiDraft> = {};
|
||||||
|
const notifyExceptionById: Record<string, ApiPeerNotifySettings> = {};
|
||||||
|
|
||||||
const dialogs = (resultPinned?.dialogs || []).concat(result.dialogs);
|
const dialogs = (resultPinned?.dialogs || []).concat(result.dialogs);
|
||||||
|
|
||||||
@ -186,7 +190,12 @@ export async function fetchChats({
|
|||||||
|
|
||||||
chats.push(chat);
|
chats.push(chat);
|
||||||
|
|
||||||
scheduleMutedChatUpdate(chat.id, chat.muteUntil, sendApiUpdate);
|
const notifySettings = buildApiPeerNotifySettings(dialog.notifySettings);
|
||||||
|
if (Object.values(omitUndefined(notifySettings)).length) {
|
||||||
|
notifyExceptionById[chat.id] = notifySettings;
|
||||||
|
|
||||||
|
scheduleMutedChatUpdate(chat.id, notifySettings.mutedUntil, sendApiUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
if (withPinned && dialog.pinned) {
|
if (withPinned && dialog.pinned) {
|
||||||
orderedPinnedIds.push(chat.id);
|
orderedPinnedIds.push(chat.id);
|
||||||
@ -229,6 +238,7 @@ export async function fetchChats({
|
|||||||
totalChatCount,
|
totalChatCount,
|
||||||
lastMessageByChatId,
|
lastMessageByChatId,
|
||||||
messages,
|
messages,
|
||||||
|
notifyExceptionById,
|
||||||
nextOffsetId,
|
nextOffsetId,
|
||||||
nextOffsetPeerId,
|
nextOffsetPeerId,
|
||||||
nextOffsetDate,
|
nextOffsetDate,
|
||||||
@ -327,6 +337,7 @@ export async function fetchSavedChats({
|
|||||||
lastMessageByChatId,
|
lastMessageByChatId,
|
||||||
messages,
|
messages,
|
||||||
draftsById: {},
|
draftsById: {},
|
||||||
|
notifyExceptionById: {},
|
||||||
nextOffsetId,
|
nextOffsetId,
|
||||||
nextOffsetPeerId,
|
nextOffsetPeerId,
|
||||||
nextOffsetDate,
|
nextOffsetDate,
|
||||||
@ -474,7 +485,9 @@ export async function requestChatUpdate({
|
|||||||
|
|
||||||
applyState(result.state);
|
applyState(result.state);
|
||||||
|
|
||||||
scheduleMutedChatUpdate(chatUpdate.id, chatUpdate.muteUntil, sendApiUpdate);
|
const notifySettings = buildApiPeerNotifySettings(dialog.notifySettings);
|
||||||
|
|
||||||
|
scheduleMutedChatUpdate(chatUpdate.id, notifySettings.mutedUntil, sendApiUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveDraft({
|
export function saveDraft({
|
||||||
@ -722,25 +735,27 @@ async function getFullChannelInfo(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateChatMutedState({
|
export function updateChatMutedState({
|
||||||
chat, isMuted, muteUntil = 0,
|
chat, isMuted, mutedUntil = 0,
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat; isMuted: boolean; muteUntil?: number;
|
chat: ApiChat; isMuted?: boolean; mutedUntil?: number;
|
||||||
}) {
|
}) {
|
||||||
if (isMuted && !muteUntil) {
|
if (isMuted && !mutedUntil) {
|
||||||
muteUntil = MAX_INT_32;
|
mutedUntil = MAX_INT_32;
|
||||||
}
|
}
|
||||||
await invokeRequest(new GramJs.account.UpdateNotifySettings({
|
invokeRequest(new GramJs.account.UpdateNotifySettings({
|
||||||
peer: new GramJs.InputNotifyPeer({
|
peer: new GramJs.InputNotifyPeer({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
}),
|
}),
|
||||||
settings: new GramJs.InputPeerNotifySettings({ muteUntil }),
|
settings: new GramJs.InputPeerNotifySettings({ muteUntil: mutedUntil }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateNotifyExceptions',
|
'@type': 'updateChatNotifySettings',
|
||||||
chatId: chat.id,
|
chatId: chat.id,
|
||||||
isMuted,
|
settings: {
|
||||||
|
mutedUntil,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
void requestChatUpdate({
|
void requestChatUpdate({
|
||||||
@ -749,27 +764,29 @@ export async function updateChatMutedState({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateTopicMutedState({
|
export function updateTopicMutedState({
|
||||||
chat, topicId, isMuted, muteUntil = 0,
|
chat, topicId, isMuted, mutedUntil = 0,
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat; topicId: number; isMuted: boolean; muteUntil?: number;
|
chat: ApiChat; topicId: number; isMuted?: boolean; mutedUntil?: number;
|
||||||
}) {
|
}) {
|
||||||
if (isMuted && !muteUntil) {
|
if (isMuted && !mutedUntil) {
|
||||||
muteUntil = MAX_INT_32;
|
mutedUntil = MAX_INT_32;
|
||||||
}
|
}
|
||||||
await invokeRequest(new GramJs.account.UpdateNotifySettings({
|
invokeRequest(new GramJs.account.UpdateNotifySettings({
|
||||||
peer: new GramJs.InputNotifyForumTopic({
|
peer: new GramJs.InputNotifyForumTopic({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
topMsgId: topicId,
|
topMsgId: topicId,
|
||||||
}),
|
}),
|
||||||
settings: new GramJs.InputPeerNotifySettings({ muteUntil }),
|
settings: new GramJs.InputPeerNotifySettings({ muteUntil: mutedUntil }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateTopicNotifyExceptions',
|
'@type': 'updateTopicNotifySettings',
|
||||||
chatId: chat.id,
|
chatId: chat.id,
|
||||||
topicId,
|
topicId,
|
||||||
isMuted,
|
settings: {
|
||||||
|
mutedUntil,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO[forums] Request forum topic thread update
|
// TODO[forums] Request forum topic thread update
|
||||||
|
|||||||
@ -1834,11 +1834,14 @@ export async function reportSponsoredMessage({
|
|||||||
|
|
||||||
export async function readAllMentions({
|
export async function readAllMentions({
|
||||||
chat,
|
chat,
|
||||||
|
threadId,
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
threadId?: ThreadId;
|
||||||
}) {
|
}) {
|
||||||
const result = await invokeRequest(new GramJs.messages.ReadMentions({
|
const result = await invokeRequest(new GramJs.messages.ReadMentions({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
|
topMsgId: threadId ? Number(threadId) : undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
@ -1846,17 +1849,20 @@ export async function readAllMentions({
|
|||||||
processAffectedHistory(chat, result);
|
processAffectedHistory(chat, result);
|
||||||
|
|
||||||
if (result.offset) {
|
if (result.offset) {
|
||||||
await readAllMentions({ chat });
|
await readAllMentions({ chat, threadId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readAllReactions({
|
export async function readAllReactions({
|
||||||
chat,
|
chat,
|
||||||
|
threadId,
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
threadId?: ThreadId;
|
||||||
}) {
|
}) {
|
||||||
const result = await invokeRequest(new GramJs.messages.ReadReactions({
|
const result = await invokeRequest(new GramJs.messages.ReadReactions({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
|
topMsgId: threadId ? Number(threadId) : undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
@ -1864,14 +1870,15 @@ export async function readAllReactions({
|
|||||||
processAffectedHistory(chat, result);
|
processAffectedHistory(chat, result);
|
||||||
|
|
||||||
if (result.offset) {
|
if (result.offset) {
|
||||||
await readAllReactions({ chat });
|
await readAllReactions({ chat, threadId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchUnreadMentions({
|
export async function fetchUnreadMentions({
|
||||||
chat, ...pagination
|
chat, threadId, ...pagination
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
threadId?: ThreadId;
|
||||||
offsetId?: number;
|
offsetId?: number;
|
||||||
addOffset?: number;
|
addOffset?: number;
|
||||||
maxId?: number;
|
maxId?: number;
|
||||||
@ -1879,6 +1886,7 @@ export async function fetchUnreadMentions({
|
|||||||
}) {
|
}) {
|
||||||
const result = await invokeRequest(new GramJs.messages.GetUnreadMentions({
|
const result = await invokeRequest(new GramJs.messages.GetUnreadMentions({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
|
topMsgId: threadId ? Number(threadId) : undefined,
|
||||||
limit: MENTION_UNREAD_SLICE,
|
limit: MENTION_UNREAD_SLICE,
|
||||||
...pagination,
|
...pagination,
|
||||||
}));
|
}));
|
||||||
@ -1899,9 +1907,10 @@ export async function fetchUnreadMentions({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchUnreadReactions({
|
export async function fetchUnreadReactions({
|
||||||
chat, ...pagination
|
chat, threadId, ...pagination
|
||||||
}: {
|
}: {
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
threadId?: ThreadId;
|
||||||
offsetId?: number;
|
offsetId?: number;
|
||||||
addOffset?: number;
|
addOffset?: number;
|
||||||
maxId?: number;
|
maxId?: number;
|
||||||
@ -1909,6 +1918,7 @@ export async function fetchUnreadReactions({
|
|||||||
}) {
|
}) {
|
||||||
const result = await invokeRequest(new GramJs.messages.GetUnreadReactions({
|
const result = await invokeRequest(new GramJs.messages.GetUnreadReactions({
|
||||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||||
|
topMsgId: threadId ? Number(threadId) : undefined,
|
||||||
limit: REACTION_UNREAD_SLICE,
|
limit: REACTION_UNREAD_SLICE,
|
||||||
...pagination,
|
...pagination,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import type {
|
|||||||
ApiConfig,
|
ApiConfig,
|
||||||
ApiInputPrivacyRules,
|
ApiInputPrivacyRules,
|
||||||
ApiLanguage,
|
ApiLanguage,
|
||||||
ApiNotifyException,
|
ApiNotifyPeerType,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
ApiPhoto,
|
ApiPhoto,
|
||||||
ApiPrivacyKey,
|
ApiPrivacyKey,
|
||||||
ApiUser,
|
ApiUser,
|
||||||
@ -21,15 +22,14 @@ import {
|
|||||||
MAX_INT_32,
|
MAX_INT_32,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
|
||||||
import { buildAppConfig } from '../apiBuilders/appConfig';
|
import { buildAppConfig } from '../apiBuilders/appConfig';
|
||||||
import { buildApiPhoto, buildPrivacyRules } from '../apiBuilders/common';
|
import { buildApiPhoto, buildPrivacyRules } from '../apiBuilders/common';
|
||||||
import {
|
import {
|
||||||
buildApiConfig,
|
buildApiConfig,
|
||||||
buildApiCountryList,
|
buildApiCountryList,
|
||||||
buildApiLanguage,
|
buildApiLanguage,
|
||||||
buildApiNotifyException,
|
|
||||||
buildApiPeerColors,
|
buildApiPeerColors,
|
||||||
|
buildApiPeerNotifySettings,
|
||||||
buildApiSession,
|
buildApiSession,
|
||||||
buildApiTimezone,
|
buildApiTimezone,
|
||||||
buildApiWallpaper,
|
buildApiWallpaper,
|
||||||
@ -323,20 +323,26 @@ export async function fetchNotificationExceptions() {
|
|||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.push(buildApiNotifyException(update.notifySettings, update.peer.peer));
|
const peerId = getApiChatIdFromMtpPeer(update.peer.peer);
|
||||||
|
|
||||||
|
acc[peerId] = buildApiPeerNotifySettings(update.notifySettings);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, [] as ApiNotifyException[]);
|
}, {} as Record<string, ApiPeerNotifySettings>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchNotificationSettings() {
|
export async function fetchContactSignUpSetting() {
|
||||||
|
const hasContactJoinedNotifications = await invokeRequest(new GramJs.account.GetContactSignUpNotification());
|
||||||
|
|
||||||
|
return hasContactJoinedNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchNotifyDefaultSettings() {
|
||||||
const [
|
const [
|
||||||
isMutedContactSignUpNotification,
|
usersSettings,
|
||||||
privateContactNotificationsSettings,
|
groupsSettings,
|
||||||
groupNotificationsSettings,
|
channelsSettings,
|
||||||
broadcastNotificationsSettings,
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
invokeRequest(new GramJs.account.GetContactSignUpNotification()),
|
|
||||||
invokeRequest(new GramJs.account.GetNotifySettings({
|
invokeRequest(new GramJs.account.GetNotifySettings({
|
||||||
peer: new GramJs.InputNotifyUsers(),
|
peer: new GramJs.InputNotifyUsers(),
|
||||||
})),
|
})),
|
||||||
@ -348,37 +354,14 @@ export async function fetchNotificationSettings() {
|
|||||||
})),
|
})),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!privateContactNotificationsSettings || !groupNotificationsSettings || !broadcastNotificationsSettings) {
|
if (!usersSettings || !groupsSettings || !channelsSettings) {
|
||||||
return false;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
|
||||||
silent: privateSilent, muteUntil: privateMuteUntil, showPreviews: privateShowPreviews,
|
|
||||||
} = privateContactNotificationsSettings;
|
|
||||||
const {
|
|
||||||
silent: groupSilent, muteUntil: groupMuteUntil, showPreviews: groupShowPreviews,
|
|
||||||
} = groupNotificationsSettings;
|
|
||||||
const {
|
|
||||||
silent: broadcastSilent, muteUntil: broadcastMuteUntil, showPreviews: broadcastShowPreviews,
|
|
||||||
} = broadcastNotificationsSettings;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasContactJoinedNotifications: !isMutedContactSignUpNotification,
|
users: buildApiPeerNotifySettings(usersSettings),
|
||||||
hasPrivateChatsNotifications: !(
|
groups: buildApiPeerNotifySettings(groupsSettings),
|
||||||
privateSilent
|
channels: buildApiPeerNotifySettings(channelsSettings),
|
||||||
|| (typeof privateMuteUntil === 'number' && getServerTime() < privateMuteUntil)
|
|
||||||
),
|
|
||||||
hasPrivateChatsMessagePreview: privateShowPreviews,
|
|
||||||
hasGroupNotifications: !(
|
|
||||||
groupSilent || (typeof groupMuteUntil === 'number'
|
|
||||||
&& getServerTime() < groupMuteUntil)
|
|
||||||
),
|
|
||||||
hasGroupMessagePreview: groupShowPreviews,
|
|
||||||
hasBroadcastNotifications: !(
|
|
||||||
broadcastSilent || (typeof broadcastMuteUntil === 'number'
|
|
||||||
&& getServerTime() < broadcastMuteUntil)
|
|
||||||
),
|
|
||||||
hasBroadcastMessagePreview: broadcastShowPreviews,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,17 +369,17 @@ export function updateContactSignUpNotification(isSilent: boolean) {
|
|||||||
return invokeRequest(new GramJs.account.SetContactSignUpNotification({ silent: isSilent }));
|
return invokeRequest(new GramJs.account.SetContactSignUpNotification({ silent: isSilent }));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateNotificationSettings(peerType: 'contact' | 'group' | 'broadcast', {
|
export function updateNotificationSettings(peerType: ApiNotifyPeerType, {
|
||||||
isSilent,
|
isMuted,
|
||||||
shouldShowPreviews,
|
shouldShowPreviews,
|
||||||
}: {
|
}: {
|
||||||
isSilent?: boolean;
|
isMuted?: boolean;
|
||||||
shouldShowPreviews?: boolean;
|
shouldShowPreviews?: boolean;
|
||||||
}) {
|
}) {
|
||||||
let peer: GramJs.TypeInputNotifyPeer;
|
let peer: GramJs.TypeInputNotifyPeer;
|
||||||
if (peerType === 'contact') {
|
if (peerType === 'users') {
|
||||||
peer = new GramJs.InputNotifyUsers();
|
peer = new GramJs.InputNotifyUsers();
|
||||||
} else if (peerType === 'group') {
|
} else if (peerType === 'groups') {
|
||||||
peer = new GramJs.InputNotifyChats();
|
peer = new GramJs.InputNotifyChats();
|
||||||
} else {
|
} else {
|
||||||
peer = new GramJs.InputNotifyBroadcasts();
|
peer = new GramJs.InputNotifyBroadcasts();
|
||||||
@ -404,8 +387,7 @@ export function updateNotificationSettings(peerType: 'contact' | 'group' | 'broa
|
|||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
showPreviews: shouldShowPreviews,
|
showPreviews: shouldShowPreviews,
|
||||||
silent: isSilent,
|
muteUntil: isMuted ? MAX_INT_32 : 0,
|
||||||
muteUntil: isSilent ? MAX_INT_32 : 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return invokeRequest(new GramJs.account.UpdateNotifySettings({
|
return invokeRequest(new GramJs.account.UpdateNotifySettings({
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import type { OnApiUpdate } from '../types';
|
|||||||
import { MAX_INT_32 } from '../../config';
|
import { MAX_INT_32 } from '../../config';
|
||||||
import { getServerTime } from '../../util/serverTime';
|
import { getServerTime } from '../../util/serverTime';
|
||||||
|
|
||||||
type UnmuteQueueItem = { chatId: string; topicId?: number; muteUntil: number };
|
type UnmuteQueueItem = { chatId: string; topicId?: number; mutedUntil: number };
|
||||||
const unmuteTimers = new Map<string, any>();
|
const unmuteTimers = new Map<string, any>();
|
||||||
const unmuteQueue: Array<UnmuteQueueItem> = [];
|
const unmuteQueue: Array<UnmuteQueueItem> = [];
|
||||||
const scheduleUnmute = (item: UnmuteQueueItem, onUpdate: NoneToVoidFunction) => {
|
const scheduleUnmute = (item: UnmuteQueueItem, onUpdate: NoneToVoidFunction) => {
|
||||||
@ -12,9 +12,9 @@ const scheduleUnmute = (item: UnmuteQueueItem, onUpdate: NoneToVoidFunction) =>
|
|||||||
clearTimeout(unmuteTimers.get(id));
|
clearTimeout(unmuteTimers.get(id));
|
||||||
unmuteTimers.delete(id);
|
unmuteTimers.delete(id);
|
||||||
}
|
}
|
||||||
if (item.muteUntil === MAX_INT_32 || item.muteUntil <= getServerTime()) return;
|
if (item.mutedUntil === MAX_INT_32 || item.mutedUntil <= getServerTime()) return;
|
||||||
unmuteQueue.push(item);
|
unmuteQueue.push(item);
|
||||||
unmuteQueue.sort((a, b) => b.muteUntil - a.muteUntil);
|
unmuteQueue.sort((a, b) => b.mutedUntil - a.mutedUntil);
|
||||||
const next = unmuteQueue.pop();
|
const next = unmuteQueue.pop();
|
||||||
if (!next) return;
|
if (!next) return;
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
@ -23,30 +23,34 @@ const scheduleUnmute = (item: UnmuteQueueItem, onUpdate: NoneToVoidFunction) =>
|
|||||||
const afterNext = unmuteQueue.pop();
|
const afterNext = unmuteQueue.pop();
|
||||||
if (afterNext) scheduleUnmute(afterNext, onUpdate);
|
if (afterNext) scheduleUnmute(afterNext, onUpdate);
|
||||||
}
|
}
|
||||||
}, (item.muteUntil - getServerTime()) * 1000);
|
}, (item.mutedUntil - getServerTime()) * 1000);
|
||||||
unmuteTimers.set(id, timer);
|
unmuteTimers.set(id, timer);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function scheduleMutedChatUpdate(chatId: string, muteUntil = 0, onUpdate: OnApiUpdate) {
|
export function scheduleMutedChatUpdate(chatId: string, mutedUntil = 0, onUpdate: OnApiUpdate) {
|
||||||
scheduleUnmute({
|
scheduleUnmute({
|
||||||
chatId,
|
chatId,
|
||||||
muteUntil,
|
mutedUntil,
|
||||||
}, () => onUpdate({
|
}, () => onUpdate({
|
||||||
'@type': 'updateNotifyExceptions',
|
'@type': 'updateChatNotifySettings',
|
||||||
chatId,
|
chatId,
|
||||||
isMuted: false,
|
settings: {
|
||||||
|
mutedUntil: 0,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scheduleMutedTopicUpdate(chatId: string, topicId: number, muteUntil = 0, onUpdate: OnApiUpdate) {
|
export function scheduleMutedTopicUpdate(chatId: string, topicId: number, mutedUntil = 0, onUpdate: OnApiUpdate) {
|
||||||
scheduleUnmute({
|
scheduleUnmute({
|
||||||
chatId,
|
chatId,
|
||||||
topicId,
|
topicId,
|
||||||
muteUntil,
|
mutedUntil,
|
||||||
}, () => onUpdate({
|
}, () => onUpdate({
|
||||||
'@type': 'updateTopicNotifyExceptions',
|
'@type': 'updateTopicNotifySettings',
|
||||||
chatId,
|
chatId,
|
||||||
topicId,
|
topicId,
|
||||||
isMuted: false,
|
settings: {
|
||||||
|
mutedUntil: 0,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,8 +47,7 @@ import {
|
|||||||
buildMessageDraft,
|
buildMessageDraft,
|
||||||
} from '../apiBuilders/messages';
|
} from '../apiBuilders/messages';
|
||||||
import {
|
import {
|
||||||
buildApiNotifyException,
|
buildApiPeerNotifySettings,
|
||||||
buildApiNotifyExceptionTopic,
|
|
||||||
buildLangStrings,
|
buildLangStrings,
|
||||||
buildPrivacyKey,
|
buildPrivacyKey,
|
||||||
} from '../apiBuilders/misc';
|
} from '../apiBuilders/misc';
|
||||||
@ -631,28 +630,6 @@ export function updater(update: Update) {
|
|||||||
messageIds: update.messages,
|
messageIds: update.messages,
|
||||||
isPinned: update.pinned,
|
isPinned: update.pinned,
|
||||||
});
|
});
|
||||||
} else if (
|
|
||||||
update instanceof GramJs.UpdateNotifySettings
|
|
||||||
&& update.peer instanceof GramJs.NotifyPeer
|
|
||||||
) {
|
|
||||||
const payload = buildApiNotifyException(update.notifySettings, update.peer.peer);
|
|
||||||
scheduleMutedChatUpdate(payload.chatId, payload.muteUntil, sendApiUpdate);
|
|
||||||
sendApiUpdate({
|
|
||||||
'@type': 'updateNotifyExceptions',
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
update instanceof GramJs.UpdateNotifySettings
|
|
||||||
&& update.peer instanceof GramJs.NotifyForumTopic
|
|
||||||
) {
|
|
||||||
const payload = buildApiNotifyExceptionTopic(
|
|
||||||
update.notifySettings, update.peer.peer, update.peer.topMsgId,
|
|
||||||
);
|
|
||||||
scheduleMutedTopicUpdate(payload.chatId, payload.topicId, payload.muteUntil, sendApiUpdate);
|
|
||||||
sendApiUpdate({
|
|
||||||
'@type': 'updateTopicNotifyExceptions',
|
|
||||||
...payload,
|
|
||||||
});
|
|
||||||
} else if (
|
} else if (
|
||||||
update instanceof GramJs.UpdateUserTyping
|
update instanceof GramJs.UpdateUserTyping
|
||||||
|| update instanceof GramJs.UpdateChatUserTyping
|
|| update instanceof GramJs.UpdateChatUserTyping
|
||||||
@ -837,18 +814,41 @@ export function updater(update: Update) {
|
|||||||
// Settings
|
// Settings
|
||||||
} else if (update instanceof GramJs.UpdateNotifySettings) {
|
} else if (update instanceof GramJs.UpdateNotifySettings) {
|
||||||
const {
|
const {
|
||||||
notifySettings: {
|
notifySettings,
|
||||||
showPreviews, silent, muteUntil,
|
peer: notifyPeer,
|
||||||
},
|
|
||||||
peer: { className },
|
|
||||||
} = update;
|
} = update;
|
||||||
|
const className = notifyPeer.className;
|
||||||
|
const settings = buildApiPeerNotifySettings(notifySettings);
|
||||||
|
|
||||||
|
if (notifyPeer instanceof GramJs.NotifyPeer) {
|
||||||
|
const peerId = getApiChatIdFromMtpPeer(notifyPeer.peer);
|
||||||
|
scheduleMutedChatUpdate(peerId, settings.mutedUntil, sendApiUpdate);
|
||||||
|
sendApiUpdate({
|
||||||
|
'@type': 'updateChatNotifySettings',
|
||||||
|
chatId: peerId,
|
||||||
|
settings,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifyPeer instanceof GramJs.NotifyForumTopic) {
|
||||||
|
const peerId = getApiChatIdFromMtpPeer(notifyPeer.peer);
|
||||||
|
scheduleMutedTopicUpdate(peerId, notifyPeer.topMsgId, settings.mutedUntil, sendApiUpdate);
|
||||||
|
sendApiUpdate({
|
||||||
|
'@type': 'updateTopicNotifySettings',
|
||||||
|
chatId: peerId,
|
||||||
|
topicId: notifyPeer.topMsgId,
|
||||||
|
settings,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const peerType = className === 'NotifyUsers'
|
const peerType = className === 'NotifyUsers'
|
||||||
? 'contact'
|
? 'users'
|
||||||
: (className === 'NotifyChats'
|
: (className === 'NotifyChats'
|
||||||
? 'group'
|
? 'groups'
|
||||||
: (className === 'NotifyBroadcasts'
|
: (className === 'NotifyBroadcasts'
|
||||||
? 'broadcast'
|
? 'channels'
|
||||||
: undefined
|
: undefined
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -858,11 +858,9 @@ export function updater(update: Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateNotifySettings',
|
'@type': 'updateDefaultNotifySettings',
|
||||||
peerType,
|
peerType,
|
||||||
isSilent: Boolean(silent
|
settings,
|
||||||
|| (typeof muteUntil === 'number' && Date.now() + getServerTimeOffset() * 1000 < muteUntil * 1000)),
|
|
||||||
shouldShowPreviews: Boolean(showPreviews),
|
|
||||||
});
|
});
|
||||||
} else if (update instanceof GramJs.UpdatePeerBlocked) {
|
} else if (update instanceof GramJs.UpdatePeerBlocked) {
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { ApiBotCommand } from './bots';
|
|||||||
import type {
|
import type {
|
||||||
ApiChatReactions, ApiFormattedText, ApiInputMessageReplyInfo, ApiPhoto, ApiStickerSet,
|
ApiChatReactions, ApiFormattedText, ApiInputMessageReplyInfo, ApiPhoto, ApiStickerSet,
|
||||||
} from './messages';
|
} from './messages';
|
||||||
import type { ApiBotVerification, ApiChatInviteImporter } from './misc';
|
import type { ApiBotVerification, ApiChatInviteImporter, ApiPeerNotifySettings } from './misc';
|
||||||
import type {
|
import type {
|
||||||
ApiEmojiStatusType, ApiFakeType, ApiUser, ApiUsername,
|
ApiEmojiStatusType, ApiFakeType, ApiUser, ApiUsername,
|
||||||
} from './users';
|
} from './users';
|
||||||
@ -27,8 +27,6 @@ export interface ApiChat {
|
|||||||
unreadMentionsCount?: number;
|
unreadMentionsCount?: number;
|
||||||
unreadReactionsCount?: number;
|
unreadReactionsCount?: number;
|
||||||
isVerified?: true;
|
isVerified?: true;
|
||||||
isMuted?: boolean;
|
|
||||||
muteUntil?: number;
|
|
||||||
areSignaturesShown?: boolean;
|
areSignaturesShown?: boolean;
|
||||||
areProfilesShown?: boolean;
|
areProfilesShown?: boolean;
|
||||||
hasPrivateLink?: boolean;
|
hasPrivateLink?: boolean;
|
||||||
@ -262,8 +260,7 @@ export interface ApiTopic {
|
|||||||
unreadMentionsCount: number;
|
unreadMentionsCount: number;
|
||||||
unreadReactionsCount: number;
|
unreadReactionsCount: number;
|
||||||
fromId: string;
|
fromId: string;
|
||||||
isMuted?: boolean;
|
notifySettings: ApiPeerNotifySettings;
|
||||||
muteUntil?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiChatlistInviteNew {
|
export interface ApiChatlistInviteNew {
|
||||||
|
|||||||
@ -106,13 +106,6 @@ export interface ApiSessionData {
|
|||||||
isTest?: true;
|
isTest?: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiNotifyException = {
|
|
||||||
chatId: string;
|
|
||||||
isMuted: boolean;
|
|
||||||
isSilent?: boolean;
|
|
||||||
shouldShowPreviews?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ApiNotification = {
|
export type ApiNotification = {
|
||||||
localId: string;
|
localId: string;
|
||||||
containerSelector?: string;
|
containerSelector?: string;
|
||||||
@ -352,3 +345,12 @@ export type ApiLimitTypeWithModal = Exclude<ApiLimitType, (
|
|||||||
export type ApiLimitTypeForPromo = Exclude<ApiLimitType,
|
export type ApiLimitTypeForPromo = Exclude<ApiLimitType,
|
||||||
'uploadMaxFileparts' | 'chatlistInvites' | 'chatlistJoined' | 'savedDialogsPinned'
|
'uploadMaxFileparts' | 'chatlistInvites' | 'chatlistJoined' | 'savedDialogsPinned'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export type ApiPeerNotifySettings = {
|
||||||
|
mutedUntil?: number;
|
||||||
|
hasSound?: boolean;
|
||||||
|
isSilentPosting?: boolean;
|
||||||
|
shouldShowPreviews?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApiNotifyPeerType = 'users' | 'groups' | 'channels';
|
||||||
|
|||||||
@ -35,7 +35,11 @@ import type {
|
|||||||
BoughtPaidMedia,
|
BoughtPaidMedia,
|
||||||
} from './messages';
|
} from './messages';
|
||||||
import type {
|
import type {
|
||||||
ApiEmojiInteraction, ApiError, ApiNotifyException, ApiSessionData,
|
ApiEmojiInteraction,
|
||||||
|
ApiError,
|
||||||
|
ApiNotifyPeerType,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
|
ApiSessionData,
|
||||||
} from './misc';
|
} from './misc';
|
||||||
import type { ApiStarsAmount } from './payments';
|
import type { ApiStarsAmount } from './payments';
|
||||||
import type { ApiPrivacyKey, LangPackStringValue, PrivacyVisibility } from './settings';
|
import type { ApiPrivacyKey, LangPackStringValue, PrivacyVisibility } from './settings';
|
||||||
@ -501,21 +505,24 @@ export type ApiUpdateTwoFaError = {
|
|||||||
messageKey: RegularLangFnParameters;
|
messageKey: RegularLangFnParameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiUpdateNotifySettings = {
|
export type ApiUpdateDefaultNotifySettings = {
|
||||||
'@type': 'updateNotifySettings';
|
'@type': 'updateDefaultNotifySettings';
|
||||||
peerType: 'contact' | 'group' | 'broadcast';
|
peerType: ApiNotifyPeerType;
|
||||||
isSilent: boolean;
|
settings: Partial<ApiPeerNotifySettings>;
|
||||||
shouldShowPreviews: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiUpdateNotifyExceptions = {
|
export type ApiUpdatePeerNotifySettings = {
|
||||||
'@type': 'updateNotifyExceptions';
|
'@type': 'updateChatNotifySettings';
|
||||||
} & ApiNotifyException;
|
chatId: string;
|
||||||
|
settings: Partial<ApiPeerNotifySettings>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiUpdateTopicNotifyExceptions = {
|
export type ApiUpdateTopicNotifySettings = {
|
||||||
'@type': 'updateTopicNotifyExceptions';
|
'@type': 'updateTopicNotifySettings';
|
||||||
|
chatId: string;
|
||||||
topicId: number;
|
topicId: number;
|
||||||
} & ApiNotifyException;
|
settings: Partial<ApiPeerNotifySettings>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiUpdateTwoFaStateWaitCode = {
|
export type ApiUpdateTwoFaStateWaitCode = {
|
||||||
'@type': 'updateTwoFaStateWaitCode';
|
'@type': 'updateTwoFaStateWaitCode';
|
||||||
@ -823,14 +830,14 @@ export type ApiUpdate = (
|
|||||||
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage | ApiUpdateStarPaymentStateCompleted |
|
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage | ApiUpdateStarPaymentStateCompleted |
|
||||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
||||||
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
ApiUpdateDefaultNotifySettings | ApiUpdatePeerNotifySettings | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
||||||
ApiUpdateServerTimeOffset | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
ApiUpdateServerTimeOffset | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
||||||
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
||||||
ApiUpdateGroupCallConnectionState | ApiUpdateGroupCallLeavePresentation | ApiUpdateGroupCallChatId |
|
ApiUpdateGroupCallConnectionState | ApiUpdateGroupCallLeavePresentation | ApiUpdateGroupCallChatId |
|
||||||
ApiUpdatePendingJoinRequests | ApiUpdatePaymentVerificationNeeded | ApiUpdatePaymentStateCompleted |
|
ApiUpdatePendingJoinRequests | ApiUpdatePaymentVerificationNeeded | ApiUpdatePaymentStateCompleted |
|
||||||
ApiUpdatePhoneCall | ApiUpdatePhoneCallSignalingData | ApiUpdatePhoneCallMediaState |
|
ApiUpdatePhoneCall | ApiUpdatePhoneCallSignalingData | ApiUpdatePhoneCallMediaState |
|
||||||
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus |
|
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus |
|
||||||
ApiUpdateMessageExtendedMedia | ApiUpdateConfig | ApiUpdateTopicNotifyExceptions | ApiUpdatePinnedTopic |
|
ApiUpdateMessageExtendedMedia | ApiUpdateConfig | ApiUpdateTopicNotifySettings | ApiUpdatePinnedTopic |
|
||||||
ApiUpdatePinnedTopicsOrder | ApiUpdateTopic | ApiUpdateTopics | ApiUpdateRecentEmojiStatuses |
|
ApiUpdatePinnedTopicsOrder | ApiUpdateTopic | ApiUpdateTopics | ApiUpdateRecentEmojiStatuses |
|
||||||
ApiUpdateRecentReactions | ApiUpdateStory | ApiUpdateReadStories | ApiUpdateDeleteStory | ApiUpdateSentStoryReaction |
|
ApiUpdateRecentReactions | ApiUpdateStory | ApiUpdateReadStories | ApiUpdateDeleteStory | ApiUpdateSentStoryReaction |
|
||||||
ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages |
|
ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages |
|
||||||
|
|||||||
@ -22,15 +22,15 @@ import {
|
|||||||
getHasAdminRight,
|
getHasAdminRight,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
isUserRightBanned,
|
isUserRightBanned,
|
||||||
selectIsChatMuted,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectBotAppPermissions,
|
selectBotAppPermissions,
|
||||||
selectChat,
|
selectChat,
|
||||||
selectChatFullInfo,
|
selectChatFullInfo,
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
selectNotifyException,
|
||||||
selectTopicLink,
|
selectTopicLink,
|
||||||
selectUser,
|
selectUser,
|
||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
@ -419,7 +419,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
|||||||
<Switcher
|
<Switcher
|
||||||
id="group-notifications"
|
id="group-notifications"
|
||||||
label={userId ? 'Toggle User Notifications' : 'Toggle Chat Notifications'}
|
label={userId ? 'Toggle User Notifications' : 'Toggle Chat Notifications'}
|
||||||
checked={isMuted}
|
checked={!isMuted}
|
||||||
inactive
|
inactive
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@ -487,7 +487,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const user = chatOrUserId ? selectUser(global, chatOrUserId) : undefined;
|
const user = chatOrUserId ? selectUser(global, chatOrUserId) : undefined;
|
||||||
const botAppPermissions = chatOrUserId ? selectBotAppPermissions(global, chatOrUserId) : undefined;
|
const botAppPermissions = chatOrUserId ? selectBotAppPermissions(global, chatOrUserId) : undefined;
|
||||||
const isForum = chat?.isForum;
|
const isForum = chat?.isForum;
|
||||||
const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
|
const isMuted = chat && getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id));
|
||||||
const { threadId } = selectCurrentMessageList(global) || {};
|
const { threadId } = selectCurrentMessageList(global) || {};
|
||||||
const topicId = isForum && threadId ? Number(threadId) : undefined;
|
const topicId = isForum && threadId ? Number(threadId) : undefined;
|
||||||
|
|
||||||
|
|||||||
@ -51,16 +51,16 @@ const MuteChatModal: FC<OwnProps> = ({
|
|||||||
], [lang]);
|
], [lang]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
const handleSubmit = useCallback(() => {
|
||||||
let muteUntil: number;
|
let mutedUntil: number;
|
||||||
if (muteUntilOption === MuteDuration.Forever) {
|
if (muteUntilOption === MuteDuration.Forever) {
|
||||||
muteUntil = MAX_INT_32;
|
mutedUntil = MAX_INT_32;
|
||||||
} else {
|
} else {
|
||||||
muteUntil = Math.floor(Date.now() / 1000) + Number(muteUntilOption);
|
mutedUntil = Math.floor(Date.now() / 1000) + Number(muteUntilOption);
|
||||||
}
|
}
|
||||||
if (topicId) {
|
if (topicId) {
|
||||||
updateTopicMutedState({ chatId, topicId, muteUntil });
|
updateTopicMutedState({ chatId, topicId, mutedUntil });
|
||||||
} else {
|
} else {
|
||||||
updateChatMutedState({ chatId, muteUntil });
|
updateChatMutedState({ chatId, mutedUntil });
|
||||||
}
|
}
|
||||||
onClose();
|
onClose();
|
||||||
}, [chatId, muteUntilOption, onClose, topicId]);
|
}, [chatId, muteUntilOption, onClose, topicId]);
|
||||||
|
|||||||
@ -23,8 +23,8 @@ import {
|
|||||||
groupStatefulContent,
|
groupStatefulContent,
|
||||||
isUserId,
|
isUserId,
|
||||||
isUserOnline,
|
isUserOnline,
|
||||||
selectIsChatMuted,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectCanAnimateInterface,
|
selectCanAnimateInterface,
|
||||||
selectChat,
|
selectChat,
|
||||||
@ -35,8 +35,8 @@ import {
|
|||||||
selectDraft,
|
selectDraft,
|
||||||
selectIsForumPanelClosed,
|
selectIsForumPanelClosed,
|
||||||
selectIsForumPanelOpen,
|
selectIsForumPanelOpen,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
selectNotifyException,
|
||||||
selectOutgoingStatus,
|
selectOutgoingStatus,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
selectPeerStory,
|
selectPeerStory,
|
||||||
@ -470,7 +470,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)),
|
isMuted: getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id)),
|
||||||
lastMessageSender,
|
lastMessageSender,
|
||||||
draft: selectDraft(global, chatId, MAIN_THREAD_ID),
|
draft: selectDraft(global, chatId, MAIN_THREAD_ID),
|
||||||
isSelected,
|
isSelected,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type { ApiChat, ApiTopic } from '../../../api/types';
|
|||||||
import type { Signal } from '../../../util/signals';
|
import type { Signal } from '../../../util/signals';
|
||||||
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
import { isSignal } from '../../../util/signals';
|
import { isSignal } from '../../../util/signals';
|
||||||
import { formatIntegerCompact } from '../../../util/textFormat';
|
import { formatIntegerCompact } from '../../../util/textFormat';
|
||||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||||
@ -62,20 +63,29 @@ const ChatBadge: FC<OwnProps> = ({
|
|||||||
isForum && topics ? Object.values(topics).filter(({ unreadCount }) => unreadCount) : undefined
|
isForum && topics ? Object.values(topics).filter(({ unreadCount }) => unreadCount) : undefined
|
||||||
), [topics, isForum]);
|
), [topics, isForum]);
|
||||||
|
|
||||||
const unreadCount = useMemo(() => (
|
const unreadCount = useMemo(() => {
|
||||||
isForum
|
if (!isForum) {
|
||||||
// If we have unmuted topics, display the count of those. Otherwise, display the count of all topics.
|
return (topic || chat).unreadCount;
|
||||||
? ((isMuted && topicsWithUnread?.filter((acc) => acc.isMuted === false).length)
|
}
|
||||||
|| topicsWithUnread?.length)
|
|
||||||
: (topic || chat).unreadCount
|
|
||||||
), [chat, topic, topicsWithUnread, isForum, isMuted]);
|
|
||||||
|
|
||||||
const shouldBeMuted = useMemo(() => {
|
return topicsWithUnread?.length;
|
||||||
const hasUnmutedUnreadTopics = topics
|
}, [chat, topic, topicsWithUnread, isForum]);
|
||||||
&& Object.values(topics).some((acc) => !acc.isMuted && acc.unreadCount);
|
|
||||||
|
|
||||||
return isMuted || (topics && !hasUnmutedUnreadTopics);
|
const shouldBeUnMuted = useMemo(() => {
|
||||||
}, [topics, isMuted]);
|
if (!isForum) {
|
||||||
|
return !isMuted || topic?.notifySettings.mutedUntil === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMuted) {
|
||||||
|
return topicsWithUnread?.some((acc) => acc.notifySettings.mutedUntil === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isEveryUnreadMuted = topicsWithUnread?.every((acc) => (
|
||||||
|
acc.notifySettings.mutedUntil && acc.notifySettings.mutedUntil > getServerTime()
|
||||||
|
));
|
||||||
|
|
||||||
|
return !isEveryUnreadMuted;
|
||||||
|
}, [isForum, isMuted, topicsWithUnread, topic?.notifySettings.mutedUntil]);
|
||||||
|
|
||||||
const hasUnreadMark = topic ? false : chat.hasUnreadMark;
|
const hasUnreadMark = topic ? false : chat.hasUnreadMark;
|
||||||
|
|
||||||
@ -91,7 +101,7 @@ const ChatBadge: FC<OwnProps> = ({
|
|||||||
const isUnread = Boolean((unreadCount || hasUnreadMark) && !isSavedDialog);
|
const isUnread = Boolean((unreadCount || hasUnreadMark) && !isSavedDialog);
|
||||||
const className = buildClassName(
|
const className = buildClassName(
|
||||||
'ChatBadge',
|
'ChatBadge',
|
||||||
shouldBeMuted && 'muted',
|
!shouldBeUnMuted && 'muted',
|
||||||
!isUnread && isPinned && 'pinned',
|
!isUnread && isPinned && 'pinned',
|
||||||
isUnread && 'unread',
|
isUnread && 'unread',
|
||||||
);
|
);
|
||||||
@ -109,7 +119,7 @@ const ChatBadge: FC<OwnProps> = ({
|
|||||||
|
|
||||||
function renderContent() {
|
function renderContent() {
|
||||||
const unreadReactionsElement = unreadReactionsCount && (
|
const unreadReactionsElement = unreadReactionsCount && (
|
||||||
<div className={buildClassName('ChatBadge reaction', shouldBeMuted && 'muted')}>
|
<div className={buildClassName('ChatBadge reaction', !shouldBeUnMuted && 'muted')}>
|
||||||
<Icon name="heart" />
|
<Icon name="heart" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -121,7 +131,7 @@ const ChatBadge: FC<OwnProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const unopenedTopicElement = isTopicUnopened && (
|
const unopenedTopicElement = isTopicUnopened && (
|
||||||
<div className={buildClassName('ChatBadge unopened', shouldBeMuted && 'muted')} />
|
<div className={buildClassName('ChatBadge unopened', !shouldBeUnMuted && 'muted')} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const unreadCountElement = (hasUnreadMark || unreadCount) ? (
|
const unreadCountElement = (hasUnreadMark || unreadCount) ? (
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
|||||||
import type { ChatAnimationTypes } from './hooks';
|
import type { ChatAnimationTypes } from './hooks';
|
||||||
|
|
||||||
import { groupStatefulContent } from '../../../global/helpers';
|
import { groupStatefulContent } from '../../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectCanAnimateInterface,
|
selectCanAnimateInterface,
|
||||||
selectCanDeleteTopic,
|
selectCanDeleteTopic,
|
||||||
@ -17,6 +18,8 @@ import {
|
|||||||
selectChatMessage,
|
selectChatMessage,
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectDraft,
|
selectDraft,
|
||||||
|
selectNotifyDefaults,
|
||||||
|
selectNotifyException,
|
||||||
selectOutgoingStatus,
|
selectOutgoingStatus,
|
||||||
selectPeerStory,
|
selectPeerStory,
|
||||||
selectSender,
|
selectSender,
|
||||||
@ -57,6 +60,7 @@ type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
isChatMuted?: boolean;
|
||||||
canDelete?: boolean;
|
canDelete?: boolean;
|
||||||
lastMessage?: ApiMessage;
|
lastMessage?: ApiMessage;
|
||||||
lastMessageStory?: ApiTypeStory;
|
lastMessageStory?: ApiTypeStory;
|
||||||
@ -75,6 +79,7 @@ const Topic: FC<OwnProps & StateProps> = ({
|
|||||||
isSelected,
|
isSelected,
|
||||||
chatId,
|
chatId,
|
||||||
chat,
|
chat,
|
||||||
|
isChatMuted,
|
||||||
style,
|
style,
|
||||||
lastMessage,
|
lastMessage,
|
||||||
lastMessageStory,
|
lastMessageStory,
|
||||||
@ -106,9 +111,9 @@ const Topic: FC<OwnProps & StateProps> = ({
|
|||||||
const [shouldRenderMuteModal, markRenderMuteModal, unmarkRenderMuteModal] = useFlag();
|
const [shouldRenderMuteModal, markRenderMuteModal, unmarkRenderMuteModal] = useFlag();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isPinned, isClosed,
|
isPinned, isClosed, notifySettings,
|
||||||
} = topic;
|
} = topic;
|
||||||
const isMuted = topic.isMuted || (topic.isMuted === undefined && chat.isMuted);
|
const isMuted = Boolean(notifySettings.mutedUntil || (notifySettings.mutedUntil === undefined && isChatMuted));
|
||||||
|
|
||||||
const handleOpenDeleteModal = useLastCallback(() => {
|
const handleOpenDeleteModal = useLastCallback(() => {
|
||||||
markRenderDeleteModal();
|
markRenderDeleteModal();
|
||||||
@ -154,6 +159,7 @@ const Topic: FC<OwnProps & StateProps> = ({
|
|||||||
const contextActions = useTopicContextActions({
|
const contextActions = useTopicContextActions({
|
||||||
topic,
|
topic,
|
||||||
chat,
|
chat,
|
||||||
|
isChatMuted,
|
||||||
wasOpened: wasTopicOpened,
|
wasOpened: wasTopicOpened,
|
||||||
canDelete,
|
canDelete,
|
||||||
handleDelete: handleOpenDeleteModal,
|
handleDelete: handleOpenDeleteModal,
|
||||||
@ -181,7 +187,7 @@ const Topic: FC<OwnProps & StateProps> = ({
|
|||||||
<TopicIcon topic={topic} className={styles.topicIcon} observeIntersection={observeIntersection} />
|
<TopicIcon topic={topic} className={styles.topicIcon} observeIntersection={observeIntersection} />
|
||||||
<h3 dir="auto" className="fullName">{renderText(topic.title)}</h3>
|
<h3 dir="auto" className="fullName">{renderText(topic.title)}</h3>
|
||||||
</div>
|
</div>
|
||||||
{topic.isMuted && <Icon name="muted" />}
|
{Boolean(notifySettings.mutedUntil) && <Icon name="muted" />}
|
||||||
<div className="separator" />
|
<div className="separator" />
|
||||||
{isClosed && (
|
{isClosed && (
|
||||||
<Icon name="lock-badge" className={styles.closedIcon} />
|
<Icon name="lock-badge" className={styles.closedIcon} />
|
||||||
@ -247,11 +253,16 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const storyData = lastMessage?.content.storyData;
|
const storyData = lastMessage?.content.storyData;
|
||||||
const lastMessageStory = storyData && selectPeerStory(global, storyData.peerId, storyData.id);
|
const lastMessageStory = storyData && selectPeerStory(global, storyData.peerId, storyData.id);
|
||||||
|
|
||||||
|
const isChatMuted = chat && getIsChatMuted(
|
||||||
|
chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
lastMessage,
|
lastMessage,
|
||||||
lastMessageSender,
|
lastMessageSender,
|
||||||
typingStatus,
|
typingStatus,
|
||||||
|
isChatMuted,
|
||||||
canDelete: selectCanDeleteTopic(global, chatId, topic.id),
|
canDelete: selectCanDeleteTopic(global, chatId, topic.id),
|
||||||
withInterfaceAnimations: selectCanAnimateInterface(global),
|
withInterfaceAnimations: selectCanAnimateInterface(global),
|
||||||
draft,
|
draft,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import useOldLang from '../../../../hooks/useOldLang';
|
|||||||
export default function useTopicContextActions({
|
export default function useTopicContextActions({
|
||||||
topic,
|
topic,
|
||||||
chat,
|
chat,
|
||||||
|
isChatMuted,
|
||||||
wasOpened,
|
wasOpened,
|
||||||
canDelete,
|
canDelete,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
@ -20,6 +21,7 @@ export default function useTopicContextActions({
|
|||||||
}: {
|
}: {
|
||||||
topic: ApiTopic;
|
topic: ApiTopic;
|
||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
|
isChatMuted?: boolean;
|
||||||
wasOpened?: boolean;
|
wasOpened?: boolean;
|
||||||
canDelete?: boolean;
|
canDelete?: boolean;
|
||||||
handleDelete?: NoneToVoidFunction;
|
handleDelete?: NoneToVoidFunction;
|
||||||
@ -29,7 +31,7 @@ export default function useTopicContextActions({
|
|||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const {
|
const {
|
||||||
isPinned, isMuted, isClosed, id: topicId,
|
isPinned, notifySettings, isClosed, id: topicId,
|
||||||
} = topic;
|
} = topic;
|
||||||
|
|
||||||
const chatId = chat.id;
|
const chatId = chat.id;
|
||||||
@ -75,7 +77,7 @@ export default function useTopicContextActions({
|
|||||||
handler: () => toggleTopicPinned({ chatId, topicId, isPinned: true }),
|
handler: () => toggleTopicPinned({ chatId, topicId, isPinned: true }),
|
||||||
}) : undefined;
|
}) : undefined;
|
||||||
|
|
||||||
const actionMute = ((chat.isMuted && isMuted !== false) || isMuted === true)
|
const actionMute = ((isChatMuted && notifySettings.mutedUntil === undefined) || notifySettings.mutedUntil)
|
||||||
? {
|
? {
|
||||||
title: lang('ChatList.Unmute'),
|
title: lang('ChatList.Unmute'),
|
||||||
icon: 'unmute',
|
icon: 'unmute',
|
||||||
@ -114,5 +116,5 @@ export default function useTopicContextActions({
|
|||||||
actionCloseTopic,
|
actionCloseTopic,
|
||||||
actionDelete,
|
actionDelete,
|
||||||
]) as MenuItemContextAction[];
|
]) as MenuItemContextAction[];
|
||||||
}, [topic, chat, wasOpened, lang, canDelete, handleDelete, handleMute]);
|
}, [topic, chat, isChatMuted, wasOpened, lang, canDelete, handleDelete, handleMute]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,10 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
import type { ApiChat, ApiUser } from '../../../api/types';
|
import type { ApiChat, ApiUser } from '../../../api/types';
|
||||||
import { StoryViewerOrigin } from '../../../types';
|
import { StoryViewerOrigin } from '../../../types';
|
||||||
|
|
||||||
import { isUserId, selectIsChatMuted } from '../../../global/helpers';
|
import { isUserId } from '../../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectChat, selectIsChatPinned, selectNotifyExceptions,
|
selectChat, selectIsChatPinned, selectNotifyDefaults, selectNotifyException, selectUser,
|
||||||
selectNotifySettings, selectUser,
|
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||||
|
|
||||||
@ -156,9 +156,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
const user = selectUser(global, chatId);
|
const user = selectUser(global, chatId);
|
||||||
const isPinned = selectIsChatPinned(global, chatId);
|
const isPinned = selectIsChatPinned(global, chatId);
|
||||||
const isMuted = chat
|
const isMuted = chat && getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id));
|
||||||
? selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global))
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import type { FC } from '../../../lib/teact/teact';
|
|||||||
import React, { memo, useCallback, useEffect } from '../../../lib/teact/teact';
|
import React, { memo, useCallback, useEffect } from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
|
import type { ApiNotifyPeerType, ApiPeerNotifySettings } from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
checkIfNotificationsSupported,
|
checkIfNotificationsSupported,
|
||||||
checkIfOfflinePushFailed,
|
checkIfOfflinePushFailed,
|
||||||
@ -22,12 +24,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
hasPrivateChatsNotifications: boolean;
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>;
|
||||||
hasPrivateChatsMessagePreview: boolean;
|
|
||||||
hasGroupNotifications: boolean;
|
|
||||||
hasGroupMessagePreview: boolean;
|
|
||||||
hasBroadcastNotifications: boolean;
|
|
||||||
hasBroadcastMessagePreview: boolean;
|
|
||||||
hasContactJoinedNotifications: boolean;
|
hasContactJoinedNotifications: boolean;
|
||||||
hasWebNotifications: boolean;
|
hasWebNotifications: boolean;
|
||||||
hasPushNotifications: boolean;
|
hasPushNotifications: boolean;
|
||||||
@ -37,12 +34,7 @@ type StateProps = {
|
|||||||
const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
||||||
isActive,
|
isActive,
|
||||||
onReset,
|
onReset,
|
||||||
hasPrivateChatsNotifications,
|
notifyDefaults,
|
||||||
hasPrivateChatsMessagePreview,
|
|
||||||
hasGroupNotifications,
|
|
||||||
hasGroupMessagePreview,
|
|
||||||
hasBroadcastNotifications,
|
|
||||||
hasBroadcastMessagePreview,
|
|
||||||
hasContactJoinedNotifications,
|
hasContactJoinedNotifications,
|
||||||
hasPushNotifications,
|
hasPushNotifications,
|
||||||
hasWebNotifications,
|
hasWebNotifications,
|
||||||
@ -66,27 +58,18 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const handleSettingsChange = useCallback((
|
const handleSettingsChange = useCallback((
|
||||||
e: ChangeEvent<HTMLInputElement>,
|
e: ChangeEvent<HTMLInputElement>,
|
||||||
peerType: 'contact' | 'group' | 'broadcast',
|
peerType: ApiNotifyPeerType,
|
||||||
setting: 'silent' | 'showPreviews',
|
setting: 'mute' | 'showPreviews',
|
||||||
) => {
|
) => {
|
||||||
const currentIsSilent = peerType === 'contact'
|
const currentIsMuted = Boolean(notifyDefaults?.[peerType]?.mutedUntil);
|
||||||
? !hasPrivateChatsNotifications
|
const currentShouldShowPreviews = Boolean(notifyDefaults?.[peerType]?.shouldShowPreviews);
|
||||||
: !(peerType === 'group' ? hasGroupNotifications : hasBroadcastNotifications);
|
|
||||||
const currentShouldShowPreviews = peerType === 'contact'
|
|
||||||
? hasPrivateChatsMessagePreview
|
|
||||||
: (peerType === 'group' ? hasGroupMessagePreview : hasBroadcastMessagePreview);
|
|
||||||
|
|
||||||
updateNotificationSettings({
|
updateNotificationSettings({
|
||||||
peerType,
|
peerType,
|
||||||
...(setting === 'silent' && { isSilent: !e.target.checked, shouldShowPreviews: currentShouldShowPreviews }),
|
isMuted: setting === 'mute' ? !e.target.checked : currentIsMuted,
|
||||||
...(setting === 'showPreviews' && { shouldShowPreviews: e.target.checked, isSilent: currentIsSilent }),
|
shouldShowPreviews: setting === 'showPreviews' ? e.target.checked : currentShouldShowPreviews,
|
||||||
});
|
});
|
||||||
}, [
|
}, [notifyDefaults]);
|
||||||
hasBroadcastMessagePreview, hasBroadcastNotifications,
|
|
||||||
hasGroupMessagePreview, hasGroupNotifications,
|
|
||||||
hasPrivateChatsMessagePreview, hasPrivateChatsNotifications,
|
|
||||||
updateNotificationSettings,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleWebNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleWebNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const isEnabled = e.target.checked;
|
const isEnabled = e.target.checked;
|
||||||
@ -103,27 +86,27 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
}, [updateWebNotificationSettings]);
|
}, [updateWebNotificationSettings]);
|
||||||
|
|
||||||
const handlePrivateChatsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handlePrivateChatsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'contact', 'silent');
|
handleSettingsChange(e, 'users', 'mute');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handlePrivateChatsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handlePrivateChatsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'contact', 'showPreviews');
|
handleSettingsChange(e, 'users', 'showPreviews');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handleGroupsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleGroupsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'group', 'silent');
|
handleSettingsChange(e, 'groups', 'mute');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handleGroupsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleGroupsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'group', 'showPreviews');
|
handleSettingsChange(e, 'groups', 'showPreviews');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handleChannelsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleChannelsNotificationsChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'broadcast', 'silent');
|
handleSettingsChange(e, 'channels', 'mute');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handleChannelsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleChannelsPreviewChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
handleSettingsChange(e, 'broadcast', 'showPreviews');
|
handleSettingsChange(e, 'channels', 'showPreviews');
|
||||||
}, [handleSettingsChange]);
|
}, [handleSettingsChange]);
|
||||||
|
|
||||||
const handleContactNotificationChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleContactNotificationChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -186,17 +169,17 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('NotificationsForPrivateChats')}
|
label={lang('NotificationsForPrivateChats')}
|
||||||
subLabel={lang(hasPrivateChatsNotifications
|
subLabel={lang(notifyDefaults?.users?.mutedUntil
|
||||||
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
checked={hasPrivateChatsNotifications}
|
checked={Boolean(notifyDefaults?.users?.mutedUntil)}
|
||||||
onChange={handlePrivateChatsNotificationsChange}
|
onChange={handlePrivateChatsNotificationsChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('MessagePreview')}
|
label={lang('MessagePreview')}
|
||||||
disabled={!hasPrivateChatsNotifications}
|
disabled={!notifyDefaults?.users?.mutedUntil}
|
||||||
subLabel={lang(hasPrivateChatsMessagePreview
|
subLabel={lang(notifyDefaults?.users?.shouldShowPreviews
|
||||||
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
checked={hasPrivateChatsMessagePreview}
|
checked={Boolean(notifyDefaults?.users?.shouldShowPreviews)}
|
||||||
onChange={handlePrivateChatsPreviewChange}
|
onChange={handlePrivateChatsPreviewChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -206,15 +189,17 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('NotificationsForGroups')}
|
label={lang('NotificationsForGroups')}
|
||||||
subLabel={lang(hasGroupNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
subLabel={lang(notifyDefaults?.groups?.mutedUntil
|
||||||
checked={hasGroupNotifications}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
|
checked={Boolean(notifyDefaults?.groups?.mutedUntil)}
|
||||||
onChange={handleGroupsNotificationsChange}
|
onChange={handleGroupsNotificationsChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('MessagePreview')}
|
label={lang('MessagePreview')}
|
||||||
disabled={!hasGroupNotifications}
|
disabled={!notifyDefaults?.groups?.mutedUntil}
|
||||||
subLabel={lang(hasGroupMessagePreview ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
subLabel={lang(notifyDefaults?.groups?.shouldShowPreviews
|
||||||
checked={hasGroupMessagePreview}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
|
checked={Boolean(notifyDefaults?.groups?.shouldShowPreviews)}
|
||||||
onChange={handleGroupsPreviewChange}
|
onChange={handleGroupsPreviewChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -224,15 +209,17 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('NotificationsForChannels')}
|
label={lang('NotificationsForChannels')}
|
||||||
subLabel={lang(hasBroadcastNotifications ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
subLabel={lang(notifyDefaults?.channels?.mutedUntil
|
||||||
checked={hasBroadcastNotifications}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
|
checked={Boolean(notifyDefaults?.channels?.mutedUntil)}
|
||||||
onChange={handleChannelsNotificationsChange}
|
onChange={handleChannelsNotificationsChange}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('MessagePreview')}
|
label={lang('MessagePreview')}
|
||||||
disabled={!hasBroadcastNotifications}
|
disabled={!notifyDefaults?.channels?.mutedUntil}
|
||||||
subLabel={lang(hasBroadcastMessagePreview ? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
subLabel={lang(notifyDefaults?.channels?.shouldShowPreviews
|
||||||
checked={hasBroadcastMessagePreview}
|
? 'UserInfoNotificationsEnabled' : 'UserInfoNotificationsDisabled')}
|
||||||
|
checked={Boolean(notifyDefaults?.channels?.shouldShowPreviews)}
|
||||||
onChange={handleChannelsPreviewChange}
|
onChange={handleChannelsPreviewChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -253,12 +240,6 @@ const SettingsNotifications: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
return {
|
return {
|
||||||
hasPrivateChatsNotifications: Boolean(global.settings.byKey.hasPrivateChatsNotifications),
|
|
||||||
hasPrivateChatsMessagePreview: Boolean(global.settings.byKey.hasPrivateChatsMessagePreview),
|
|
||||||
hasGroupNotifications: Boolean(global.settings.byKey.hasGroupNotifications),
|
|
||||||
hasGroupMessagePreview: Boolean(global.settings.byKey.hasGroupMessagePreview),
|
|
||||||
hasBroadcastNotifications: Boolean(global.settings.byKey.hasBroadcastNotifications),
|
|
||||||
hasBroadcastMessagePreview: Boolean(global.settings.byKey.hasBroadcastMessagePreview),
|
|
||||||
hasContactJoinedNotifications: Boolean(global.settings.byKey.hasContactJoinedNotifications),
|
hasContactJoinedNotifications: Boolean(global.settings.byKey.hasContactJoinedNotifications),
|
||||||
hasWebNotifications: global.settings.byKey.hasWebNotifications,
|
hasWebNotifications: global.settings.byKey.hasWebNotifications,
|
||||||
hasPushNotifications: global.settings.byKey.hasPushNotifications,
|
hasPushNotifications: global.settings.byKey.hasPushNotifications,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { FC } from '../../lib/teact/teact';
|
|||||||
import React, { memo, useEffect, useRef } from '../../lib/teact/teact';
|
import React, { memo, useEffect, useRef } from '../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, withGlobal } from '../../global';
|
||||||
|
|
||||||
import type { MessageListType } from '../../types';
|
import type { MessageListType, ThreadId } from '../../types';
|
||||||
import { MAIN_THREAD_ID } from '../../api/types';
|
import { MAIN_THREAD_ID } from '../../api/types';
|
||||||
|
|
||||||
import { selectChat, selectCurrentMessageList, selectCurrentMiddleSearch } from '../../global/selectors';
|
import { selectChat, selectCurrentMessageList, selectCurrentMiddleSearch } from '../../global/selectors';
|
||||||
@ -24,6 +24,7 @@ type OwnProps = {
|
|||||||
type StateProps = {
|
type StateProps = {
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
messageListType?: MessageListType;
|
messageListType?: MessageListType;
|
||||||
|
threadId?: ThreadId;
|
||||||
unreadCount?: number;
|
unreadCount?: number;
|
||||||
unreadReactions?: number[];
|
unreadReactions?: number[];
|
||||||
unreadMentions?: number[];
|
unreadMentions?: number[];
|
||||||
@ -38,6 +39,7 @@ const FloatingActionButtons: FC<OwnProps & StateProps> = ({
|
|||||||
canPost,
|
canPost,
|
||||||
messageListType,
|
messageListType,
|
||||||
chatId,
|
chatId,
|
||||||
|
threadId,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
unreadReactions,
|
unreadReactions,
|
||||||
unreadMentions,
|
unreadMentions,
|
||||||
@ -56,6 +58,16 @@ const FloatingActionButtons: FC<OwnProps & StateProps> = ({
|
|||||||
const hasUnreadReactions = Boolean(reactionsCount);
|
const hasUnreadReactions = Boolean(reactionsCount);
|
||||||
const hasUnreadMentions = Boolean(mentionsCount);
|
const hasUnreadMentions = Boolean(mentionsCount);
|
||||||
|
|
||||||
|
const handleReadAllReactions = useLastCallback(() => {
|
||||||
|
if (!chatId) return;
|
||||||
|
readAllReactions({ chatId, threadId });
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleReadAllMentions = useLastCallback(() => {
|
||||||
|
if (!chatId) return;
|
||||||
|
readAllMentions({ chatId, threadId });
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasUnreadReactions && chatId && !unreadReactions?.length) {
|
if (hasUnreadReactions && chatId && !unreadReactions?.length) {
|
||||||
fetchUnreadReactions({ chatId });
|
fetchUnreadReactions({ chatId });
|
||||||
@ -120,7 +132,7 @@ const FloatingActionButtons: FC<OwnProps & StateProps> = ({
|
|||||||
icon="heart-outline"
|
icon="heart-outline"
|
||||||
ariaLabelLang="AccDescrReactionMentionDown"
|
ariaLabelLang="AccDescrReactionMentionDown"
|
||||||
onClick={focusNextReaction}
|
onClick={focusNextReaction}
|
||||||
onReadAll={readAllReactions}
|
onReadAll={handleReadAllReactions}
|
||||||
unreadCount={reactionsCount}
|
unreadCount={reactionsCount}
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
styles.reactions,
|
styles.reactions,
|
||||||
@ -133,7 +145,7 @@ const FloatingActionButtons: FC<OwnProps & StateProps> = ({
|
|||||||
icon="mention"
|
icon="mention"
|
||||||
ariaLabelLang="AccDescrMentionDown"
|
ariaLabelLang="AccDescrMentionDown"
|
||||||
onClick={focusNextMention}
|
onClick={focusNextMention}
|
||||||
onReadAll={readAllMentions}
|
onReadAll={handleReadAllMentions}
|
||||||
unreadCount={mentionsCount}
|
unreadCount={mentionsCount}
|
||||||
className={!hasUnreadMentions && styles.hidden}
|
className={!hasUnreadMentions && styles.hidden}
|
||||||
/>
|
/>
|
||||||
@ -166,6 +178,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
return {
|
return {
|
||||||
messageListType,
|
messageListType,
|
||||||
chatId,
|
chatId,
|
||||||
|
threadId,
|
||||||
reactionsCount: shouldShowCount ? chat.unreadReactionsCount : undefined,
|
reactionsCount: shouldShowCount ? chat.unreadReactionsCount : undefined,
|
||||||
unreadReactions: shouldShowCount ? chat.unreadReactions : undefined,
|
unreadReactions: shouldShowCount ? chat.unreadReactions : undefined,
|
||||||
unreadMentions: shouldShowCount ? chat.unreadMentions : undefined,
|
unreadMentions: shouldShowCount ? chat.unreadMentions : undefined,
|
||||||
|
|||||||
@ -20,8 +20,8 @@ import {
|
|||||||
isSystemBot,
|
isSystemBot,
|
||||||
isUserId,
|
isUserId,
|
||||||
isUserRightBanned,
|
isUserRightBanned,
|
||||||
selectIsChatMuted,
|
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectBot,
|
selectBot,
|
||||||
selectCanGift,
|
selectCanGift,
|
||||||
@ -32,8 +32,8 @@ import {
|
|||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectIsChatWithSelf,
|
selectIsChatWithSelf,
|
||||||
selectIsRightColumnShown,
|
selectIsRightColumnShown,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
selectNotifyException,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectTopic,
|
selectTopic,
|
||||||
selectUser,
|
selectUser,
|
||||||
@ -759,7 +759,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)),
|
isMuted: getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id)),
|
||||||
isPrivate,
|
isPrivate,
|
||||||
isTopic: chat?.isForum && !isMainThread,
|
isTopic: chat?.isForum && !isMainThread,
|
||||||
isForum: chat?.isForum,
|
isForum: chat?.isForum,
|
||||||
|
|||||||
@ -86,7 +86,7 @@ export default function useMessageObservers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mentionIds.length) {
|
if (mentionIds.length) {
|
||||||
markMentionsRead({ messageIds: mentionIds });
|
markMentionsRead({ chatId, messageIds: mentionIds });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reactionIds.length) {
|
if (reactionIds.length) {
|
||||||
|
|||||||
@ -227,9 +227,9 @@ const ActionMessage = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.hasUnreadMention) {
|
if (message.hasUnreadMention) {
|
||||||
markMentionsRead({ messageIds: [id] });
|
markMentionsRead({ chatId, messageIds: [id] });
|
||||||
}
|
}
|
||||||
}, [hasUnreadReaction, id, animateUnreadReaction, message.hasUnreadMention]);
|
}, [hasUnreadReaction, chatId, id, animateUnreadReaction, message.hasUnreadMention]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (action.type !== 'giftPremium') return;
|
if (action.type !== 'giftPremium') return;
|
||||||
|
|||||||
@ -869,9 +869,9 @@ const Message: FC<OwnProps & StateProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unreadMentionIds.length) {
|
if (unreadMentionIds.length) {
|
||||||
markMentionsRead({ messageIds: unreadMentionIds });
|
markMentionsRead({ chatId, messageIds: unreadMentionIds });
|
||||||
}
|
}
|
||||||
}, [hasUnreadReaction, album, messageId, animateUnreadReaction, message.hasUnreadMention]);
|
}, [hasUnreadReaction, album, chatId, messageId, animateUnreadReaction, message.hasUnreadMention]);
|
||||||
|
|
||||||
const albumLayout = useMemo(() => {
|
const albumLayout = useMemo(() => {
|
||||||
return isAlbum
|
return isAlbum
|
||||||
|
|||||||
@ -9,11 +9,12 @@ import type { ApiPhoto, ApiUser } from '../../../api/types';
|
|||||||
import { ManagementProgress } from '../../../types';
|
import { ManagementProgress } from '../../../types';
|
||||||
|
|
||||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||||
import { isUserBot, selectIsChatMuted } from '../../../global/helpers';
|
import { isUserBot } from '../../../global/helpers';
|
||||||
|
import { getIsChatMuted } from '../../../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
selectNotifyException,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectUser,
|
selectUser,
|
||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
@ -296,7 +297,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const chat = selectChat(global, userId);
|
const chat = selectChat(global, userId);
|
||||||
const userFullInfo = selectUserFullInfo(global, userId);
|
const userFullInfo = selectUserFullInfo(global, userId);
|
||||||
const { progress } = selectTabState(global).management;
|
const { progress } = selectTabState(global).management;
|
||||||
const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
|
const isMuted = chat && getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id));
|
||||||
const personalPhoto = userFullInfo?.personalPhoto;
|
const personalPhoto = userFullInfo?.personalPhoto;
|
||||||
const notPersonalPhoto = userFullInfo?.profilePhoto || userFullInfo?.fallbackPhoto;
|
const notPersonalPhoto = userFullInfo?.profilePhoto || userFullInfo?.fallbackPhoto;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type {
|
import type {
|
||||||
ApiChat, ApiChatFolder, ApiChatlistExportedInvite,
|
ApiChat, ApiChatFolder, ApiChatlistExportedInvite,
|
||||||
ApiChatMember, ApiError, ApiMissingInvitedUser,
|
ApiChatMember, ApiError, ApiMissingInvitedUser,
|
||||||
|
ApiTopic,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { RequiredGlobalActions } from '../../index';
|
import type { RequiredGlobalActions } from '../../index';
|
||||||
import type {
|
import type {
|
||||||
@ -60,6 +61,7 @@ import {
|
|||||||
addChatMembers,
|
addChatMembers,
|
||||||
addChats,
|
addChats,
|
||||||
addMessages,
|
addMessages,
|
||||||
|
addNotifyExceptions,
|
||||||
addSimilarBots,
|
addSimilarBots,
|
||||||
addUsers,
|
addUsers,
|
||||||
addUserStatuses,
|
addUserStatuses,
|
||||||
@ -221,7 +223,7 @@ addActionHandler('openChat', (global, actions, payload): ActionReturnType => {
|
|||||||
const chat = selectChat(global, id);
|
const chat = selectChat(global, id);
|
||||||
|
|
||||||
if (chat?.hasUnreadMark) {
|
if (chat?.hasUnreadMark) {
|
||||||
actions.toggleChatUnread({ id });
|
actions.markChatRead({ id });
|
||||||
}
|
}
|
||||||
|
|
||||||
const isChatOnlySummary = !selectChatLastMessageId(global, id);
|
const isChatOnlySummary = !selectChatLastMessageId(global, id);
|
||||||
@ -623,32 +625,26 @@ addActionHandler('requestSavedDialogUpdate', async (global, actions, payload): P
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('updateChatMutedState', (global, actions, payload): ActionReturnType => {
|
addActionHandler('updateChatMutedState', (global, actions, payload): ActionReturnType => {
|
||||||
const { chatId, muteUntil = 0 } = payload;
|
const { chatId, isMuted, mutedUntil } = payload;
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMuted = payload.isMuted ?? muteUntil > 0;
|
void callApi('updateChatMutedState', { chat, isMuted, mutedUntil });
|
||||||
|
|
||||||
global = updateChat(global, chatId, { isMuted });
|
|
||||||
setGlobal(global);
|
|
||||||
void callApi('updateChatMutedState', { chat, isMuted, muteUntil });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('updateTopicMutedState', (global, actions, payload): ActionReturnType => {
|
addActionHandler('updateTopicMutedState', (global, actions, payload): ActionReturnType => {
|
||||||
const { chatId, topicId, muteUntil = 0 } = payload;
|
const {
|
||||||
|
chatId, topicId, isMuted, mutedUntil,
|
||||||
|
} = payload;
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMuted = payload.isMuted ?? muteUntil > 0;
|
|
||||||
|
|
||||||
global = updateTopic(global, chatId, topicId, { isMuted });
|
|
||||||
setGlobal(global);
|
|
||||||
void callApi('updateTopicMutedState', {
|
void callApi('updateTopicMutedState', {
|
||||||
chat, topicId, isMuted, muteUntil,
|
chat, topicId, isMuted, mutedUntil,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1155,17 +1151,47 @@ addActionHandler('deleteChatFolder', async (global, actions, payload): Promise<v
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('toggleChatUnread', (global, actions, payload): ActionReturnType => {
|
addActionHandler('markChatUnread', (global, actions, payload): ActionReturnType => {
|
||||||
const { id } = payload;
|
const { id } = payload;
|
||||||
const chat = selectChat(global, id);
|
const chat = selectChat(global, id);
|
||||||
if (chat) {
|
if (!chat) return;
|
||||||
if (chat.unreadCount) {
|
void callApi('toggleDialogUnread', {
|
||||||
void callApi('markMessageListRead', { chat, threadId: MAIN_THREAD_ID });
|
chat,
|
||||||
} else {
|
hasUnreadMark: !chat.hasUnreadMark,
|
||||||
void callApi('toggleDialogUnread', {
|
});
|
||||||
chat,
|
});
|
||||||
hasUnreadMark: !chat.hasUnreadMark,
|
|
||||||
});
|
addActionHandler('markChatRead', async (global, actions, payload): Promise<void> => {
|
||||||
|
const { id } = payload;
|
||||||
|
const chat = selectChat(global, id);
|
||||||
|
if (!chat) return;
|
||||||
|
if (!chat.isForum) {
|
||||||
|
await callApi('markMessageListRead', { chat, threadId: MAIN_THREAD_ID });
|
||||||
|
actions.readAllMentions({ chatId: id });
|
||||||
|
actions.readAllReactions({ chatId: id });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasMoreTopics = true;
|
||||||
|
let lastTopic: ApiTopic | undefined;
|
||||||
|
let processedCount = 0;
|
||||||
|
|
||||||
|
while (hasMoreTopics) {
|
||||||
|
const result = await callApi('fetchTopics', {
|
||||||
|
chat, offsetDate: lastTopic?.date, offsetTopicId: lastTopic?.id, offsetId: lastTopic?.lastMessageId, limit: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result?.topics?.length) return;
|
||||||
|
|
||||||
|
result.topics.forEach((topic) => {
|
||||||
|
if (!topic.unreadCount && !topic.unreadMentionsCount && !topic.unreadReactionsCount) return;
|
||||||
|
actions.markTopicRead({ chatId: id, topicId: topic.id });
|
||||||
|
});
|
||||||
|
|
||||||
|
lastTopic = result.topics[result.topics.length - 1];
|
||||||
|
processedCount += result.topics.length;
|
||||||
|
if (result.count <= processedCount) {
|
||||||
|
hasMoreTopics = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1185,6 +1211,8 @@ addActionHandler('markTopicRead', (global, actions, payload): ActionReturnType =
|
|||||||
threadId: topicId,
|
threadId: topicId,
|
||||||
maxId: lastTopicMessageId,
|
maxId: lastTopicMessageId,
|
||||||
});
|
});
|
||||||
|
actions.readAllMentions({ chatId, threadId: topicId });
|
||||||
|
actions.readAllReactions({ chatId, threadId: topicId });
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateTopic(global, chatId, topicId, {
|
global = updateTopic(global, chatId, topicId, {
|
||||||
@ -2910,6 +2938,7 @@ async function loadChats(
|
|||||||
global = updateChatListSecondaryInfo(global, listType, result);
|
global = updateChatListSecondaryInfo(global, listType, result);
|
||||||
global = replaceMessages(global, result.messages);
|
global = replaceMessages(global, result.messages);
|
||||||
global = updateChatsLastMessageId(global, result.lastMessageByChatId, listType);
|
global = updateChatsLastMessageId(global, result.lastMessageByChatId, listType);
|
||||||
|
global = addNotifyExceptions(global, result.notifyExceptionById);
|
||||||
|
|
||||||
if (!shouldIgnorePagination) {
|
if (!shouldIgnorePagination) {
|
||||||
global = replaceChatListLoadingParameters(
|
global = replaceChatListLoadingParameters(
|
||||||
|
|||||||
@ -1818,12 +1818,11 @@ async function fetchUnreadMentions<T extends GlobalState>(global: T, chatId: str
|
|||||||
}
|
}
|
||||||
|
|
||||||
addActionHandler('markMentionsRead', (global, actions, payload): ActionReturnType => {
|
addActionHandler('markMentionsRead', (global, actions, payload): ActionReturnType => {
|
||||||
const { messageIds, tabId = getCurrentTabId() } = payload;
|
const { chatId, messageIds, tabId = getCurrentTabId() } = payload;
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
const chat = selectCurrentChat(global, tabId);
|
|
||||||
if (!chat) return;
|
if (!chat) return;
|
||||||
|
|
||||||
global = removeUnreadMentions(global, chat.id, chat, messageIds, true);
|
global = removeUnreadMentions(global, chatId, chat, messageIds, true);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
actions.markMessagesRead({ messageIds, tabId });
|
actions.markMessagesRead({ messageIds, tabId });
|
||||||
@ -1848,17 +1847,22 @@ addActionHandler('focusNextMention', async (global, actions, payload): Promise<v
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('readAllMentions', (global, actions, payload): ActionReturnType => {
|
addActionHandler('readAllMentions', (global, actions, payload): ActionReturnType => {
|
||||||
const { tabId = getCurrentTabId() } = payload || {};
|
const { chatId, threadId = MAIN_THREAD_ID } = payload;
|
||||||
|
|
||||||
const chat = selectCurrentChat(global, tabId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) return undefined;
|
if (!chat) return undefined;
|
||||||
|
|
||||||
callApi('readAllMentions', { chat });
|
callApi('readAllMentions', { chat, threadId: threadId === MAIN_THREAD_ID ? undefined : threadId });
|
||||||
|
|
||||||
return updateChat(global, chat.id, {
|
if (threadId === MAIN_THREAD_ID) {
|
||||||
unreadMentionsCount: undefined,
|
return updateChat(global, chat.id, {
|
||||||
unreadMentions: undefined,
|
unreadMentionsCount: undefined,
|
||||||
});
|
unreadMentions: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO[Forums]: Support mentions in threads
|
||||||
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
|
addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { ApiError, ApiReaction, ApiReactionEmoji } from '../../../api/types';
|
import type { ApiError, ApiReaction, ApiReactionEmoji } from '../../../api/types';
|
||||||
import type { ActionReturnType } from '../../types';
|
import type { ActionReturnType } from '../../types';
|
||||||
import { ApiMediaFormat } from '../../../api/types';
|
import { ApiMediaFormat, MAIN_THREAD_ID } from '../../../api/types';
|
||||||
|
|
||||||
import { GENERAL_REFETCH_INTERVAL } from '../../../config';
|
import { GENERAL_REFETCH_INTERVAL } from '../../../config';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
@ -557,16 +557,21 @@ addActionHandler('focusNextReaction', (global, actions, payload): ActionReturnTy
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('readAllReactions', (global, actions, payload): ActionReturnType => {
|
addActionHandler('readAllReactions', (global, actions, payload): ActionReturnType => {
|
||||||
const { tabId = getCurrentTabId() } = payload || {};
|
const { chatId, threadId = MAIN_THREAD_ID } = payload;
|
||||||
const chat = selectCurrentChat(global, tabId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) return undefined;
|
if (!chat) return undefined;
|
||||||
|
|
||||||
callApi('readAllReactions', { chat });
|
callApi('readAllReactions', { chat, threadId: threadId === MAIN_THREAD_ID ? undefined : threadId });
|
||||||
|
|
||||||
return updateUnreadReactions(global, chat.id, {
|
if (threadId === MAIN_THREAD_ID) {
|
||||||
unreadReactionsCount: undefined,
|
return updateUnreadReactions(global, chat.id, {
|
||||||
unreadReactions: undefined,
|
unreadReactionsCount: undefined,
|
||||||
});
|
unreadReactions: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO[Forums]: Support unread reactions in threads
|
||||||
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('loadTopReactions', async (global): Promise<void> => {
|
addActionHandler('loadTopReactions', async (global): Promise<void> => {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
UPLOADING_WALLPAPER_SLUG,
|
UPLOADING_WALLPAPER_SLUG,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
|
||||||
import { APP_CONFIG_REFETCH_INTERVAL, COUNTRIES_WITH_12H_TIME_FORMAT } from '../../../config';
|
import { APP_CONFIG_REFETCH_INTERVAL, COUNTRIES_WITH_12H_TIME_FORMAT, MAX_INT_32 } from '../../../config';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||||
import { requestPermission, subscribe, unsubscribe } from '../../../util/notifications';
|
import { requestPermission, subscribe, unsubscribe } from '../../../util/notifications';
|
||||||
@ -16,9 +16,9 @@ import { callApi } from '../../../api/gramjs';
|
|||||||
import { buildApiInputPrivacyRules } from '../../helpers';
|
import { buildApiInputPrivacyRules } from '../../helpers';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
addBlockedUser, addNotifyExceptions, deletePeerPhoto,
|
addBlockedUser, addNotifyException, addNotifyExceptions, deletePeerPhoto,
|
||||||
removeBlockedUser, replaceSettings, updateChat,
|
removeBlockedUser, replaceSettings, updateChat,
|
||||||
updateNotifySettings, updateUser, updateUserFullInfo,
|
updateUser, updateUserFullInfo,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import {
|
import {
|
||||||
@ -306,26 +306,40 @@ addActionHandler('loadNotificationExceptions', async (global): Promise<void> =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('loadNotificationSettings', async (global): Promise<void> => {
|
addActionHandler('loadNotificationSettings', async (global): Promise<void> => {
|
||||||
const result = await callApi('fetchNotificationSettings');
|
const [signUpNotification, notifyDefaults] = await Promise.all([
|
||||||
if (!result) {
|
callApi('fetchContactSignUpSetting'),
|
||||||
return;
|
callApi('fetchNotifyDefaultSettings'),
|
||||||
}
|
]);
|
||||||
|
|
||||||
|
if (!notifyDefaults) return;
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = replaceSettings(global, result);
|
global = replaceSettings(global, {
|
||||||
|
hasContactJoinedNotifications: signUpNotification,
|
||||||
|
});
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
settings: {
|
||||||
|
...global.settings,
|
||||||
|
notifyDefaults,
|
||||||
|
},
|
||||||
|
};
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('updateNotificationSettings', async (global, actions, payload): Promise<void> => {
|
addActionHandler('updateNotificationSettings', async (global, actions, payload): Promise<void> => {
|
||||||
const { peerType, isSilent, shouldShowPreviews } = payload!;
|
const { peerType, isMuted, shouldShowPreviews } = payload!;
|
||||||
|
|
||||||
const result = await callApi('updateNotificationSettings', peerType, { isSilent, shouldShowPreviews });
|
const result = await callApi('updateNotificationSettings', peerType, { isMuted, shouldShowPreviews });
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateNotifySettings(global, peerType, isSilent, shouldShowPreviews);
|
global = addNotifyException(global, peerType, {
|
||||||
|
mutedUntil: isMuted ? MAX_INT_32 : undefined,
|
||||||
|
shouldShowPreviews,
|
||||||
|
});
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -582,12 +596,11 @@ addActionHandler('loadCountryList', async (global, actions, payload): Promise<vo
|
|||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('ensureTimeFormat', async (global, actions, payload): Promise<void> => {
|
addActionHandler('ensureTimeFormat', async (global, actions): Promise<void> => {
|
||||||
const { tabId = getCurrentTabId() } = payload || {};
|
|
||||||
if (global.authNearestCountry) {
|
if (global.authNearestCountry) {
|
||||||
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT
|
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT
|
||||||
.has(global.authNearestCountry.toUpperCase()) ? '12h' : '24h';
|
.has(global.authNearestCountry.toUpperCase()) ? '12h' : '24h';
|
||||||
actions.setSettingOption({ timeFormat, tabId });
|
actions.setSettingOption({ timeFormat });
|
||||||
setTimeFormat(timeFormat);
|
setTimeFormat(timeFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -598,7 +611,7 @@ addActionHandler('ensureTimeFormat', async (global, actions, payload): Promise<v
|
|||||||
const nearestCountryCode = await callApi('fetchNearestCountry');
|
const nearestCountryCode = await callApi('fetchNearestCountry');
|
||||||
if (nearestCountryCode) {
|
if (nearestCountryCode) {
|
||||||
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(nearestCountryCode.toUpperCase()) ? '12h' : '24h';
|
const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(nearestCountryCode.toUpperCase()) ? '12h' : '24h';
|
||||||
actions.setSettingOption({ timeFormat, tabId });
|
actions.setSettingOption({ timeFormat });
|
||||||
setTimeFormat(timeFormat);
|
setTimeFormat(timeFormat);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,37 +2,33 @@ import type { ActionReturnType } from '../../types';
|
|||||||
|
|
||||||
import { addActionHandler, setGlobal } from '../../index';
|
import { addActionHandler, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
addNotifyException, updateChat, updateNotifySettings,
|
addNotifyException,
|
||||||
|
updateNotifyDefaults,
|
||||||
updateTopic,
|
updateTopic,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
|
|
||||||
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||||
switch (update['@type']) {
|
switch (update['@type']) {
|
||||||
case 'updateNotifySettings': {
|
case 'updateDefaultNotifySettings': {
|
||||||
return updateNotifySettings(global, update.peerType, update.isSilent, update.shouldShowPreviews);
|
return updateNotifyDefaults(global, update.peerType, update.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'updateNotifyExceptions': {
|
case 'updateChatNotifySettings': {
|
||||||
const {
|
const {
|
||||||
chatId, isMuted, isSilent, shouldShowPreviews,
|
chatId, settings,
|
||||||
} = update;
|
} = update;
|
||||||
const chat = global.chats.byId[chatId];
|
|
||||||
|
|
||||||
if (chat) {
|
global = addNotifyException(global, chatId, settings);
|
||||||
global = updateChat(global, chatId, { isMuted });
|
|
||||||
}
|
|
||||||
|
|
||||||
global = addNotifyException(global, chatId, { isMuted, isSilent, shouldShowPreviews });
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'updateTopicNotifyExceptions': {
|
case 'updateTopicNotifySettings': {
|
||||||
const {
|
const {
|
||||||
chatId, topicId, isMuted,
|
chatId, topicId, settings,
|
||||||
} = update;
|
} = update;
|
||||||
|
|
||||||
global = updateTopic(global, chatId, topicId, { isMuted });
|
global = updateTopic(global, chatId, topicId, { notifySettings: settings });
|
||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -24,7 +24,10 @@ import { replaceSettings } from '../../reducers';
|
|||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import {
|
import {
|
||||||
selectCanAnimateInterface,
|
selectCanAnimateInterface,
|
||||||
selectNotifySettings, selectPerformanceSettings, selectTabState, selectTheme,
|
selectPerformanceSettings,
|
||||||
|
selectSettingsKeys,
|
||||||
|
selectTabState,
|
||||||
|
selectTheme,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
|
|
||||||
const HISTORY_ANIMATION_DURATION = 450;
|
const HISTORY_ANIMATION_DURATION = 450;
|
||||||
@ -100,7 +103,7 @@ addActionHandler('initShared', (): ActionReturnType => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('initMain', (global): ActionReturnType => {
|
addActionHandler('initMain', (global): ActionReturnType => {
|
||||||
const { hasWebNotifications, hasPushNotifications } = selectNotifySettings(global);
|
const { hasWebNotifications, hasPushNotifications } = selectSettingsKeys(global);
|
||||||
if (hasWebNotifications && hasPushNotifications) {
|
if (hasWebNotifications && hasPushNotifications) {
|
||||||
// Most of the browsers only show the notifications permission prompt after the first user gesture.
|
// Most of the browsers only show the notifications permission prompt after the first user gesture.
|
||||||
const events = ['click', 'keypress'];
|
const events = ['click', 'keypress'];
|
||||||
|
|||||||
@ -300,6 +300,10 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
|
|||||||
|
|
||||||
cached.cacheVersion = 2;
|
cached.cacheVersion = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cached.chats.notifyExceptionById) {
|
||||||
|
cached.chats.notifyExceptionById = initialState.chats.notifyExceptionById;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCache(force?: boolean) {
|
function updateCache(force?: boolean) {
|
||||||
@ -494,6 +498,7 @@ function reduceChats<T extends GlobalState>(global: T): GlobalState['chats'] {
|
|||||||
similarChannelsById: {},
|
similarChannelsById: {},
|
||||||
similarBotsById: {},
|
similarBotsById: {},
|
||||||
isFullyLoaded: {},
|
isFullyLoaded: {},
|
||||||
|
notifyExceptionById: {},
|
||||||
loadingParameters: INITIAL_GLOBAL_STATE.chats.loadingParameters,
|
loadingParameters: INITIAL_GLOBAL_STATE.chats.loadingParameters,
|
||||||
byId: pickTruthy(global.chats.byId, idsToSave),
|
byId: pickTruthy(global.chats.byId, idsToSave),
|
||||||
fullInfoById: pickTruthy(global.chats.fullInfoById, idsToSave),
|
fullInfoById: pickTruthy(global.chats.fullInfoById, idsToSave),
|
||||||
@ -662,7 +667,6 @@ function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings
|
|||||||
themes,
|
themes,
|
||||||
performance,
|
performance,
|
||||||
privacy: {},
|
privacy: {},
|
||||||
notifyExceptions: {},
|
|
||||||
botVerificationShownPeerIds,
|
botVerificationShownPeerIds,
|
||||||
miniAppsCachedPosition,
|
miniAppsCachedPosition,
|
||||||
miniAppsCachedSize,
|
miniAppsCachedSize,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import type {
|
|||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { OldLangFn } from '../../hooks/useOldLang';
|
import type { OldLangFn } from '../../hooks/useOldLang';
|
||||||
import type {
|
import type {
|
||||||
CustomPeer, NotifyException, NotifySettings, ThreadId,
|
CustomPeer, ThreadId,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type { LangFn } from '../../util/localization';
|
import type { LangFn } from '../../util/localization';
|
||||||
import { MAIN_THREAD_ID } from '../../api/types';
|
import { MAIN_THREAD_ID } from '../../api/types';
|
||||||
@ -306,40 +306,6 @@ export function isChatArchived(chat: ApiChat) {
|
|||||||
return chat.folderId === ARCHIVED_FOLDER_ID;
|
return chat.folderId === ARCHIVED_FOLDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectIsChatMuted(
|
|
||||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions: Record<string, NotifyException> = {},
|
|
||||||
) {
|
|
||||||
// If this chat is in exceptions they take precedence
|
|
||||||
if (notifyExceptions[chat.id] && notifyExceptions[chat.id].isMuted !== undefined) {
|
|
||||||
return notifyExceptions[chat.id].isMuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
chat.isMuted
|
|
||||||
|| (isUserId(chat.id) && !notifySettings.hasPrivateChatsNotifications)
|
|
||||||
|| (isChatChannel(chat) && !notifySettings.hasBroadcastNotifications)
|
|
||||||
|| (isChatGroup(chat) && !notifySettings.hasGroupNotifications)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function selectShouldShowMessagePreview(
|
|
||||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions: Record<string, NotifyException> = {},
|
|
||||||
) {
|
|
||||||
const {
|
|
||||||
hasPrivateChatsMessagePreview = true,
|
|
||||||
hasBroadcastMessagePreview = true,
|
|
||||||
hasGroupMessagePreview = true,
|
|
||||||
} = notifySettings;
|
|
||||||
// If this chat is in exceptions they take precedence
|
|
||||||
if (notifyExceptions[chat.id] && notifyExceptions[chat.id].shouldShowPreviews !== undefined) {
|
|
||||||
return notifyExceptions[chat.id].shouldShowPreviews;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (isUserId(chat.id) && hasPrivateChatsMessagePreview)
|
|
||||||
|| (isChatChannel(chat) && hasBroadcastMessagePreview)
|
|
||||||
|| (isChatGroup(chat) && hasGroupMessagePreview);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCanDeleteChat(chat: ApiChat) {
|
export function getCanDeleteChat(chat: ApiChat) {
|
||||||
return isChatBasicGroup(chat) || ((isChatSuperGroup(chat) || isChatChannel(chat)) && chat.isCreator);
|
return isChatBasicGroup(chat) || ((isChatSuperGroup(chat) || isChatChannel(chat)) && chat.isCreator);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import type { ApiInputPrivacyRules, BotsPrivacyType, PrivacyVisibility } from '../../api/types';
|
import type {
|
||||||
|
ApiInputPrivacyRules,
|
||||||
|
BotsPrivacyType,
|
||||||
|
PrivacyVisibility,
|
||||||
|
} from '../../api/types';
|
||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
|
|
||||||
import { partition } from '../../util/iteratees';
|
import { partition } from '../../util/iteratees';
|
||||||
|
|||||||
65
src/global/helpers/notifications.ts
Normal file
65
src/global/helpers/notifications.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import type {
|
||||||
|
ApiChat,
|
||||||
|
ApiNotifyPeerType,
|
||||||
|
ApiPeer,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
|
} from '../../api/types';
|
||||||
|
|
||||||
|
import { omitUndefined } from '../../util/iteratees';
|
||||||
|
import { getServerTime } from '../../util/serverTime';
|
||||||
|
import { isChatChannel, isUserId } from './chats';
|
||||||
|
|
||||||
|
export function getIsChatMuted(
|
||||||
|
chat: ApiChat,
|
||||||
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>,
|
||||||
|
notifyException?: ApiPeerNotifySettings,
|
||||||
|
) {
|
||||||
|
const settings = getChatNotifySettings(chat, notifyDefaults, notifyException);
|
||||||
|
if (!settings?.mutedUntil) return false;
|
||||||
|
return getServerTime() < settings.mutedUntil;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIsChatSilent(
|
||||||
|
chat: ApiChat,
|
||||||
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>,
|
||||||
|
notifyException?: ApiPeerNotifySettings,
|
||||||
|
) {
|
||||||
|
const settings = getChatNotifySettings(chat, notifyDefaults, notifyException);
|
||||||
|
if (!settings) return false;
|
||||||
|
return !settings.hasSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getShouldShowMessagePreview(
|
||||||
|
chat: ApiChat,
|
||||||
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>,
|
||||||
|
notifyException?: ApiPeerNotifySettings,
|
||||||
|
) {
|
||||||
|
const settings = getChatNotifySettings(chat, notifyDefaults, notifyException);
|
||||||
|
return Boolean(settings?.shouldShowPreviews);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChatNotifySettings(
|
||||||
|
chat: ApiChat,
|
||||||
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>,
|
||||||
|
notifyException?: ApiPeerNotifySettings,
|
||||||
|
): ApiPeerNotifySettings | undefined {
|
||||||
|
const defaults = notifyDefaults?.[getNotificationPeerType(chat)];
|
||||||
|
|
||||||
|
if (!notifyException && !defaults) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...defaults,
|
||||||
|
...(notifyException && omitUndefined(notifyException)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNotificationPeerType(peer: ApiPeer): ApiNotifyPeerType {
|
||||||
|
if (isUserId(peer.id)) {
|
||||||
|
return 'users';
|
||||||
|
}
|
||||||
|
|
||||||
|
const chat = peer as ApiChat;
|
||||||
|
return isChatChannel(chat) ? 'channels' : 'groups';
|
||||||
|
}
|
||||||
@ -122,6 +122,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
similarChannelsById: {},
|
similarChannelsById: {},
|
||||||
similarBotsById: {},
|
similarBotsById: {},
|
||||||
topicsInfoById: {},
|
topicsInfoById: {},
|
||||||
|
notifyExceptionById: {},
|
||||||
loadingParameters: {
|
loadingParameters: {
|
||||||
active: {},
|
active: {},
|
||||||
archived: {},
|
archived: {},
|
||||||
@ -297,7 +298,6 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
},
|
},
|
||||||
performance: INITIAL_PERFORMANCE_STATE_MAX,
|
performance: INITIAL_PERFORMANCE_STATE_MAX,
|
||||||
privacy: {},
|
privacy: {},
|
||||||
notifyExceptions: {},
|
|
||||||
botVerificationShownPeerIds: [],
|
botVerificationShownPeerIds: [],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { ApiNotifyException } from '../../api/types';
|
import type { ApiNotifyPeerType, ApiPeerNotifySettings } from '../../api/types';
|
||||||
import type {
|
import type {
|
||||||
ISettings, IThemeSettings, NotifyException,
|
ISettings, IThemeSettings,
|
||||||
ThemeKey,
|
ThemeKey,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
@ -39,52 +39,51 @@ export function replaceThemeSettings<T extends GlobalState>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function addNotifyExceptions<T extends GlobalState>(
|
export function addNotifyExceptions<T extends GlobalState>(
|
||||||
global: T, notifyExceptions: ApiNotifyException[],
|
global: T, notifyExceptionById: Record<string, ApiPeerNotifySettings>,
|
||||||
): T {
|
|
||||||
notifyExceptions.forEach((notifyException) => {
|
|
||||||
const { chatId, ...exceptionData } = notifyException;
|
|
||||||
global = addNotifyException(global, chatId, exceptionData);
|
|
||||||
});
|
|
||||||
|
|
||||||
return global;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addNotifyException<T extends GlobalState>(
|
|
||||||
global: T, id: string, notifyException: NotifyException,
|
|
||||||
): T {
|
): T {
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
settings: {
|
chats: {
|
||||||
...global.settings,
|
...global.chats,
|
||||||
notifyExceptions: {
|
notifyExceptionById: {
|
||||||
...global.settings.notifyExceptions,
|
...global.chats.notifyExceptionById,
|
||||||
|
...notifyExceptionById,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addNotifyException<T extends GlobalState>(
|
||||||
|
global: T, id: string, notifyException: ApiPeerNotifySettings,
|
||||||
|
): T {
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
chats: {
|
||||||
|
...global.chats,
|
||||||
|
notifyExceptionById: {
|
||||||
|
...global.chats.notifyExceptionById,
|
||||||
[id]: notifyException,
|
[id]: notifyException,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line consistent-return
|
export function updateNotifyDefaults<T extends GlobalState>(
|
||||||
export function updateNotifySettings<T extends GlobalState>(
|
global: T, peerType: ApiNotifyPeerType, settings: Partial<ApiPeerNotifySettings>,
|
||||||
global: T, peerType: 'contact' | 'group' | 'broadcast', isSilent?: boolean, shouldShowPreviews?: boolean,
|
|
||||||
): T {
|
): T {
|
||||||
switch (peerType) {
|
return {
|
||||||
case 'contact':
|
...global,
|
||||||
return replaceSettings(global, {
|
settings: {
|
||||||
...(typeof isSilent !== 'undefined' && { hasPrivateChatsNotifications: !isSilent }),
|
...global.settings,
|
||||||
...(typeof shouldShowPreviews !== 'undefined' && { hasPrivateChatsMessagePreview: shouldShowPreviews }),
|
notifyDefaults: {
|
||||||
});
|
...global.settings.notifyDefaults,
|
||||||
case 'group':
|
[peerType]: {
|
||||||
return replaceSettings(global, {
|
...global.settings.notifyDefaults?.[peerType],
|
||||||
...(typeof isSilent !== 'undefined' && { hasGroupNotifications: !isSilent }),
|
...settings,
|
||||||
...(typeof shouldShowPreviews !== 'undefined' && { hasGroupMessagePreview: shouldShowPreviews }),
|
},
|
||||||
});
|
},
|
||||||
case 'broadcast':
|
},
|
||||||
return replaceSettings(global, {
|
};
|
||||||
...(typeof isSilent !== 'undefined' && { hasBroadcastNotifications: !isSilent }),
|
|
||||||
...(typeof shouldShowPreviews !== 'undefined' && { hasBroadcastMessagePreview: shouldShowPreviews }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addBlockedUser<T extends GlobalState>(global: T, contactId: string): T {
|
export function addBlockedUser<T extends GlobalState>(global: T, contactId: string): T {
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
|
|
||||||
export function selectNotifySettings<T extends GlobalState>(global: T) {
|
export function selectNotifyDefaults<T extends GlobalState>(global: T) {
|
||||||
return global.settings.byKey;
|
return global.settings.notifyDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectNotifyExceptions<T extends GlobalState>(global: T) {
|
export function selectNotifyException<T extends GlobalState>(global: T, chatId: string) {
|
||||||
return global.settings.notifyExceptions;
|
return global.chats.notifyExceptionById?.[chatId];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectLanguageCode<T extends GlobalState>(global: T) {
|
export function selectLanguageCode<T extends GlobalState>(global: T) {
|
||||||
@ -13,7 +13,7 @@ export function selectLanguageCode<T extends GlobalState>(global: T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function selectCanSetPasscode<T extends GlobalState>(global: T) {
|
export function selectCanSetPasscode<T extends GlobalState>(global: T) {
|
||||||
return global.authRememberMe && global.isCacheApiSupported;
|
return global.authRememberMe;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectTranslationLanguage<T extends GlobalState>(global: T) {
|
export function selectTranslationLanguage<T extends GlobalState>(global: T) {
|
||||||
@ -27,3 +27,7 @@ export function selectNewNoncontactPeersRequirePremium<T extends GlobalState>(gl
|
|||||||
export function selectShouldHideReadMarks<T extends GlobalState>(global: T) {
|
export function selectShouldHideReadMarks<T extends GlobalState>(global: T) {
|
||||||
return global.settings.byKey.shouldHideReadMarks;
|
return global.settings.byKey.shouldHideReadMarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function selectSettingsKeys<T extends GlobalState>(global: T) {
|
||||||
|
return global.settings.byKey;
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import type {
|
|||||||
ApiMessageSearchContext,
|
ApiMessageSearchContext,
|
||||||
ApiNewPoll,
|
ApiNewPoll,
|
||||||
ApiNotification,
|
ApiNotification,
|
||||||
|
ApiNotifyPeerType,
|
||||||
ApiPaymentStatus,
|
ApiPaymentStatus,
|
||||||
ApiPhoto,
|
ApiPhoto,
|
||||||
ApiPremiumSection,
|
ApiPremiumSection,
|
||||||
@ -220,8 +221,8 @@ export interface ActionPayloads {
|
|||||||
isSilent: boolean;
|
isSilent: boolean;
|
||||||
};
|
};
|
||||||
updateNotificationSettings: {
|
updateNotificationSettings: {
|
||||||
peerType: 'contact' | 'group' | 'broadcast';
|
peerType: ApiNotifyPeerType;
|
||||||
isSilent?: boolean;
|
isMuted?: boolean;
|
||||||
shouldShowPreviews?: boolean;
|
shouldShowPreviews?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,7 +256,7 @@ export interface ActionPayloads {
|
|||||||
loadCountryList: {
|
loadCountryList: {
|
||||||
langCode?: string;
|
langCode?: string;
|
||||||
};
|
};
|
||||||
ensureTimeFormat: WithTabId | undefined;
|
ensureTimeFormat: undefined;
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
loadWebPagePreview: {
|
loadWebPagePreview: {
|
||||||
@ -365,7 +366,8 @@ export interface ActionPayloads {
|
|||||||
toggleChatArchived: {
|
toggleChatArchived: {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
toggleChatUnread: { id: string };
|
markChatUnread: { id: string };
|
||||||
|
markChatRead: { id: string };
|
||||||
loadChatFolders: undefined;
|
loadChatFolders: undefined;
|
||||||
loadRecommendedChatFolders: undefined;
|
loadRecommendedChatFolders: undefined;
|
||||||
editChatFolder: {
|
editChatFolder: {
|
||||||
@ -1047,7 +1049,7 @@ export interface ActionPayloads {
|
|||||||
updateChatMutedState: {
|
updateChatMutedState: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
isMuted?: boolean;
|
isMuted?: boolean;
|
||||||
muteUntil?: number;
|
mutedUntil?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
updateChat: {
|
updateChat: {
|
||||||
@ -1313,9 +1315,16 @@ export interface ActionPayloads {
|
|||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
focusNextReaction: WithTabId | undefined;
|
focusNextReaction: WithTabId | undefined;
|
||||||
focusNextMention: WithTabId | undefined;
|
focusNextMention: WithTabId | undefined;
|
||||||
readAllReactions: WithTabId | undefined;
|
readAllReactions: {
|
||||||
readAllMentions: WithTabId | undefined;
|
chatId: string;
|
||||||
|
threadId?: ThreadId;
|
||||||
|
};
|
||||||
|
readAllMentions: {
|
||||||
|
chatId: string;
|
||||||
|
threadId?: ThreadId;
|
||||||
|
};
|
||||||
markMentionsRead: {
|
markMentionsRead: {
|
||||||
|
chatId: string;
|
||||||
messageIds: number[];
|
messageIds: number[];
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
copyMessageLink: {
|
copyMessageLink: {
|
||||||
@ -2505,7 +2514,7 @@ export interface ActionPayloads {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
topicId: number;
|
topicId: number;
|
||||||
isMuted?: boolean;
|
isMuted?: boolean;
|
||||||
muteUntil?: number;
|
mutedUntil?: number;
|
||||||
};
|
};
|
||||||
setViewForumAsMessages: {
|
setViewForumAsMessages: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
|
|||||||
@ -15,8 +15,10 @@ import type {
|
|||||||
ApiGroupCall,
|
ApiGroupCall,
|
||||||
ApiLanguage,
|
ApiLanguage,
|
||||||
ApiMessage,
|
ApiMessage,
|
||||||
|
ApiNotifyPeerType,
|
||||||
ApiPaidReactionPrivacyType,
|
ApiPaidReactionPrivacyType,
|
||||||
ApiPeerColors,
|
ApiPeerColors,
|
||||||
|
ApiPeerNotifySettings,
|
||||||
ApiPeerPhotos,
|
ApiPeerPhotos,
|
||||||
ApiPeerStories,
|
ApiPeerStories,
|
||||||
ApiPhoneCall,
|
ApiPhoneCall,
|
||||||
@ -54,7 +56,6 @@ import type {
|
|||||||
EmojiKeywords,
|
EmojiKeywords,
|
||||||
ISettings,
|
ISettings,
|
||||||
IThemeSettings,
|
IThemeSettings,
|
||||||
NotifyException,
|
|
||||||
PerformanceType,
|
PerformanceType,
|
||||||
Point,
|
Point,
|
||||||
ServiceNotification,
|
ServiceNotification,
|
||||||
@ -221,6 +222,7 @@ export type GlobalState = {
|
|||||||
similarChannelIds?: string[];
|
similarChannelIds?: string[];
|
||||||
count?: number;
|
count?: number;
|
||||||
}>>;
|
}>>;
|
||||||
|
notifyExceptionById: Record<string, ApiPeerNotifySettings>;
|
||||||
|
|
||||||
similarBotsById: Record<string, SimilarBotsInfo>;
|
similarBotsById: Record<string, SimilarBotsInfo>;
|
||||||
};
|
};
|
||||||
@ -411,7 +413,7 @@ export type GlobalState = {
|
|||||||
loadedWallpapers?: ApiWallpaper[];
|
loadedWallpapers?: ApiWallpaper[];
|
||||||
themes: Partial<Record<ThemeKey, IThemeSettings>>;
|
themes: Partial<Record<ThemeKey, IThemeSettings>>;
|
||||||
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
|
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
|
||||||
notifyExceptions?: Record<number, NotifyException>;
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>;
|
||||||
lastPremiumBandwithNotificationDate?: number;
|
lastPremiumBandwithNotificationDate?: number;
|
||||||
paidReactionPrivacy?: ApiPaidReactionPrivacyType;
|
paidReactionPrivacy?: ApiPaidReactionPrivacyType;
|
||||||
languages?: ApiLanguage[];
|
languages?: ApiLanguage[];
|
||||||
|
|||||||
@ -79,7 +79,8 @@ const useChatContextActions = ({
|
|||||||
toggleSavedDialogPinned,
|
toggleSavedDialogPinned,
|
||||||
updateChatMutedState,
|
updateChatMutedState,
|
||||||
toggleChatArchived,
|
toggleChatArchived,
|
||||||
toggleChatUnread,
|
markChatRead,
|
||||||
|
markChatUnread,
|
||||||
openChatInNewTab,
|
openChatInNewTab,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
@ -149,10 +150,10 @@ const useChatContextActions = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const actionMaskAsRead = (chat.unreadCount || chat.hasUnreadMark)
|
const actionMaskAsRead = (chat.unreadCount || chat.hasUnreadMark)
|
||||||
? { title: lang('MarkAsRead'), icon: 'readchats', handler: () => toggleChatUnread({ id: chat.id }) }
|
? { title: lang('MarkAsRead'), icon: 'readchats', handler: () => markChatRead({ id: chat.id }) }
|
||||||
: undefined;
|
: undefined;
|
||||||
const actionMarkAsUnread = !(chat.unreadCount || chat.hasUnreadMark) && !chat.isForum
|
const actionMarkAsUnread = !(chat.unreadCount || chat.hasUnreadMark) && !chat.isForum
|
||||||
? { title: lang('MarkAsUnread'), icon: 'unread', handler: () => toggleChatUnread({ id: chat.id }) }
|
? { title: lang('MarkAsUnread'), icon: 'unread', handler: () => markChatUnread({ id: chat.id }) }
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const actionArchive = isChatArchived(chat)
|
const actionArchive = isChatArchived(chat)
|
||||||
|
|||||||
@ -76,19 +76,6 @@ export interface IThemeSettings {
|
|||||||
isBlurred?: boolean;
|
isBlurred?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotifySettings = {
|
|
||||||
hasPrivateChatsNotifications?: boolean;
|
|
||||||
hasPrivateChatsMessagePreview?: boolean;
|
|
||||||
hasGroupNotifications?: boolean;
|
|
||||||
hasGroupMessagePreview?: boolean;
|
|
||||||
hasBroadcastNotifications?: boolean;
|
|
||||||
hasBroadcastMessagePreview?: boolean;
|
|
||||||
hasContactJoinedNotifications?: boolean;
|
|
||||||
hasWebNotifications: boolean;
|
|
||||||
hasPushNotifications: boolean;
|
|
||||||
notificationSoundVolume: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LangCode = (
|
export type LangCode = (
|
||||||
'en' | 'ar' | 'be' | 'ca' | 'nl' | 'fr' | 'de' | 'id' | 'it' | 'ko' | 'ms' | 'fa' | 'pl' | 'pt-br' | 'ru' | 'es'
|
'en' | 'ar' | 'be' | 'ca' | 'nl' | 'fr' | 'de' | 'id' | 'it' | 'ko' | 'ms' | 'fa' | 'pl' | 'pt-br' | 'ru' | 'es'
|
||||||
| 'tr' | 'uk' | 'uz'
|
| 'tr' | 'uk' | 'uz'
|
||||||
@ -96,7 +83,7 @@ export type LangCode = (
|
|||||||
|
|
||||||
export type TimeFormat = '24h' | '12h';
|
export type TimeFormat = '24h' | '12h';
|
||||||
|
|
||||||
export interface ISettings extends NotifySettings, Record<string, any> {
|
export interface ISettings {
|
||||||
theme: ThemeKey;
|
theme: ThemeKey;
|
||||||
shouldUseSystemTheme: boolean;
|
shouldUseSystemTheme: boolean;
|
||||||
messageTextSize: number;
|
messageTextSize: number;
|
||||||
@ -139,6 +126,10 @@ export interface ISettings extends NotifySettings, Record<string, any> {
|
|||||||
shouldDebugExportedSenders?: boolean;
|
shouldDebugExportedSenders?: boolean;
|
||||||
shouldWarnAboutSvg?: boolean;
|
shouldWarnAboutSvg?: boolean;
|
||||||
shouldSkipWebAppCloseConfirmation: boolean;
|
shouldSkipWebAppCloseConfirmation: boolean;
|
||||||
|
hasContactJoinedNotifications?: boolean;
|
||||||
|
hasWebNotifications: boolean;
|
||||||
|
hasPushNotifications: boolean;
|
||||||
|
notificationSoundVolume: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IAnchorPosition = {
|
export type IAnchorPosition = {
|
||||||
@ -461,12 +452,6 @@ export enum ManagementScreens {
|
|||||||
|
|
||||||
export type ManagementType = 'user' | 'group' | 'channel' | 'bot';
|
export type ManagementType = 'user' | 'group' | 'channel' | 'bot';
|
||||||
|
|
||||||
export type NotifyException = {
|
|
||||||
isMuted: boolean;
|
|
||||||
isSilent?: boolean;
|
|
||||||
shouldShowPreviews?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type EmojiKeywords = {
|
export type EmojiKeywords = {
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
version?: number;
|
version?: number;
|
||||||
|
|||||||
@ -3,20 +3,18 @@ import { addCallback } from '../lib/teact/teactn';
|
|||||||
import { addActionHandler, getGlobal } from '../global';
|
import { addActionHandler, getGlobal } from '../global';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiChat, ApiChatFolder, ApiUser,
|
ApiChat, ApiChatFolder, ApiNotifyPeerType, ApiPeerNotifySettings, ApiUser,
|
||||||
} from '../api/types';
|
} from '../api/types';
|
||||||
import type { GlobalState } from '../global/types';
|
import type { GlobalState } from '../global/types';
|
||||||
import type { NotifyException, NotifySettings } from '../types';
|
|
||||||
import type { CallbackManager } from './callbacks';
|
import type { CallbackManager } from './callbacks';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, DEBUG, SAVED_FOLDER_ID, SERVICE_NOTIFICATIONS_USER_ID,
|
ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, DEBUG, SAVED_FOLDER_ID, SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { selectIsChatMuted } from '../global/helpers';
|
import { getIsChatMuted } from '../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectChatLastMessage,
|
selectChatLastMessage,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectTopics,
|
selectTopics,
|
||||||
} from '../global/selectors';
|
} from '../global/selectors';
|
||||||
@ -79,8 +77,8 @@ let prevGlobal: {
|
|||||||
chatsById: Record<string, ApiChat>;
|
chatsById: Record<string, ApiChat>;
|
||||||
foldersById: Record<string, ApiChatFolder>;
|
foldersById: Record<string, ApiChatFolder>;
|
||||||
usersById: Record<string, ApiUser>;
|
usersById: Record<string, ApiUser>;
|
||||||
notifySettings: NotifySettings;
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>;
|
||||||
notifyExceptions?: Record<number, NotifyException>;
|
notifyExceptions?: Record<number, ApiPeerNotifySettings>;
|
||||||
} = initials.prevGlobal;
|
} = initials.prevGlobal;
|
||||||
|
|
||||||
let prepared: {
|
let prepared: {
|
||||||
@ -219,8 +217,8 @@ function updateFolderManager(global: GlobalState) {
|
|||||||
const areAllLastMessageIdsChanged = global.chats.lastMessageIds.all !== prevGlobal.lastAllMessageIds;
|
const areAllLastMessageIdsChanged = global.chats.lastMessageIds.all !== prevGlobal.lastAllMessageIds;
|
||||||
const areTopicsChanged = global.chats.topicsInfoById !== prevGlobal.topicsInfoById;
|
const areTopicsChanged = global.chats.topicsInfoById !== prevGlobal.topicsInfoById;
|
||||||
const areUsersChanged = global.users.byId !== prevGlobal.usersById;
|
const areUsersChanged = global.users.byId !== prevGlobal.usersById;
|
||||||
const areNotifySettingsChanged = selectNotifySettings(global) !== prevGlobal.notifySettings;
|
const areNotifyDefaultsChanged = selectNotifyDefaults(global) !== prevGlobal.notifyDefaults;
|
||||||
const areNotifyExceptionsChanged = selectNotifyExceptions(global) !== prevGlobal.notifyExceptions;
|
const areNotifyExceptionsChanged = global.chats.notifyExceptionById !== prevGlobal.notifyExceptions;
|
||||||
|
|
||||||
let affectedFolderIds: number[] = [];
|
let affectedFolderIds: number[] = [];
|
||||||
|
|
||||||
@ -232,7 +230,7 @@ function updateFolderManager(global: GlobalState) {
|
|||||||
|
|
||||||
if (!(
|
if (!(
|
||||||
isAllFolderChanged || isArchivedFolderChanged || isSavedFolderChanged || areFoldersChanged
|
isAllFolderChanged || isArchivedFolderChanged || isSavedFolderChanged || areFoldersChanged
|
||||||
|| areChatsChanged || areUsersChanged || areTopicsChanged || areNotifySettingsChanged || areNotifyExceptionsChanged
|
|| areChatsChanged || areUsersChanged || areTopicsChanged || areNotifyDefaultsChanged || areNotifyExceptionsChanged
|
||||||
|| areSavedLastMessageIdsChanged || areAllLastMessageIdsChanged
|
|| areSavedLastMessageIdsChanged || areAllLastMessageIdsChanged
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -252,7 +250,7 @@ function updateFolderManager(global: GlobalState) {
|
|||||||
affectedFolderIds = affectedFolderIds.concat(updateChats(
|
affectedFolderIds = affectedFolderIds.concat(updateChats(
|
||||||
global,
|
global,
|
||||||
areFoldersChanged || isAllFolderChanged || isArchivedFolderChanged || isSavedFolderChanged,
|
areFoldersChanged || isAllFolderChanged || isArchivedFolderChanged || isSavedFolderChanged,
|
||||||
areNotifySettingsChanged,
|
areNotifyDefaultsChanged,
|
||||||
areNotifyExceptionsChanged,
|
areNotifyExceptionsChanged,
|
||||||
prevAllFolderListIds,
|
prevAllFolderListIds,
|
||||||
prevArchivedFolderListIds,
|
prevArchivedFolderListIds,
|
||||||
@ -411,7 +409,7 @@ function buildFolderSummary(folder: ApiChatFolder): FolderSummary {
|
|||||||
function updateChats(
|
function updateChats(
|
||||||
global: GlobalState,
|
global: GlobalState,
|
||||||
areFoldersChanged: boolean,
|
areFoldersChanged: boolean,
|
||||||
areNotifySettingsChanged: boolean,
|
areNotifyDefaultsChanged: boolean,
|
||||||
areNotifyExceptionsChanged: boolean,
|
areNotifyExceptionsChanged: boolean,
|
||||||
prevAllFolderListIds?: string[],
|
prevAllFolderListIds?: string[],
|
||||||
prevArchivedFolderListIds?: string[],
|
prevArchivedFolderListIds?: string[],
|
||||||
@ -421,8 +419,8 @@ function updateChats(
|
|||||||
const newUsersById = global.users.byId;
|
const newUsersById = global.users.byId;
|
||||||
const newAllLastMessageIds = global.chats.lastMessageIds.all;
|
const newAllLastMessageIds = global.chats.lastMessageIds.all;
|
||||||
const newSavedLastMessageIds = global.chats.lastMessageIds.saved;
|
const newSavedLastMessageIds = global.chats.lastMessageIds.saved;
|
||||||
const newNotifySettings = selectNotifySettings(global);
|
const newNotifyDefaults = selectNotifyDefaults(global);
|
||||||
const newNotifyExceptions = selectNotifyExceptions(global);
|
const newNotifyExceptions = global.chats.notifyExceptionById;
|
||||||
const folderSummaries = Object.values(prepared.folderSummariesById);
|
const folderSummaries = Object.values(prepared.folderSummariesById);
|
||||||
const affectedFolderIds = new Set<number>();
|
const affectedFolderIds = new Set<number>();
|
||||||
|
|
||||||
@ -445,7 +443,7 @@ function updateChats(
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!areFoldersChanged
|
!areFoldersChanged
|
||||||
&& !areNotifySettingsChanged
|
&& !areNotifyDefaultsChanged
|
||||||
&& !areNotifyExceptionsChanged
|
&& !areNotifyExceptionsChanged
|
||||||
&& chat === prevGlobal.chatsById[chatId]
|
&& chat === prevGlobal.chatsById[chatId]
|
||||||
&& newUsersById[chatId] === prevGlobal.usersById[chatId]
|
&& newUsersById[chatId] === prevGlobal.usersById[chatId]
|
||||||
@ -463,7 +461,7 @@ function updateChats(
|
|||||||
const newSummary = buildChatSummary(
|
const newSummary = buildChatSummary(
|
||||||
global,
|
global,
|
||||||
chat,
|
chat,
|
||||||
newNotifySettings,
|
newNotifyDefaults,
|
||||||
newNotifyExceptions,
|
newNotifyExceptions,
|
||||||
newUsersById[chatId],
|
newUsersById[chatId],
|
||||||
isRemovedFromAll,
|
isRemovedFromAll,
|
||||||
@ -500,7 +498,7 @@ function updateChats(
|
|||||||
prevGlobal.usersById = newUsersById;
|
prevGlobal.usersById = newUsersById;
|
||||||
prevGlobal.lastAllMessageIds = newAllLastMessageIds;
|
prevGlobal.lastAllMessageIds = newAllLastMessageIds;
|
||||||
prevGlobal.lastSavedMessageIds = newSavedLastMessageIds;
|
prevGlobal.lastSavedMessageIds = newSavedLastMessageIds;
|
||||||
prevGlobal.notifySettings = newNotifySettings;
|
prevGlobal.notifyDefaults = newNotifyDefaults;
|
||||||
prevGlobal.notifyExceptions = newNotifyExceptions;
|
prevGlobal.notifyExceptions = newNotifyExceptions;
|
||||||
|
|
||||||
return Array.from(affectedFolderIds);
|
return Array.from(affectedFolderIds);
|
||||||
@ -509,8 +507,8 @@ function updateChats(
|
|||||||
function buildChatSummary<T extends GlobalState>(
|
function buildChatSummary<T extends GlobalState>(
|
||||||
global: T,
|
global: T,
|
||||||
chat: ApiChat,
|
chat: ApiChat,
|
||||||
notifySettings: NotifySettings,
|
notifyDefaults?: Record<ApiNotifyPeerType, ApiPeerNotifySettings>,
|
||||||
notifyExceptions?: Record<number, NotifyException>,
|
notifyExceptions?: Record<string, ApiPeerNotifySettings>,
|
||||||
user?: ApiUser,
|
user?: ApiUser,
|
||||||
isRemovedFromAll?: boolean,
|
isRemovedFromAll?: boolean,
|
||||||
isRemovedFromSaved?: boolean,
|
isRemovedFromSaved?: boolean,
|
||||||
@ -548,7 +546,7 @@ function buildChatSummary<T extends GlobalState>(
|
|||||||
isListedInAll: Boolean(!isRestricted && !isNotJoined && !migratedTo && !shouldHideServiceChat && !isRemovedFromAll),
|
isListedInAll: Boolean(!isRestricted && !isNotJoined && !migratedTo && !shouldHideServiceChat && !isRemovedFromAll),
|
||||||
isListedInSaved: !isRemovedFromSaved,
|
isListedInSaved: !isRemovedFromSaved,
|
||||||
isArchived: folderId === ARCHIVED_FOLDER_ID,
|
isArchived: folderId === ARCHIVED_FOLDER_ID,
|
||||||
isMuted: selectIsChatMuted(chat, notifySettings, notifyExceptions),
|
isMuted: getIsChatMuted(chat, notifyDefaults, notifyExceptions?.[chat.id]),
|
||||||
isUnread: Boolean(unreadCount || unreadMentionsCount || hasUnreadMark),
|
isUnread: Boolean(unreadCount || unreadMentionsCount || hasUnreadMark),
|
||||||
unreadCount,
|
unreadCount,
|
||||||
unreadMentionsCount,
|
unreadMentionsCount,
|
||||||
@ -810,8 +808,6 @@ function buildInitials() {
|
|||||||
chatsById: {},
|
chatsById: {},
|
||||||
usersById: {},
|
usersById: {},
|
||||||
topicsInfoById: {},
|
topicsInfoById: {},
|
||||||
notifySettings: {} as NotifySettings,
|
|
||||||
notifyExceptions: {},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
prepared: {
|
prepared: {
|
||||||
|
|||||||
@ -16,16 +16,16 @@ import {
|
|||||||
getPrivateChatUserId,
|
getPrivateChatUserId,
|
||||||
getUserFullName,
|
getUserFullName,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
selectIsChatMuted,
|
|
||||||
selectShouldShowMessagePreview,
|
|
||||||
} from '../global/helpers';
|
} from '../global/helpers';
|
||||||
import { addNotifyExceptions, replaceSettings } from '../global/reducers';
|
import { getIsChatMuted, getIsChatSilent, getShouldShowMessagePreview } from '../global/helpers/notifications';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectIsChatWithSelf,
|
selectIsChatWithSelf,
|
||||||
selectNotifyExceptions,
|
selectNotifyDefaults,
|
||||||
selectNotifySettings,
|
selectNotifyException,
|
||||||
|
selectSettingsKeys,
|
||||||
|
selectTopicFromMessage,
|
||||||
selectUser,
|
selectUser,
|
||||||
} from '../global/selectors';
|
} from '../global/selectors';
|
||||||
import { callApi } from '../api/gramjs';
|
import { callApi } from '../api/gramjs';
|
||||||
@ -34,6 +34,7 @@ import { buildCollectionByKey } from './iteratees';
|
|||||||
import * as mediaLoader from './mediaLoader';
|
import * as mediaLoader from './mediaLoader';
|
||||||
import { oldTranslate } from './oldLangProvider';
|
import { oldTranslate } from './oldLangProvider';
|
||||||
import { debounce } from './schedulers';
|
import { debounce } from './schedulers';
|
||||||
|
import { getServerTime } from './serverTime';
|
||||||
import { IS_ELECTRON, IS_SERVICE_WORKER_SUPPORTED, IS_TOUCH_ENV } from './windowEnvironment';
|
import { IS_ELECTRON, IS_SERVICE_WORKER_SUPPORTED, IS_TOUCH_ENV } from './windowEnvironment';
|
||||||
|
|
||||||
import MessageSummary from '../components/common/MessageSummary';
|
import MessageSummary from '../components/common/MessageSummary';
|
||||||
@ -107,7 +108,7 @@ notificationSound.setAttribute('mozaudiochannel', 'notification');
|
|||||||
|
|
||||||
export async function playNotifySound(id?: string, volume?: number) {
|
export async function playNotifySound(id?: string, volume?: number) {
|
||||||
if (id !== undefined && soundPlayedIds.has(id)) return;
|
if (id !== undefined && soundPlayedIds.has(id)) return;
|
||||||
const { notificationSoundVolume } = selectNotifySettings(getGlobal());
|
const { notificationSoundVolume } = selectSettingsKeys(getGlobal());
|
||||||
const currentVolume = volume ? volume / 10 : notificationSoundVolume / 10;
|
const currentVolume = volume ? volume / 10 : notificationSoundVolume / 10;
|
||||||
if (currentVolume === 0) return;
|
if (currentVolume === 0) return;
|
||||||
notificationSound.volume = currentVolume;
|
notificationSound.volume = currentVolume;
|
||||||
@ -181,27 +182,6 @@ export async function unsubscribe() {
|
|||||||
await unsubscribeFromPush(subscription);
|
await unsubscribeFromPush(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates if notification settings are loaded from the api
|
|
||||||
let areSettingsLoaded = false;
|
|
||||||
|
|
||||||
// Load notification settings from the api
|
|
||||||
async function loadNotificationSettings() {
|
|
||||||
if (areSettingsLoaded) return selectNotifySettings(getGlobal());
|
|
||||||
const [resultSettings, resultExceptions] = await Promise.all([
|
|
||||||
callApi('fetchNotificationSettings'),
|
|
||||||
callApi('fetchNotificationExceptions'),
|
|
||||||
]);
|
|
||||||
if (!resultSettings) return selectNotifySettings(getGlobal());
|
|
||||||
|
|
||||||
let global = replaceSettings(getGlobal(), resultSettings);
|
|
||||||
if (resultExceptions) {
|
|
||||||
global = addNotifyExceptions(global, resultExceptions);
|
|
||||||
}
|
|
||||||
setGlobal(global);
|
|
||||||
areSettingsLoaded = true;
|
|
||||||
return selectNotifySettings(global);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load custom emoji from the api if it's not cached already
|
// Load custom emoji from the api if it's not cached already
|
||||||
async function loadCustomEmoji(id: string) {
|
async function loadCustomEmoji(id: string) {
|
||||||
let global = getGlobal();
|
let global = getGlobal();
|
||||||
@ -293,9 +273,12 @@ export async function subscribe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkIfShouldNotify(chat: ApiChat, message: Partial<ApiMessage>) {
|
function checkIfShouldNotify(chat: ApiChat, message: Partial<ApiMessage>) {
|
||||||
if (!areSettingsLoaded) return false;
|
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
const isMuted = selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
|
const isChatMuted = getIsChatMuted(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id));
|
||||||
|
const topic = selectTopicFromMessage(global, message as ApiMessage);
|
||||||
|
const topicMutedUntil = topic?.notifySettings.mutedUntil;
|
||||||
|
const isMuted = topicMutedUntil === undefined ? isChatMuted : topicMutedUntil > getServerTime();
|
||||||
|
|
||||||
const shouldNotifyAboutMessage = message.content?.action?.type !== 'phoneCall';
|
const shouldNotifyAboutMessage = message.content?.action?.type !== 'phoneCall';
|
||||||
if (isMuted || !shouldNotifyAboutMessage
|
if (isMuted || !shouldNotifyAboutMessage
|
||||||
|| chat.isNotJoined || !chat.isListed || selectIsChatWithSelf(global, chat.id)) {
|
|| chat.isNotJoined || !chat.isListed || selectIsChatWithSelf(global, chat.id)) {
|
||||||
@ -330,7 +313,7 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage, reaction?: A
|
|||||||
let body: string;
|
let body: string;
|
||||||
if (
|
if (
|
||||||
!isScreenLocked
|
!isScreenLocked
|
||||||
&& selectShouldShowMessagePreview(chat, selectNotifySettings(global), selectNotifyExceptions(global))
|
&& getShouldShowMessagePreview(chat, selectNotifyDefaults(global), selectNotifyException(global, chat.id))
|
||||||
) {
|
) {
|
||||||
const isChat = chat && (isChatChannel(chat) || message.senderId === message.chatId);
|
const isChat = chat && (isChatChannel(chat) || message.senderId === message.chatId);
|
||||||
|
|
||||||
@ -386,7 +369,7 @@ export async function notifyAboutCall({
|
|||||||
}: {
|
}: {
|
||||||
call: ApiPhoneCall; user: ApiUser;
|
call: ApiPhoneCall; user: ApiUser;
|
||||||
}) {
|
}) {
|
||||||
const { hasWebNotifications } = await loadNotificationSettings();
|
const { hasWebNotifications } = selectSettingsKeys(getGlobal());
|
||||||
if (document.hasFocus() || !hasWebNotifications) return;
|
if (document.hasFocus() || !hasWebNotifications) return;
|
||||||
const areNotificationsSupported = checkIfNotificationsSupported();
|
const areNotificationsSupported = checkIfNotificationsSupported();
|
||||||
if (!areNotificationsSupported) return;
|
if (!areNotificationsSupported) return;
|
||||||
@ -420,11 +403,18 @@ export async function notifyAboutMessage({
|
|||||||
message,
|
message,
|
||||||
isReaction = false,
|
isReaction = false,
|
||||||
}: { chat: ApiChat; message: Partial<ApiMessage>; isReaction?: boolean }) {
|
}: { chat: ApiChat; message: Partial<ApiMessage>; isReaction?: boolean }) {
|
||||||
const { hasWebNotifications } = await loadNotificationSettings();
|
const global = getGlobal();
|
||||||
|
const { hasWebNotifications } = selectSettingsKeys(global);
|
||||||
if (!checkIfShouldNotify(chat, message)) return;
|
if (!checkIfShouldNotify(chat, message)) return;
|
||||||
|
const isChatSilent = getIsChatSilent(
|
||||||
|
chat, selectNotifyDefaults(getGlobal()), selectNotifyException(getGlobal(), chat.id),
|
||||||
|
);
|
||||||
|
const topic = selectTopicFromMessage(global, message as ApiMessage);
|
||||||
|
const isSilent = topic?.notifySettings.hasSound === undefined ? isChatSilent : !topic.notifySettings.hasSound;
|
||||||
|
|
||||||
const areNotificationsSupported = checkIfNotificationsSupported();
|
const areNotificationsSupported = checkIfNotificationsSupported();
|
||||||
if (!hasWebNotifications || !areNotificationsSupported) {
|
if (!hasWebNotifications || !areNotificationsSupported) {
|
||||||
if (!message.isSilent && !isReaction && !IS_ELECTRON) {
|
if (!isSilent && !message.isSilent && !isReaction && !IS_ELECTRON) {
|
||||||
// Only play sound if web notifications are disabled
|
// Only play sound if web notifications are disabled
|
||||||
playNotifySoundDebounced(String(message.id) || chat.id);
|
playNotifySoundDebounced(String(message.id) || chat.id);
|
||||||
}
|
}
|
||||||
@ -463,7 +453,7 @@ export async function notifyAboutMessage({
|
|||||||
chatId: chat.id,
|
chatId: chat.id,
|
||||||
messageId: message.id,
|
messageId: message.id,
|
||||||
shouldReplaceHistory: true,
|
shouldReplaceHistory: true,
|
||||||
isSilent: message.isSilent,
|
isSilent: isSilent || message.isSilent,
|
||||||
reaction: activeReaction?.reaction,
|
reaction: activeReaction?.reaction,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user