[Perf] Composer: Prevent invisible animations when opening chat

This commit is contained in:
Alexander Zinchuk 2021-08-03 19:03:11 +03:00
parent 69b9394a18
commit 8dff81f301
4 changed files with 41 additions and 19 deletions

View File

@ -28,6 +28,7 @@ import { isChatChannel, isChatPrivate } from '../../modules/helpers';
import { orderBy, pick } from '../../util/iteratees'; import { orderBy, pick } from '../../util/iteratees';
import { fastRaf, debounce, onTickEnd } from '../../util/schedulers'; import { fastRaf, debounce, onTickEnd } from '../../util/schedulers';
import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps'; import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { groupMessages } from './helpers/groupMessages'; import { groupMessages } from './helpers/groupMessages';
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur'; import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
@ -112,7 +113,6 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
focusingId, focusingId,
hasFocusHighlight, hasFocusHighlight,
isSelectModeActive, isSelectModeActive,
animationLevel,
loadViewportMessages, loadViewportMessages,
setScrollOffset, setScrollOffset,
lastMessage, lastMessage,
@ -413,11 +413,11 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
// This should match deps for `useOnChange` above // This should match deps for `useOnChange` above
}, [messageIds, isViewportNewest, containerHeight, hasTools]); }, [messageIds, isViewportNewest, containerHeight, hasTools]);
useEffect(() => { useEffectWithPrevDeps(([prevIsSelectModeActive]) => {
if (!animationLevel || animationLevel > 0) { if (prevIsSelectModeActive !== undefined) {
dispatchHeavyAnimationEvent(SELECT_MODE_ANIMATION_DURATION + ANIMATION_END_DELAY); dispatchHeavyAnimationEvent(SELECT_MODE_ANIMATION_DURATION + ANIMATION_END_DELAY);
} }
}, [animationLevel, isSelectModeActive]); }, [isSelectModeActive]);
const lang = useLang(); const lang = useLang();
@ -534,7 +534,6 @@ export default memo(withGlobal<OwnProps>(
focusingId, focusingId,
hasFocusHighlight, hasFocusHighlight,
isSelectModeActive: selectIsInSelectMode(global), isSelectModeActive: selectIsInSelectMode(global),
animationLevel: global.settings.byKey.animationLevel,
...(withLastMessageWhenPreloading && { lastMessage }), ...(withLastMessageWhenPreloading && { lastMessage }),
botDescription, botDescription,
threadTopMessageId, threadTopMessageId,

View File

@ -25,7 +25,7 @@ import './AttachmentModal.scss';
export type OwnProps = { export type OwnProps = {
attachments: ApiAttachment[]; attachments: ApiAttachment[];
caption: string; caption: string;
canSuggestEmoji?: boolean; isReady?: boolean;
currentUserId?: number; currentUserId?: number;
groupChatMembers?: ApiChatMember[]; groupChatMembers?: ApiChatMember[];
usersById?: Record<number, ApiUser>; usersById?: Record<number, ApiUser>;
@ -44,14 +44,15 @@ const DROP_LEAVE_TIMEOUT_MS = 150;
const AttachmentModal: FC<OwnProps> = ({ const AttachmentModal: FC<OwnProps> = ({
attachments, attachments,
caption, caption,
groupChatMembers, isReady,
currentUserId, currentUserId,
groupChatMembers,
usersById, usersById,
recentEmojis, recentEmojis,
baseEmojiKeywords, baseEmojiKeywords,
emojiKeywords, emojiKeywords,
onCaptionUpdate,
addRecentEmoji, addRecentEmoji,
onCaptionUpdate,
onSend, onSend,
onFileAppend, onFileAppend,
onClear, onClear,
@ -89,6 +90,7 @@ const AttachmentModal: FC<OwnProps> = ({
onCaptionUpdate, onCaptionUpdate,
baseEmojiKeywords, baseEmojiKeywords,
emojiKeywords, emojiKeywords,
!isReady,
); );
useEffect(() => (isOpen ? captureEscKeyListener(onClear) : undefined), [isOpen, onClear]); useEffect(() => (isOpen ? captureEscKeyListener(onClear) : undefined), [isOpen, onClear]);

View File

@ -93,6 +93,10 @@
} }
} }
&.not-ready > i {
animation-duration: 0ms !important;
}
body.animation-level-0 &, body.animation-level-1 & { body.animation-level-0 &, body.animation-level-1 & {
.icon-send, .icon-microphone-alt, .icon-check { .icon-send, .icon-microphone-alt, .icon-check {
animation-duration: 0ms !important; animation-duration: 0ms !important;
@ -123,6 +127,10 @@
animation: hide-icon .4s forwards ease-out; animation: hide-icon .4s forwards ease-out;
} }
&.not-ready > i {
animation-duration: 0ms !important;
}
&.is-loading { &.is-loading {
.Spinner { .Spinner {
animation: grow-icon .4s ease-out; animation: grow-icon .4s ease-out;
@ -155,7 +163,6 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
.svg-appendix { .svg-appendix {
position: absolute; position: absolute;
bottom: -.1875rem; bottom: -.1875rem;

View File

@ -96,8 +96,8 @@ type OwnProps = {
threadId: number; threadId: number;
messageListType: MessageListType; messageListType: MessageListType;
dropAreaState: string; dropAreaState: string;
onDropHide: NoneToVoidFunction;
isReady: boolean; isReady: boolean;
onDropHide: NoneToVoidFunction;
}; };
type StateProps = { type StateProps = {
@ -160,8 +160,8 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
dropAreaState, dropAreaState,
shouldSchedule, shouldSchedule,
canScheduleUntilOnline, canScheduleUntilOnline,
onDropHide,
isReady, isReady,
onDropHide,
editingMessage, editingMessage,
chatId, chatId,
threadId, threadId,
@ -520,7 +520,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
} }
// Wait until message animation starts // Wait until message animation starts
requestAnimationFrame(() => { resetComposer(); }); requestAnimationFrame(() => {
resetComposer();
});
}, [ }, [
connectionState, attachments, activeVoiceRecording, isForwarding, serverTimeOffset, clearDraft, chatId, connectionState, attachments, activeVoiceRecording, isForwarding, serverTimeOffset, clearDraft, chatId,
resetComposer, stopRecordingVoice, showDialog, slowMode, isAdmin, sendMessage, forwardMessages, lang, resetComposer, stopRecordingVoice, showDialog, slowMode, isAdmin, sendMessage, forwardMessages, lang,
@ -537,7 +539,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
openCalendar(); openCalendar();
} else { } else {
sendMessage({ sticker }); sendMessage({ sticker });
requestAnimationFrame(() => { resetComposer(shouldPreserveInput); }); requestAnimationFrame(() => {
resetComposer(shouldPreserveInput);
});
} }
}, [shouldSchedule, openCalendar, sendMessage, resetComposer]); }, [shouldSchedule, openCalendar, sendMessage, resetComposer]);
@ -547,7 +551,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
openCalendar(); openCalendar();
} else { } else {
sendMessage({ gif }); sendMessage({ gif });
requestAnimationFrame(() => { resetComposer(true); }); requestAnimationFrame(() => {
resetComposer(true);
});
} }
}, [shouldSchedule, openCalendar, sendMessage, resetComposer]); }, [shouldSchedule, openCalendar, sendMessage, resetComposer]);
@ -567,7 +573,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
} }
clearDraft({ chatId, localOnly: true }); clearDraft({ chatId, localOnly: true });
requestAnimationFrame(() => { resetComposer(); }); requestAnimationFrame(() => {
resetComposer();
});
}, [chatId, clearDraft, connectionState, resetComposer, sendInlineBotResult]); }, [chatId, clearDraft, connectionState, resetComposer, sendInlineBotResult]);
const handlePollSend = useCallback((poll: ApiNewPoll) => { const handlePollSend = useCallback((poll: ApiNewPoll) => {
@ -604,7 +612,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
...scheduledMessageArgs, ...scheduledMessageArgs,
scheduledAt, scheduledAt,
}); });
requestAnimationFrame(() => { resetComposer(); }); requestAnimationFrame(() => {
resetComposer();
});
} }
closeCalendar(); closeCalendar();
}, [closeCalendar, handleSend, resetComposer, scheduledMessageArgs, sendMessage, serverTimeOffset]); }, [closeCalendar, handleSend, resetComposer, scheduledMessageArgs, sendMessage, serverTimeOffset]);
@ -674,7 +684,9 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
openCalendar(); openCalendar();
} else { } else {
handleSend(); handleSend();
requestAnimationFrame(() => { resetComposer(); }); requestAnimationFrame(() => {
resetComposer();
});
} }
break; break;
case MainButtonState.Record: case MainButtonState.Record:
@ -723,6 +735,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
const symbolMenuButtonClassName = buildClassName( const symbolMenuButtonClassName = buildClassName(
'mobile-symbol-menu-button', 'mobile-symbol-menu-button',
!isReady && 'not-ready',
isSymbolMenuLoaded isSymbolMenuLoaded
? (isSymbolMenuOpen && 'menu-opened') ? (isSymbolMenuOpen && 'menu-opened')
: (isSymbolMenuOpen && 'is-loading'), : (isSymbolMenuOpen && 'is-loading'),
@ -751,6 +764,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
currentUserId={currentUserId} currentUserId={currentUserId}
usersById={usersById} usersById={usersById}
recentEmojis={recentEmojis} recentEmojis={recentEmojis}
isReady={isReady}
onCaptionUpdate={setHtml} onCaptionUpdate={setHtml}
baseEmojiKeywords={baseEmojiKeywords} baseEmojiKeywords={baseEmojiKeywords}
emojiKeywords={emojiKeywords} emojiKeywords={emojiKeywords}
@ -819,7 +833,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
> >
<i className="icon-smile" /> <i className="icon-smile" />
<i className="icon-keyboard" /> <i className="icon-keyboard" />
{!isSymbolMenuLoaded && <Spinner color="gray" />} {isSymbolMenuOpen && !isSymbolMenuLoaded && <Spinner color="gray" />}
</Button> </Button>
) : ( ) : (
<ResponsiveHoverButton <ResponsiveHoverButton
@ -945,7 +959,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
ref={mainButtonRef} ref={mainButtonRef}
round round
color="secondary" color="secondary"
className={`${mainButtonState} ${activeVoiceRecording ? 'recording' : ''}`} className={buildClassName(mainButtonState, !isReady && 'not-ready', activeVoiceRecording && 'recording')}
disabled={areVoiceMessagesNotAllowed} disabled={areVoiceMessagesNotAllowed}
ariaLabel={lang(sendButtonAriaLabel)} ariaLabel={lang(sendButtonAriaLabel)}
onClick={mainButtonHandler} onClick={mainButtonHandler}