Composer: Support editing drafts, restore regular drafts after editing (#1764)
This commit is contained in:
parent
2b55037b08
commit
debbbf339d
@ -39,6 +39,8 @@ import {
|
|||||||
selectChatMessage,
|
selectChatMessage,
|
||||||
selectUser,
|
selectUser,
|
||||||
selectCanScheduleUntilOnline,
|
selectCanScheduleUntilOnline,
|
||||||
|
selectEditingScheduledDraft,
|
||||||
|
selectEditingDraft,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import {
|
import {
|
||||||
getAllowedAttachmentOptions,
|
getAllowedAttachmentOptions,
|
||||||
@ -147,6 +149,7 @@ type StateProps =
|
|||||||
sendAsUser?: ApiUser;
|
sendAsUser?: ApiUser;
|
||||||
sendAsChat?: ApiChat;
|
sendAsChat?: ApiChat;
|
||||||
sendAsId?: string;
|
sendAsId?: string;
|
||||||
|
editingDraft?: ApiFormattedText;
|
||||||
}
|
}
|
||||||
& Pick<GlobalState, 'connectionState'>;
|
& Pick<GlobalState, 'connectionState'>;
|
||||||
|
|
||||||
@ -213,6 +216,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
sendAsUser,
|
sendAsUser,
|
||||||
sendAsChat,
|
sendAsChat,
|
||||||
sendAsId,
|
sendAsId,
|
||||||
|
editingDraft,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
@ -457,10 +461,27 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
};
|
};
|
||||||
}, [chatId, resetComposer, stopRecordingVoiceRef]);
|
}, [chatId, resetComposer, stopRecordingVoiceRef]);
|
||||||
|
|
||||||
const handleEditComplete = useEditing(htmlRef, setHtml, editingMessage, resetComposer, openDeleteModal);
|
const [handleEditComplete, handleEditCancel] = useEditing(
|
||||||
|
htmlRef,
|
||||||
|
setHtml,
|
||||||
|
editingMessage,
|
||||||
|
resetComposer,
|
||||||
|
openDeleteModal,
|
||||||
|
chatId,
|
||||||
|
threadId,
|
||||||
|
messageListType,
|
||||||
|
draft,
|
||||||
|
editingDraft,
|
||||||
|
);
|
||||||
useDraft(draft, chatId, threadId, htmlRef, setHtml, editingMessage);
|
useDraft(draft, chatId, threadId, htmlRef, setHtml, editingMessage);
|
||||||
useClipboardPaste(insertTextAndUpdateCursor, setAttachments, editingMessage);
|
useClipboardPaste(insertTextAndUpdateCursor, setAttachments, editingMessage);
|
||||||
|
|
||||||
|
const handleEmbeddedClear = useCallback(() => {
|
||||||
|
if (editingMessage) {
|
||||||
|
handleEditCancel();
|
||||||
|
}
|
||||||
|
}, [editingMessage, handleEditCancel]);
|
||||||
|
|
||||||
const handleFileSelect = useCallback(async (files: File[], isQuick: boolean) => {
|
const handleFileSelect = useCallback(async (files: File[], isQuick: boolean) => {
|
||||||
setAttachments(await Promise.all(files.map((file) => buildAttachment(file.name, file, isQuick))));
|
setAttachments(await Promise.all(files.map((file) => buildAttachment(file.name, file, isQuick))));
|
||||||
}, []);
|
}, []);
|
||||||
@ -965,7 +986,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
<div id="message-compose">
|
<div id="message-compose">
|
||||||
<div className="svg-appendix" ref={appendixRef} />
|
<div className="svg-appendix" ref={appendixRef} />
|
||||||
<ComposerEmbeddedMessage />
|
<ComposerEmbeddedMessage onClear={handleEmbeddedClear} />
|
||||||
<WebPagePreview
|
<WebPagePreview
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
threadId={threadId}
|
threadId={threadId}
|
||||||
@ -1187,6 +1208,10 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined;
|
const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined;
|
||||||
const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined;
|
const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined;
|
||||||
|
|
||||||
|
const editingDraft = messageListType === 'scheduled'
|
||||||
|
? selectEditingScheduledDraft(global, chatId)
|
||||||
|
: selectEditingDraft(global, chatId, threadId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
editingMessage: selectEditingMessage(global, chatId, threadId, messageListType),
|
editingMessage: selectEditingMessage(global, chatId, threadId, messageListType),
|
||||||
connectionState: global.connectionState,
|
connectionState: global.connectionState,
|
||||||
@ -1225,6 +1250,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
sendAsUser,
|
sendAsUser,
|
||||||
sendAsChat,
|
sendAsChat,
|
||||||
sendAsId,
|
sendAsId,
|
||||||
|
editingDraft,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Composer));
|
)(Composer));
|
||||||
|
|||||||
@ -38,15 +38,20 @@ type StateProps = {
|
|||||||
forwardedMessagesCount?: number;
|
forwardedMessagesCount?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
onClear?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
const FORWARD_RENDERING_DELAY = 300;
|
const FORWARD_RENDERING_DELAY = 300;
|
||||||
|
|
||||||
const ComposerEmbeddedMessage: FC<StateProps> = ({
|
const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
||||||
replyingToId,
|
replyingToId,
|
||||||
editingId,
|
editingId,
|
||||||
message,
|
message,
|
||||||
sender,
|
sender,
|
||||||
shouldAnimate,
|
shouldAnimate,
|
||||||
forwardedMessagesCount,
|
forwardedMessagesCount,
|
||||||
|
onClear,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
setReplyingToId,
|
setReplyingToId,
|
||||||
@ -76,7 +81,8 @@ const ComposerEmbeddedMessage: FC<StateProps> = ({
|
|||||||
} else if (forwardedMessagesCount) {
|
} else if (forwardedMessagesCount) {
|
||||||
exitForwardMode();
|
exitForwardMode();
|
||||||
}
|
}
|
||||||
}, [replyingToId, editingId, forwardedMessagesCount, setReplyingToId, setEditingId, exitForwardMode]);
|
onClear?.();
|
||||||
|
}, [replyingToId, editingId, forwardedMessagesCount, onClear, setReplyingToId, setEditingId, exitForwardMode]);
|
||||||
|
|
||||||
useEffect(() => (isShown ? captureEscKeyListener(clearEmbedded) : undefined), [isShown, clearEmbedded]);
|
useEffect(() => (isShown ? captureEscKeyListener(clearEmbedded) : undefined), [isShown, clearEmbedded]);
|
||||||
|
|
||||||
@ -113,7 +119,7 @@ const ComposerEmbeddedMessage: FC<StateProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(withGlobal(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const { chatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {};
|
const { chatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {};
|
||||||
if (!chatId || !threadId || !messageListType) {
|
if (!chatId || !threadId || !messageListType) {
|
||||||
|
|||||||
@ -29,9 +29,10 @@ const useDraft = (
|
|||||||
|
|
||||||
const updateDraft = useCallback((draftChatId: string, draftThreadId: number) => {
|
const updateDraft = useCallback((draftChatId: string, draftThreadId: number) => {
|
||||||
const currentHtml = htmlRef.current;
|
const currentHtml = htmlRef.current;
|
||||||
if (currentHtml.length && !editedMessage) {
|
if (editedMessage) return;
|
||||||
|
if (currentHtml.length) {
|
||||||
saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(currentHtml!) });
|
saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(currentHtml!) });
|
||||||
} else {
|
} else if (currentHtml !== undefined) {
|
||||||
clearDraft({ chatId: draftChatId, threadId: draftThreadId });
|
clearDraft({ chatId: draftChatId, threadId: draftThreadId });
|
||||||
}
|
}
|
||||||
}, [clearDraft, editedMessage, htmlRef, saveDraft]);
|
}, [clearDraft, editedMessage, htmlRef, saveDraft]);
|
||||||
@ -61,7 +62,7 @@ const useDraft = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!draft) {
|
if (editedMessage || !draft) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ const useDraft = (
|
|||||||
focusEditableElement(messageInput, true);
|
focusEditableElement(messageInput, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [chatId, threadId, draft, setHtml, updateDraft, prevChatId, prevThreadId]);
|
}, [chatId, threadId, draft, setHtml, updateDraft, prevChatId, prevThreadId, editedMessage]);
|
||||||
|
|
||||||
const html = htmlRef.current;
|
const html = htmlRef.current;
|
||||||
// Update draft when input changes
|
// Update draft when input changes
|
||||||
|
|||||||
@ -1,40 +1,79 @@
|
|||||||
import { useCallback } from '../../../../lib/teact/teact';
|
import { useCallback, useEffect } from '../../../../lib/teact/teact';
|
||||||
import { getActions } from '../../../../global';
|
import { getActions } from '../../../../global';
|
||||||
|
|
||||||
import { ApiMessage } from '../../../../api/types';
|
import { ApiFormattedText, ApiMessage } from '../../../../api/types';
|
||||||
|
import { MessageListType } from '../../../../global/types';
|
||||||
|
|
||||||
|
import useEffectWithPrevDeps from '../../../../hooks/useEffectWithPrevDeps';
|
||||||
import { EDITABLE_INPUT_ID } from '../../../../config';
|
import { EDITABLE_INPUT_ID } from '../../../../config';
|
||||||
import parseMessageInput from '../../../../util/parseMessageInput';
|
import parseMessageInput from '../../../../util/parseMessageInput';
|
||||||
import focusEditableElement from '../../../../util/focusEditableElement';
|
import focusEditableElement from '../../../../util/focusEditableElement';
|
||||||
import { hasMessageMedia } from '../../../../global/helpers';
|
import { hasMessageMedia } from '../../../../global/helpers';
|
||||||
import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities';
|
import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities';
|
||||||
import useOnChange from '../../../../hooks/useOnChange';
|
import { fastRaf } from '../../../../util/schedulers';
|
||||||
|
import useBackgroundMode from '../../../../hooks/useBackgroundMode';
|
||||||
|
import useBeforeUnload from '../../../../hooks/useBeforeUnload';
|
||||||
|
|
||||||
const useEditing = (
|
const useEditing = (
|
||||||
htmlRef: { current: string },
|
htmlRef: { current: string },
|
||||||
setHtml: (html: string) => void,
|
setHtml: (html: string) => void,
|
||||||
editedMessage: ApiMessage | undefined,
|
editedMessage: ApiMessage | undefined,
|
||||||
resetComposer: () => void,
|
resetComposer: (shouldPreserveInput?: boolean) => void,
|
||||||
openDeleteModal: () => void,
|
openDeleteModal: () => void,
|
||||||
|
chatId: string,
|
||||||
|
threadId: number,
|
||||||
|
type: MessageListType,
|
||||||
|
draft?: ApiFormattedText,
|
||||||
|
editingDraft?: ApiFormattedText,
|
||||||
) => {
|
) => {
|
||||||
const { editMessage } = getActions();
|
const { editMessage, setEditingDraft } = getActions();
|
||||||
|
|
||||||
useOnChange(([prevEditedMessage]) => {
|
useEffectWithPrevDeps(([prevEditedMessage]) => {
|
||||||
if (!editedMessage) {
|
if (!editedMessage) {
|
||||||
setHtml('');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (prevEditedMessage?.id === editedMessage.id) {
|
if (prevEditedMessage?.id === editedMessage.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setHtml(getTextWithEntitiesAsHtml(editedMessage.content.text));
|
|
||||||
|
|
||||||
|
const html = getTextWithEntitiesAsHtml(editingDraft?.text.length ? editingDraft : editedMessage.content.text);
|
||||||
|
setHtml(html);
|
||||||
|
// `fastRaf` would execute syncronously in this case
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
|
const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
|
||||||
focusEditableElement(messageInput, true);
|
focusEditableElement(messageInput, true);
|
||||||
});
|
});
|
||||||
}, [editedMessage, setHtml] as const);
|
}, [editedMessage, setHtml] as const);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editedMessage) return undefined;
|
||||||
|
return () => {
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
const edited = parseMessageInput(htmlRef.current!);
|
||||||
|
const update = edited.text.length ? edited : undefined;
|
||||||
|
setEditingDraft({
|
||||||
|
chatId, threadId, type, text: update,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [chatId, editedMessage, htmlRef, setEditingDraft, threadId, type]);
|
||||||
|
|
||||||
|
const restoreNewDraftAfterEditing = useCallback(() => {
|
||||||
|
if (!draft) return;
|
||||||
|
// Run 1 frame after editing draft reset
|
||||||
|
fastRaf(() => {
|
||||||
|
setHtml(getTextWithEntitiesAsHtml(draft));
|
||||||
|
const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
focusEditableElement(messageInput, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [draft, setHtml]);
|
||||||
|
|
||||||
|
const handleEditCancel = useCallback(() => {
|
||||||
|
resetComposer();
|
||||||
|
restoreNewDraftAfterEditing();
|
||||||
|
}, [resetComposer, restoreNewDraftAfterEditing]);
|
||||||
|
|
||||||
const handleEditComplete = useCallback(() => {
|
const handleEditComplete = useCallback(() => {
|
||||||
const { text, entities } = parseMessageInput(htmlRef.current!);
|
const { text, entities } = parseMessageInput(htmlRef.current!);
|
||||||
|
|
||||||
@ -54,9 +93,22 @@ const useEditing = (
|
|||||||
});
|
});
|
||||||
|
|
||||||
resetComposer();
|
resetComposer();
|
||||||
}, [editMessage, editedMessage, htmlRef, openDeleteModal, resetComposer]);
|
restoreNewDraftAfterEditing();
|
||||||
|
}, [editMessage, editedMessage, htmlRef, openDeleteModal, resetComposer, restoreNewDraftAfterEditing]);
|
||||||
|
|
||||||
return handleEditComplete;
|
const handleBlur = useCallback(() => {
|
||||||
|
if (!editedMessage) return;
|
||||||
|
const edited = parseMessageInput(htmlRef.current!);
|
||||||
|
const update = edited.text.length ? edited : undefined;
|
||||||
|
setEditingDraft({
|
||||||
|
chatId, threadId, type, text: update,
|
||||||
|
});
|
||||||
|
}, [chatId, editedMessage, htmlRef, setEditingDraft, threadId, type]);
|
||||||
|
|
||||||
|
useBackgroundMode(handleBlur);
|
||||||
|
useBeforeUnload(handleBlur);
|
||||||
|
|
||||||
|
return [handleEditComplete, handleEditCancel];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useEditing;
|
export default useEditing;
|
||||||
|
|||||||
@ -3,8 +3,9 @@ import {
|
|||||||
} from '../../index';
|
} from '../../index';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ApiChat, ApiFormattedText, ApiMessage, MAIN_THREAD_ID,
|
ApiChat, ApiMessage, MAIN_THREAD_ID,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
import { Thread } from '../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID,
|
DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
@ -15,16 +16,18 @@ import {
|
|||||||
updateUsers,
|
updateUsers,
|
||||||
updateChats,
|
updateChats,
|
||||||
updateThreadInfos,
|
updateThreadInfos,
|
||||||
replaceThreadParam,
|
|
||||||
updateListedIds,
|
updateListedIds,
|
||||||
safeReplaceViewportIds,
|
safeReplaceViewportIds,
|
||||||
addChatMessagesById,
|
addChatMessagesById,
|
||||||
|
updateThread,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectDraft,
|
selectDraft,
|
||||||
selectChatMessage,
|
selectChatMessage,
|
||||||
selectThreadInfo,
|
selectThreadInfo,
|
||||||
|
selectEditingId,
|
||||||
|
selectEditingDraft,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import { init as initFolderManager } from '../../../util/folderManager';
|
import { init as initFolderManager } from '../../../util/folderManager';
|
||||||
|
|
||||||
@ -84,11 +87,11 @@ async function loadAndReplaceMessages() {
|
|||||||
|
|
||||||
// Memoize drafts
|
// Memoize drafts
|
||||||
const draftChatIds = Object.keys(global.messages.byChatId);
|
const draftChatIds = Object.keys(global.messages.byChatId);
|
||||||
const draftsByChatId = draftChatIds.reduce<Record<string, ApiFormattedText>>((acc, chatId) => {
|
const draftsByChatId = draftChatIds.reduce<Record<string, Partial<Thread>>>((acc, chatId) => {
|
||||||
const draft = selectDraft(global, chatId, MAIN_THREAD_ID);
|
acc[chatId] = {};
|
||||||
if (draft) {
|
acc[chatId].draft = selectDraft(global, chatId, MAIN_THREAD_ID);
|
||||||
acc[chatId] = draft;
|
acc[chatId].editingId = selectEditingId(global, chatId, MAIN_THREAD_ID);
|
||||||
}
|
acc[chatId].editingDraft = selectEditingDraft(global, chatId, MAIN_THREAD_ID);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
@ -183,7 +186,7 @@ async function loadAndReplaceMessages() {
|
|||||||
|
|
||||||
// Restore drafts
|
// Restore drafts
|
||||||
Object.keys(draftsByChatId).forEach((chatId) => {
|
Object.keys(draftsByChatId).forEach((chatId) => {
|
||||||
global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', draftsByChatId[chatId]);
|
global = updateThread(global, chatId, MAIN_THREAD_ID, draftsByChatId[chatId]);
|
||||||
});
|
});
|
||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|||||||
@ -81,6 +81,16 @@ addActionHandler('setEditingId', (global, actions, payload) => {
|
|||||||
return replaceThreadParam(global, chatId, threadId, paramName, messageId);
|
return replaceThreadParam(global, chatId, threadId, paramName, messageId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('setEditingDraft', (global, actions, payload) => {
|
||||||
|
const {
|
||||||
|
text, chatId, threadId, type,
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
const paramName = type === 'scheduled' ? 'editingScheduledDraft' : 'editingDraft';
|
||||||
|
|
||||||
|
return replaceThreadParam(global, chatId, threadId, paramName, text);
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('editLastMessage', (global) => {
|
addActionHandler('editLastMessage', (global) => {
|
||||||
const { chatId, threadId } = selectCurrentMessageList(global) || {};
|
const { chatId, threadId } = selectCurrentMessageList(global) || {};
|
||||||
if (!chatId || !threadId) {
|
if (!chatId || !threadId) {
|
||||||
|
|||||||
@ -71,7 +71,7 @@ function replaceChatMessages(global: GlobalState, chatId: string, newById: Recor
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateThread(
|
export function updateThread(
|
||||||
global: GlobalState, chatId: string, threadId: number, threadUpdate: Partial<Thread>,
|
global: GlobalState, chatId: string, threadId: number, threadUpdate: Partial<Thread>,
|
||||||
): GlobalState {
|
): GlobalState {
|
||||||
const current = global.messages.byChatId[chatId];
|
const current = global.messages.byChatId[chatId];
|
||||||
|
|||||||
@ -133,10 +133,18 @@ export function selectEditingId(global: GlobalState, chatId: string, threadId: n
|
|||||||
return selectThreadParam(global, chatId, threadId, 'editingId');
|
return selectThreadParam(global, chatId, threadId, 'editingId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function selectEditingDraft(global: GlobalState, chatId: string, threadId: number) {
|
||||||
|
return selectThreadParam(global, chatId, threadId, 'editingDraft');
|
||||||
|
}
|
||||||
|
|
||||||
export function selectEditingScheduledId(global: GlobalState, chatId: string) {
|
export function selectEditingScheduledId(global: GlobalState, chatId: string) {
|
||||||
return selectThreadParam(global, chatId, MAIN_THREAD_ID, 'editingScheduledId');
|
return selectThreadParam(global, chatId, MAIN_THREAD_ID, 'editingScheduledId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function selectEditingScheduledDraft(global: GlobalState, chatId: string) {
|
||||||
|
return selectThreadParam(global, chatId, MAIN_THREAD_ID, 'editingScheduledDraft');
|
||||||
|
}
|
||||||
|
|
||||||
export function selectDraft(global: GlobalState, chatId: string, threadId: number) {
|
export function selectDraft(global: GlobalState, chatId: string, threadId: number) {
|
||||||
return selectThreadParam(global, chatId, threadId, 'draft');
|
return selectThreadParam(global, chatId, threadId, 'draft');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,6 +92,8 @@ export interface Thread {
|
|||||||
replyingToId?: number;
|
replyingToId?: number;
|
||||||
editingId?: number;
|
editingId?: number;
|
||||||
editingScheduledId?: number;
|
editingScheduledId?: number;
|
||||||
|
editingDraft?: ApiFormattedText;
|
||||||
|
editingScheduledDraft?: ApiFormattedText;
|
||||||
draft?: ApiFormattedText;
|
draft?: ApiFormattedText;
|
||||||
noWebPage?: boolean;
|
noWebPage?: boolean;
|
||||||
threadInfo?: ApiThreadInfo;
|
threadInfo?: ApiThreadInfo;
|
||||||
@ -515,6 +517,12 @@ export interface ActionPayloads {
|
|||||||
type?: MessageListType;
|
type?: MessageListType;
|
||||||
shouldReplaceHistory?: boolean;
|
shouldReplaceHistory?: boolean;
|
||||||
};
|
};
|
||||||
|
setEditingDraft: {
|
||||||
|
text?: ApiFormattedText;
|
||||||
|
chatId: string;
|
||||||
|
threadId: number;
|
||||||
|
type: MessageListType;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NonTypedActionNames = (
|
export type NonTypedActionNames = (
|
||||||
@ -544,13 +552,14 @@ export type NonTypedActionNames = (
|
|||||||
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
||||||
'editMessage' | 'deleteHistory' | 'enterMessageSelectMode' | 'toggleMessageSelection' | 'exitMessageSelectMode' |
|
'editMessage' | 'deleteHistory' | 'enterMessageSelectMode' | 'toggleMessageSelection' | 'exitMessageSelectMode' |
|
||||||
'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' |
|
'openTelegramLink' | 'openChatByUsername' | 'requestThreadInfoUpdate' | 'setScrollOffset' | 'unpinAllMessages' |
|
||||||
'setReplyingToId' | 'setEditingId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' |
|
'setReplyingToId' | 'editLastMessage' | 'saveDraft' | 'clearDraft' | 'loadPinnedMessages' |
|
||||||
'toggleMessageWebPage' | 'replyToNextMessage' | 'deleteChatUser' | 'deleteChat' | 'sendReaction' |
|
'toggleMessageWebPage' | 'replyToNextMessage' | 'deleteChatUser' | 'deleteChat' | 'sendReaction' |
|
||||||
'reportMessages' | 'sendMessageAction' | 'focusNextReply' | 'openChatByInvite' | 'loadSeenBy' |
|
'reportMessages' | 'sendMessageAction' | 'focusNextReply' | 'openChatByInvite' | 'loadSeenBy' |
|
||||||
'loadSponsoredMessages' | 'viewSponsoredMessage' | 'loadSendAs' | 'saveDefaultSendAs' | 'loadAvailableReactions' |
|
'loadSponsoredMessages' | 'viewSponsoredMessage' | 'loadSendAs' | 'saveDefaultSendAs' | 'loadAvailableReactions' |
|
||||||
'stopActiveEmojiInteraction' | 'interactWithAnimatedEmoji' | 'loadReactors' | 'setDefaultReaction' |
|
'stopActiveEmojiInteraction' | 'interactWithAnimatedEmoji' | 'loadReactors' | 'setDefaultReaction' |
|
||||||
'sendDefaultReaction' | 'sendEmojiInteraction' | 'sendWatchingEmojiInteraction' | 'loadMessageReactions' |
|
'sendDefaultReaction' | 'sendEmojiInteraction' | 'sendWatchingEmojiInteraction' | 'loadMessageReactions' |
|
||||||
'stopActiveReaction' | 'startActiveReaction' | 'copySelectedMessages' | 'copyMessagesByIds' |
|
'stopActiveReaction' | 'startActiveReaction' | 'copySelectedMessages' | 'copyMessagesByIds' |
|
||||||
|
'setEditingId' |
|
||||||
// downloads
|
// downloads
|
||||||
'downloadSelectedMessages' | 'downloadMessageMedia' | 'cancelMessageMediaDownload' |
|
'downloadSelectedMessages' | 'downloadMessageMedia' | 'cancelMessageMediaDownload' |
|
||||||
// scheduled messages
|
// scheduled messages
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { useEffect } from '../lib/teact/teact';
|
import { useEffect } from '../lib/teact/teact';
|
||||||
import usePrevious from './usePrevious';
|
import usePrevious from './usePrevious';
|
||||||
|
|
||||||
const useEffectWithPrevDeps = <T extends any[]>(cb: (args: T | []) => void, dependencies: T, debugKey?: string) => {
|
const useEffectWithPrevDeps = <T extends readonly any[]>(
|
||||||
|
cb: (args: T | readonly []) => void, dependencies: T, debugKey?: string,
|
||||||
|
) => {
|
||||||
const prevDeps = usePrevious<T>(dependencies);
|
const prevDeps = usePrevious<T>(dependencies);
|
||||||
return useEffect(() => {
|
return useEffect(() => {
|
||||||
return cb(prevDeps || []);
|
return cb(prevDeps || []);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user