Chat: Fix muted state (#5752)

This commit is contained in:
zubiden 2025-03-30 15:46:13 +02:00 committed by Alexander Zinchuk
parent e494152ea0
commit 4b2bee8a2f
8 changed files with 57 additions and 23 deletions

View File

@ -1923,18 +1923,20 @@ const Composer: FC<OwnProps & StateProps> = ({
{!hasText && (
<>
{isChannel && (
<Button
round
faded
className="composer-action-button"
color="translucent"
onClick={handleToggleSilentPosting}
ariaLabel={lang(
isSilentPosting ? 'AriaComposerSilentPostingDisable' : 'AriaComposerSilentPostingEnable',
)}
>
<Icon name={isSilentPosting ? 'mute' : 'unmute'} />
</Button>
<Transition className="composer-action-button" name="reveal" activeKey={Number(isSilentPosting)}>
<Button
round
faded
className="composer-action-button"
color="translucent"
onClick={handleToggleSilentPosting}
ariaLabel={lang(
isSilentPosting ? 'AriaComposerSilentPostingDisable' : 'AriaComposerSilentPostingEnable',
)}
>
<Icon name={isSilentPosting ? 'mute' : 'unmute'} />
</Button>
</Transition>
)}
{withScheduledButton && (
<Button

View File

@ -281,6 +281,7 @@ const Chat: FC<OwnProps & StateProps> = ({
isSavedDialog,
currentUserId,
isPreview,
topics,
});
const isIntersecting = useIsIntersecting(ref, chat ? observeIntersection : undefined);

View File

@ -75,6 +75,7 @@ import {
replaceChatListIds,
replaceChatListLoadingParameters,
replaceMessages,
replaceNotifyExceptions,
replaceSimilarChannels,
replaceThreadParam,
replaceUserStatuses,
@ -2928,6 +2929,7 @@ async function loadChats(
const offsetId = params.nextOffsetId;
const isFirstBatch = !shouldIgnorePagination && !offsetPeer && !offsetDate && !offsetId;
const shouldReplaceStaleState = listType === 'active' && isFirstBatch;
const result = listType === 'saved' ? await callApi('fetchSavedChats', {
limit: CHAT_LIST_LOAD_SLICE,
@ -2960,16 +2962,21 @@ async function loadChats(
global = updateChats(global, newChats);
if (isFirstBatch) {
global = replaceChatListIds(global, listType, chatIds);
global = replaceUserStatuses(global, result.userStatusesById);
} else {
global = addChatListIds(global, listType, chatIds);
}
if (shouldReplaceStaleState) {
global = replaceUserStatuses(global, result.userStatusesById);
global = replaceNotifyExceptions(global, result.notifyExceptionById);
} else {
global = addUserStatuses(global, result.userStatusesById);
global = addNotifyExceptions(global, result.notifyExceptionById);
}
global = updateChatListSecondaryInfo(global, listType, result);
global = replaceMessages(global, result.messages);
global = updateChatsLastMessageId(global, result.lastMessageByChatId, listType);
global = addNotifyExceptions(global, result.notifyExceptionById);
if (!shouldIgnorePagination) {
global = replaceChatListLoadingParameters(

View File

@ -544,8 +544,15 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
const chat = selectChat(global, chatId);
const currentThreadInfo = selectThreadInfo(global, chatId, threadId);
if (chat?.isForum && threadInfo.lastReadInboxMessageId !== currentThreadInfo?.lastReadInboxMessageId) {
actions.loadTopicById({ chatId, topicId: Number(threadId) });
const topic = selectTopic(global, chatId, threadId);
if (chat?.isForum) {
if (!topic || topic.lastMessageId !== currentThreadInfo?.lastReadInboxMessageId) {
actions.loadTopicById({ chatId, topicId: Number(threadId) });
} else {
global = updateTopic(global, chatId, Number(threadId), {
unreadCount: 0,
});
}
}
// Update reply thread last read message id if already read in main thread

View File

@ -498,7 +498,7 @@ function reduceChats<T extends GlobalState>(global: T): GlobalState['chats'] {
similarChannelsById: {},
similarBotsById: {},
isFullyLoaded: {},
notifyExceptionById: {},
notifyExceptionById: pickTruthy(global.chats.notifyExceptionById, idsToSave),
loadingParameters: INITIAL_GLOBAL_STATE.chats.loadingParameters,
byId: pickTruthy(global.chats.byId, idsToSave),
fullInfoById: pickTruthy(global.chats.fullInfoById, idsToSave),
@ -659,7 +659,7 @@ function omitLocalMedia(message: ApiMessage): ApiMessage {
function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings'] {
const {
byKey, themes, performance, botVerificationShownPeerIds, miniAppsCachedPosition, miniAppsCachedSize,
byKey, themes, performance, botVerificationShownPeerIds, miniAppsCachedPosition, miniAppsCachedSize, notifyDefaults,
} = global.settings;
return {
@ -670,6 +670,7 @@ function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings
botVerificationShownPeerIds,
miniAppsCachedPosition,
miniAppsCachedSize,
notifyDefaults,
};
}

View File

@ -53,6 +53,18 @@ export function addNotifyExceptions<T extends GlobalState>(
};
}
export function replaceNotifyExceptions<T extends GlobalState>(
global: T, notifyExceptionById: Record<string, ApiPeerNotifySettings>,
): T {
return {
...global,
chats: {
...global.chats,
notifyExceptionById,
},
};
}
export function addNotifyException<T extends GlobalState>(
global: T, id: string, notifyException: ApiPeerNotifySettings,
): T {

View File

@ -1,8 +1,8 @@
import { useMemo } from '../lib/teact/teact';
import { getActions } from '../global';
import type { ApiChat, ApiTopic, ApiUser } from '../api/types';
import type { MenuItemContextAction } from '../components/ui/ListItem';
import { type ApiChat, type ApiUser } from '../api/types';
import { SERVICE_NOTIFICATIONS_USER_ID } from '../config';
import {
@ -23,6 +23,7 @@ const useChatContextActions = ({
isSavedDialog,
currentUserId,
isPreview,
topics,
handleDelete,
handleMute,
handleChatFolderChange,
@ -37,6 +38,7 @@ const useChatContextActions = ({
isSavedDialog?: boolean;
currentUserId?: string;
isPreview?: boolean;
topics?: Record<number, ApiTopic>;
handleDelete?: NoneToVoidFunction;
handleMute?: NoneToVoidFunction;
handleChatFolderChange: NoneToVoidFunction;
@ -149,8 +151,9 @@ const useChatContextActions = ({
return compact([actionOpenInNewTab, actionPin, actionAddToFolder, actionMute]) as MenuItemContextAction[];
}
const actionMaskAsRead = (chat.unreadCount || chat.hasUnreadMark)
? { title: lang('MarkAsRead'), icon: 'readchats', handler: () => markChatMessagesRead({ id: chat.id }) }
const actionMaskAsRead = (
chat.unreadCount || chat.hasUnreadMark || Object.values(topics || {}).some(({ unreadCount }) => unreadCount)
) ? { title: lang('MarkAsRead'), icon: 'readchats', handler: () => markChatMessagesRead({ id: chat.id }) }
: undefined;
const actionMarkAsUnread = !(chat.unreadCount || chat.hasUnreadMark) && !chat.isForum
? { title: lang('MarkAsUnread'), icon: 'unread', handler: () => markChatUnread({ id: chat.id }) }
@ -181,7 +184,7 @@ const useChatContextActions = ({
}, [
chat, user, canChangeFolder, lang, handleChatFolderChange, isPinned, isInSearch, isMuted, currentUserId,
handleDelete, handleMute, handleReport, folderId, isSelf, isServiceNotifications, isSavedDialog, deleteTitle,
isPreview,
isPreview, topics,
]);
};

View File

@ -278,9 +278,10 @@ function checkIfShouldNotify(chat: ApiChat, message: Partial<ApiMessage>) {
const topic = selectTopicFromMessage(global, message as ApiMessage);
const topicMutedUntil = topic?.notifySettings.mutedUntil;
const isMuted = topicMutedUntil === undefined ? isChatMuted : topicMutedUntil > getServerTime();
const shouldIgnoreMute = message.isMentioned;
const shouldNotifyAboutMessage = message.content?.action?.type !== 'phoneCall';
if (isMuted || !shouldNotifyAboutMessage
if ((isMuted && !shouldIgnoreMute) || !shouldNotifyAboutMessage
|| chat.isNotJoined || !chat.isListed || selectIsChatWithSelf(global, chat.id)) {
return false;
}