Service Notifications: Fix marking as read

This commit is contained in:
Alexander Zinchuk 2021-11-12 18:45:45 +03:00
parent 8b959f3fb1
commit ac8eee48ec
5 changed files with 42 additions and 18 deletions

View File

@ -77,7 +77,6 @@ type StateProps = {
isBot?: boolean; isBot?: boolean;
messageIds?: number[]; messageIds?: number[];
messagesById?: Record<number, ApiMessage>; messagesById?: Record<number, ApiMessage>;
isUnread?: boolean;
firstUnreadId?: number; firstUnreadId?: number;
isViewportNewest?: boolean; isViewportNewest?: boolean;
isRestricted?: boolean; isRestricted?: boolean;
@ -125,7 +124,6 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
messageIds, messageIds,
messagesById, messagesById,
firstUnreadId, firstUnreadId,
isUnread,
isViewportNewest, isViewportNewest,
threadFirstMessageId, threadFirstMessageId,
isRestricted, isRestricted,
@ -174,12 +172,11 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
}, [firstUnreadId]); }, [firstUnreadId]);
// Updated only once when messages are loaded (as we want the unread divider to keep its position) // Updated only once when messages are loaded (as we want the unread divider to keep its position)
const withUnreadDivider = areMessagesLoaded && isUnread;
useOnChange(() => { useOnChange(() => {
if (withUnreadDivider) { if (areMessagesLoaded) {
memoUnreadDividerBeforeIdRef.current = memoFirstUnreadIdRef.current; memoUnreadDividerBeforeIdRef.current = memoFirstUnreadIdRef.current;
} }
}, [withUnreadDivider]); }, [areMessagesLoaded]);
useOnChange(() => { useOnChange(() => {
memoFocusingIdRef.current = focusingId; memoFocusingIdRef.current = focusingId;
@ -506,7 +503,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
messageIds={messageIds || [lastMessage!.id]} messageIds={messageIds || [lastMessage!.id]}
messageGroups={messageGroups || groupMessages([lastMessage!])} messageGroups={messageGroups || groupMessages([lastMessage!])}
isViewportNewest={Boolean(isViewportNewest)} isViewportNewest={Boolean(isViewportNewest)}
isUnread={Boolean(isUnread)} isUnread={Boolean(firstUnreadId)}
withUsers={withUsers} withUsers={withUsers}
noAvatars={noAvatars} noAvatars={noAvatars}
containerRef={containerRef} containerRef={containerRef}
@ -581,7 +578,6 @@ export default memo(withGlobal<OwnProps>(
isBot: Boolean(chatBot), isBot: Boolean(chatBot),
messageIds, messageIds,
messagesById, messagesById,
isUnread: Boolean(chat.unreadCount),
firstUnreadId: selectFirstUnreadId(global, chatId, threadId), firstUnreadId: selectFirstUnreadId(global, chatId, threadId),
isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId), isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId),
threadFirstMessageId: selectFirstMessageId(global, chatId, threadId), threadFirstMessageId: selectFirstMessageId(global, chatId, threadId),

View File

@ -76,6 +76,7 @@ export interface ServiceNotification {
id: number; id: number;
message: ApiMessage; message: ApiMessage;
version?: string; version?: string;
isUnread?: boolean;
} }
export type GlobalState = { export type GlobalState = {

View File

@ -485,15 +485,24 @@ addReducer('markMessageListRead', (global, actions, payload) => {
return undefined; return undefined;
} }
if (chatId === SERVICE_NOTIFICATIONS_USER_ID) {
global = {
...global,
serviceNotifications: global.serviceNotifications.map((notification) => {
return notification.isUnread && notification.id <= maxId ? { ...notification, isUnread: false } : notification;
}),
};
}
const viewportIds = selectViewportIds(global, chatId, threadId); const viewportIds = selectViewportIds(global, chatId, threadId);
const minId = selectFirstUnreadId(global, chatId, threadId); const minId = selectFirstUnreadId(global, chatId, threadId);
if (!viewportIds || !minId || !chat.unreadCount) { if (!viewportIds || !minId || !chat.unreadCount) {
return undefined; return global;
} }
const readCount = countSortedIds(viewportIds!, minId, maxId); const readCount = countSortedIds(viewportIds!, minId, maxId);
if (!readCount) { if (!readCount) {
return undefined; return global;
} }
return updateChat(global, chatId, { return updateChat(global, chatId, {

View File

@ -43,7 +43,7 @@ import parseMessageInput from '../../../util/parseMessageInput';
const FOCUS_DURATION = 1500; const FOCUS_DURATION = 1500;
const FOCUS_NO_HIGHLIGHT_DURATION = FAST_SMOOTH_MAX_DURATION + ANIMATION_END_DELAY; const FOCUS_NO_HIGHLIGHT_DURATION = FAST_SMOOTH_MAX_DURATION + ANIMATION_END_DELAY;
const POLL_RESULT_OPEN_DELAY_MS = 450; const POLL_RESULT_OPEN_DELAY_MS = 450;
const SERVICE_NOTIFICATIONS_MAX_AMOUNT = 1e4; const SERVICE_NOTIFICATIONS_MAX_AMOUNT = 1e3;
let blurTimeout: number | undefined; let blurTimeout: number | undefined;
@ -609,12 +609,13 @@ addReducer('createServiceNotification', (global, actions, payload) => {
id, id,
message, message,
version, version,
isUnread: true,
}; };
setGlobal({ setGlobal({
...global, ...global,
serviceNotifications: [ serviceNotifications: [
...serviceNotifications, ...serviceNotifications.slice(-SERVICE_NOTIFICATIONS_MAX_AMOUNT),
serviceNotification, serviceNotification,
], ],
}); });

View File

@ -7,7 +7,7 @@ import {
MAIN_THREAD_ID, MAIN_THREAD_ID,
} from '../../api/types'; } from '../../api/types';
import { LOCAL_MESSAGE_ID_BASE } from '../../config'; import { LOCAL_MESSAGE_ID_BASE, SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
import { import {
selectChat, selectIsChatWithBot, selectIsChatWithSelf, selectChat, selectIsChatWithBot, selectIsChatWithSelf,
} from './chats'; } from './chats';
@ -583,19 +583,36 @@ export function selectFirstUnreadId(global: GlobalState, chatId: string, threadI
return undefined; return undefined;
} }
if (outlyingIds) { const lastReadServiceNotificationId = chatId === SERVICE_NOTIFICATIONS_USER_ID
const found = !lastReadId ? outlyingIds[0] : outlyingIds.find((id) => { ? global.serviceNotifications.reduce((max, notification) => {
return id > lastReadId && byId[id] && (!byId[id].isOutgoing || byId[id].isFromScheduled); return !notification.isUnread && notification.id > max ? notification.id : max;
}, -1)
: -1;
function findAfterLastReadId(listIds: number[]) {
if (!lastReadId) {
return listIds[0];
}
return listIds.find((id) => {
return (
id > lastReadId
&& byId[id]
&& (!byId[id].isOutgoing || byId[id].isFromScheduled)
&& id > lastReadServiceNotificationId
);
}); });
}
if (outlyingIds) {
const found = findAfterLastReadId(outlyingIds);
if (found) { if (found) {
return found; return found;
} }
} }
if (listedIds) { if (listedIds) {
const found = !lastReadId ? listedIds[0] : listedIds.find((id) => { const found = findAfterLastReadId(listedIds);
return id > lastReadId && byId[id] && (!byId[id].isOutgoing || byId[id].isFromScheduled);
});
if (found) { if (found) {
return found; return found;
} }