Composer: Fix syncing drafts between tabs
This commit is contained in:
parent
c3fd837a81
commit
c624675e9f
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user