Composer: Fix syncing drafts between tabs

This commit is contained in:
Alexander Zinchuk 2023-02-22 23:48:48 +01:00
parent c3fd837a81
commit c624675e9f
4 changed files with 40 additions and 15 deletions

View File

@ -4,7 +4,9 @@ import React, {
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { TabState, MessageListType, GlobalState } from '../../../global/types'; import type {
TabState, MessageListType, GlobalState, ApiDraft,
} from '../../../global/types';
import type { import type {
ApiAttachment, ApiAttachment,
ApiBotInlineResult, ApiBotInlineResult,
@ -147,7 +149,7 @@ type StateProps =
{ {
editingMessage?: ApiMessage; editingMessage?: ApiMessage;
chat?: ApiChat; chat?: ApiChat;
draft?: ApiFormattedText; draft?: ApiDraft;
isChatWithBot?: boolean; isChatWithBot?: boolean;
isChatWithSelf?: boolean; isChatWithSelf?: boolean;
isChannel?: boolean; isChannel?: boolean;

View File

@ -1,7 +1,8 @@
import { useCallback, useEffect } from '../../../../lib/teact/teact'; import { useCallback, useEffect } from '../../../../lib/teact/teact';
import { getActions } from '../../../../global'; import { getActions } from '../../../../global';
import type { ApiFormattedText, ApiMessage } from '../../../../api/types'; import type { ApiDraft } from '../../../../global/types';
import type { ApiMessage } from '../../../../api/types';
import type { Signal } from '../../../../util/signals'; import type { Signal } from '../../../../util/signals';
import { ApiMessageEntityTypes } from '../../../../api/types'; import { ApiMessageEntityTypes } from '../../../../api/types';
@ -26,7 +27,7 @@ function freeze() {
} }
const useDraft = ( const useDraft = (
draft: ApiFormattedText | undefined, draft: ApiDraft | undefined,
chatId: string, chatId: string,
threadId: number, threadId: number,
getHtml: Signal<string>, getHtml: Signal<string>,
@ -38,7 +39,7 @@ const useDraft = (
const isEditing = Boolean(editedMessage); const isEditing = Boolean(editedMessage);
const updateDraft = useCallback((prevState: { chatId?: string; threadId?: number } = {}) => { const updateDraft = useCallback((prevState: { chatId?: string; threadId?: number } = {}, shouldForce = false) => {
if (isEditing || !lastSyncTime) return; if (isEditing || !lastSyncTime) return;
const html = getHtml(); const html = getHtml();
@ -48,15 +49,21 @@ const useDraft = (
chatId: prevState.chatId ?? chatId, chatId: prevState.chatId ?? chatId,
threadId: prevState.threadId ?? threadId, threadId: prevState.threadId ?? threadId,
draft: parseMessageInput(html), draft: parseMessageInput(html),
shouldForce,
}); });
} else { } else {
clearDraft({ clearDraft({
chatId: prevState.chatId ?? chatId, chatId: prevState.chatId ?? chatId,
threadId: prevState.threadId ?? threadId, threadId: prevState.threadId ?? threadId,
shouldForce,
}); });
} }
}, [chatId, threadId, isEditing, lastSyncTime, getHtml, saveDraft, clearDraft]); }, [chatId, threadId, isEditing, lastSyncTime, getHtml, saveDraft, clearDraft]);
const forceUpdateDraft = useCallback(() => {
updateDraft(undefined, true);
}, [updateDraft]);
const updateDraftRef = useStateRef(updateDraft); const updateDraftRef = useStateRef(updateDraft);
const runDebouncedForSaveDraft = useRunDebounced(DRAFT_DEBOUNCE, true, undefined, [chatId, threadId]); const runDebouncedForSaveDraft = useRunDebounced(DRAFT_DEBOUNCE, true, undefined, [chatId, threadId]);
@ -67,7 +74,9 @@ const useDraft = (
setHtml(''); setHtml('');
} }
return; if (!draft?.shouldForce) {
return;
}
} }
if (editedMessage || !draft) { if (editedMessage || !draft) {
@ -130,8 +139,8 @@ const useDraft = (
}); });
}, [chatIdRef, getHtml, runDebouncedForSaveDraft, threadIdRef, updateDraftRef]); }, [chatIdRef, getHtml, runDebouncedForSaveDraft, threadIdRef, updateDraftRef]);
useBackgroundMode(updateDraft); useBackgroundMode(forceUpdateDraft);
useBeforeUnload(updateDraft); useBeforeUnload(forceUpdateDraft);
}; };
export default useDraft; export default useDraft;

View File

@ -2,7 +2,7 @@ import type { RequiredGlobalActions } from '../../index';
import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index';
import type { import type {
ActionReturnType, GlobalState, TabArgs, ActionReturnType, ApiDraft, GlobalState, TabArgs,
} from '../../types'; } from '../../types';
import type { import type {
ApiAttachment, ApiAttachment,
@ -356,7 +356,9 @@ addActionHandler('cancelSendingMessage', (global, actions, payload): ActionRetur
}); });
addActionHandler('saveDraft', async (global, actions, payload): Promise<void> => { addActionHandler('saveDraft', async (global, actions, payload): Promise<void> => {
const { chatId, threadId, draft } = payload!; const {
chatId, threadId, draft, shouldForce,
} = payload;
if (!draft) { if (!draft) {
return; return;
} }
@ -366,6 +368,13 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise<void> =>
const user = selectUser(global, chatId)!; const user = selectUser(global, chatId)!;
if (user && isDeletedUser(user)) return; if (user && isDeletedUser(user)) return;
draft.isLocal = true;
draft.shouldForce = shouldForce;
global = replaceThreadParam(global, chatId, threadId, 'draft', draft);
global = updateChat(global, chatId, { draftDate: Math.round(Date.now() / 1000) });
setGlobal(global);
const result = await callApi('saveDraft', { const result = await callApi('saveDraft', {
chat, chat,
text, text,
@ -374,8 +383,8 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise<void> =>
threadId: selectThreadTopMessageId(global, chatId, threadId), threadId: selectThreadTopMessageId(global, chatId, threadId),
}); });
if (!result) { if (result) {
draft.isLocal = true; draft.isLocal = false;
} }
global = getGlobal(); global = getGlobal();
@ -386,7 +395,9 @@ addActionHandler('saveDraft', async (global, actions, payload): Promise<void> =>
}); });
addActionHandler('clearDraft', (global, actions, payload): ActionReturnType => { addActionHandler('clearDraft', (global, actions, payload): ActionReturnType => {
const { chatId, threadId = MAIN_THREAD_ID, localOnly } = payload!; const {
chatId, threadId = MAIN_THREAD_ID, localOnly, shouldForce,
} = payload;
if (!selectDraft(global, chatId, threadId)) { if (!selectDraft(global, chatId, threadId)) {
return undefined; return undefined;
} }
@ -397,7 +408,8 @@ addActionHandler('clearDraft', (global, actions, payload): ActionReturnType => {
void callApi('clearDraft', chat, selectThreadTopMessageId(global, chatId, threadId)); void callApi('clearDraft', chat, selectThreadTopMessageId(global, chatId, threadId));
} }
global = replaceThreadParam(global, chatId, threadId, 'draft', undefined); const newDraft: ApiDraft | undefined = shouldForce ? { shouldForce, text: '' } : undefined;
global = replaceThreadParam(global, chatId, threadId, 'draft', newDraft);
global = updateChat(global, chatId, { draftDate: undefined }); global = updateChat(global, chatId, { draftDate: undefined });
return global; return global;

View File

@ -799,7 +799,7 @@ export type CallbackAction = Values<{
} }
}>; }>;
export type ApiDraft = ApiFormattedText & { isLocal?: boolean }; export type ApiDraft = ApiFormattedText & { isLocal?: boolean; shouldForce?: boolean };
type WithTabId = { tabId?: number }; type WithTabId = { tabId?: number };
@ -1237,11 +1237,13 @@ export interface ActionPayloads {
chatId: string; chatId: string;
threadId: number; threadId: number;
draft: ApiDraft; draft: ApiDraft;
shouldForce?: boolean;
}; };
clearDraft: { clearDraft: {
chatId: string; chatId: string;
threadId?: number; threadId?: number;
localOnly?: boolean; localOnly?: boolean;
shouldForce?: boolean;
}; };
loadPinnedMessages: { loadPinnedMessages: {
chatId: string; chatId: string;