Message List: Reply focusing stack (#1260)

This commit is contained in:
Alexander Zinchuk 2021-07-13 17:31:39 +03:00
parent fa8e750433
commit e744febfe8
6 changed files with 53 additions and 11 deletions

View File

@ -27,7 +27,7 @@ type StateProps = {
unreadCount?: number;
};
type DispatchProps = Pick<GlobalActions, 'focusLastMessage'>;
type DispatchProps = Pick<GlobalActions, 'focusNextReply'>;
const FOCUS_MARGIN = 20;
@ -36,7 +36,7 @@ const ScrollDownButton: FC<OwnProps & StateProps & DispatchProps> = ({
canPost,
messageListType,
unreadCount,
focusLastMessage,
focusNextReply,
}) => {
const lang = useLang();
// eslint-disable-next-line no-null/no-null
@ -48,7 +48,7 @@ const ScrollDownButton: FC<OwnProps & StateProps & DispatchProps> = ({
}
if (messageListType === 'thread') {
focusLastMessage();
focusNextReply();
} else {
const messagesContainer = elementRef.current!.parentElement!.querySelector<HTMLDivElement>('.MessageList')!;
const messageElements = messagesContainer.querySelectorAll<HTMLDivElement>('.message-list-item');
@ -59,7 +59,7 @@ const ScrollDownButton: FC<OwnProps & StateProps & DispatchProps> = ({
fastSmoothScroll(messagesContainer, lastMessageElement, 'end', FOCUS_MARGIN);
}
}, [isShown, messageListType, focusLastMessage]);
}, [isShown, messageListType, focusNextReply]);
const fabClassName = buildClassName(
'ScrollDownButton',
@ -101,5 +101,5 @@ export default memo(withGlobal<OwnProps>(
unreadCount: chat && threadId === MAIN_THREAD_ID && messageListType === 'thread' ? chat.unreadCount : undefined,
};
},
(setGlobal, actions): DispatchProps => pick(actions, ['focusLastMessage']),
(setGlobal, actions): DispatchProps => pick(actions, ['focusNextReply']),
)(ScrollDownButton));

View File

@ -416,8 +416,10 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
}, [botSender, openUserInfo]);
const handleReplyClick = useCallback((): void => {
focusMessage({ chatId, threadId, messageId: message.replyToMessageId });
}, [focusMessage, chatId, threadId, message.replyToMessageId]);
focusMessage({
chatId, threadId, messageId: message.replyToMessageId, replyMessageId: messageId,
});
}, [focusMessage, chatId, threadId, message.replyToMessageId, messageId]);
const handleMediaClick = useCallback((): void => {
openMediaViewer({

View File

@ -58,6 +58,7 @@ export interface Thread {
noWebPage?: boolean;
threadInfo?: ApiThreadInfo;
firstMessageId?: number;
replyStack?: number[];
}
export type GlobalState = {
@ -424,7 +425,7 @@ export type ActionTypes = (
'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' |
'setReplyingToId' | 'setEditingId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' |
'loadMessageLink' | 'toggleMessageWebPage' | 'replyToNextMessage' | 'deleteChatUser' | 'deleteChat' |
'reportMessages' |
'reportMessages' | 'focusNextReply' |
// scheduled messages
'loadScheduledHistory' | 'sendScheduledMessages' | 'rescheduleMessage' | 'deleteScheduledMessages' |
// poll result

View File

@ -1,7 +1,6 @@
import { addReducer, setGlobal } from '../../../lib/teact/teactn';
import {
exitMessageSelectMode,
updateCurrentMessageList,
exitMessageSelectMode, replaceThreadParam, updateCurrentMessageList,
} from '../../reducers';
import { selectCurrentMessageList } from '../../selectors';
import { closeLocalTextSearch } from './localSearch';
@ -19,6 +18,7 @@ addReducer('openChat', (global, actions, payload) => {
|| currentMessageList.threadId !== threadId
|| currentMessageList.type !== type
)) {
global = replaceThreadParam(global, id, threadId, 'replyStack', []);
global = exitMessageSelectMode(global);
global = closeLocalTextSearch(global);

View File

@ -21,7 +21,7 @@ import {
selectChatMessages,
selectAllowedMessageActions,
selectMessageIdsByGroupId,
selectForwardedMessageIdsByGroupId, selectIsViewportNewest, selectReplyingToId,
selectForwardedMessageIdsByGroupId, selectIsViewportNewest, selectReplyingToId, selectReplyStack,
} from '../../selectors';
import { findLast } from '../../../util/iteratees';
import { IS_TOUCH_ENV } from '../../../util/environment';
@ -240,9 +240,39 @@ addReducer('focusLastMessage', (global, actions) => {
});
});
addReducer('focusNextReply', (global, actions) => {
const currentMessageList = selectCurrentMessageList(global);
if (!currentMessageList) {
return undefined;
}
const { chatId, threadId } = currentMessageList;
const replyStack = selectReplyStack(global, chatId, threadId);
if (!replyStack || replyStack.length === 0) {
actions.focusLastMessage();
} else {
const messageId = replyStack.pop();
global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack]);
setGlobal(global);
actions.focusMessage({
chatId,
threadId,
messageId,
});
}
return undefined;
});
addReducer('focusMessage', (global, actions, payload) => {
const {
chatId, threadId = MAIN_THREAD_ID, messageListType = 'thread', noHighlight, groupedId, groupedChatId,
replyMessageId,
} = payload!;
let { messageId } = payload!;
@ -275,6 +305,11 @@ addReducer('focusMessage', (global, actions, payload) => {
global = updateFocusedMessage(global, chatId, messageId, noHighlight);
global = updateFocusDirection(global, undefined);
if (replyMessageId) {
const replyStack = selectReplyStack(global, chatId, threadId) || [];
global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack, replyMessageId]);
}
if (shouldSwitchChat) {
global = updateFocusDirection(global, FocusDirection.Static);
}

View File

@ -150,6 +150,10 @@ export function selectFirstMessageId(global: GlobalState, chatId: number, thread
return selectThreadParam(global, chatId, threadId, 'firstMessageId');
}
export function selectReplyStack(global: GlobalState, chatId: number, threadId: number) {
return selectThreadParam(global, chatId, threadId, 'replyStack');
}
export function selectThreadOriginChat(global: GlobalState, chatId: number, threadId: number) {
if (threadId === MAIN_THREAD_ID) {
return selectChat(global, chatId);