diff --git a/src/components/mediaViewer/MediaViewer.tsx b/src/components/mediaViewer/MediaViewer.tsx index 55c824361..daa3260b2 100644 --- a/src/components/mediaViewer/MediaViewer.tsx +++ b/src/components/mediaViewer/MediaViewer.tsx @@ -37,7 +37,6 @@ import { renderMessageText } from '../common/helpers/renderMessageText'; import useFlag from '../../hooks/useFlag'; import useForceUpdate from '../../hooks/useForceUpdate'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; -import useHistoryBack from '../../hooks/useHistoryBack'; import useLang from '../../hooks/useLang'; import usePrevious from '../../hooks/usePrevious'; import { useMediaProps } from './hooks/useMediaProps'; @@ -64,6 +63,7 @@ type StateProps = { chatMessages?: Record; collectionIds?: number[]; animationLevel: AnimationLevel; + shouldSkipHistoryAnimations?: boolean; }; const ANIMATION_DURATION = 350; @@ -80,6 +80,7 @@ const MediaViewer: FC = ({ chatMessages, collectionIds, animationLevel, + shouldSkipHistoryAnimations, }) => { const { openMediaViewer, @@ -95,7 +96,7 @@ const MediaViewer: FC = ({ const animationKey = useRef(); const prevSenderId = usePrevious(senderId); const headerAnimation = animationLevel === 2 ? 'slide-fade' : 'none'; - const isGhostAnimation = animationLevel === 2; + const isGhostAnimation = animationLevel === 2 && !shouldSkipHistoryAnimations; /* Controls */ const [isReportModalOpen, openReportModal, closeReportModal] = useFlag(); @@ -184,12 +185,10 @@ const MediaViewer: FC = ({ bestImageData, prevBestImageData, dimensions, isVideo, hasFooter, ]); - const close = useCallback(() => { - closeMediaViewer(); - }, [closeMediaViewer]); + const handleClose = useCallback(() => closeMediaViewer(), [closeMediaViewer]); const handleFooterClick = useCallback(() => { - close(); + handleClose(); if (IS_SINGLE_COLUMN_LAYOUT) { setTimeout(() => { @@ -199,7 +198,7 @@ const MediaViewer: FC = ({ } else { focusMessage({ chatId, threadId, mediaId }); } - }, [close, chatId, threadId, focusMessage, toggleChatInfo, mediaId]); + }, [handleClose, chatId, threadId, focusMessage, toggleChatInfo, mediaId]); const handleForward = useCallback(() => { openForwardMenu({ @@ -221,8 +220,8 @@ const MediaViewer: FC = ({ }, [avatarOwner?.id, chatId, openMediaViewer, origin, threadId]); useEffect(() => (isOpen ? captureEscKeyListener(() => { - close(); - }) : undefined), [close, isOpen]); + handleClose(); + }) : undefined), [handleClose, isOpen]); useEffect(() => { if (isVideo && !isGif) { @@ -235,7 +234,6 @@ const MediaViewer: FC = ({ if (!isOpen) { return undefined; } - windowSize.disableRefresh(); return () => { @@ -254,11 +252,6 @@ const MediaViewer: FC = ({ const lang = useLang(); - useHistoryBack({ - isActive: isOpen, - onBack: closeMediaViewer, - }); - function renderSenderInfo() { return avatarOwner ? ( = ({ } return ( - +
{IS_SINGLE_COLUMN_LAYOUT && ( @@ -300,7 +293,7 @@ const MediaViewer: FC = ({ fileName={fileName} canReport={canReport} onReport={openReportModal} - onCloseMediaViewer={close} + onCloseMediaViewer={handleClose} onForward={handleForward} zoomLevelChange={zoomLevelChange} setZoomLevelChange={setZoomLevelChange} @@ -328,7 +321,7 @@ const MediaViewer: FC = ({ zoomLevelChange={zoomLevelChange} isVideo={isVideo} animationLevel={animationLevel} - onClose={close} + onClose={handleClose} selectMedia={selectMedia} onFooterClick={handleFooterClick} /> @@ -349,16 +342,18 @@ export default memo(withGlobal( animationLevel, } = global.settings.byKey; + const { shouldSkipHistoryAnimations } = global; + let isChatWithSelf = !!chatId && selectIsChatWithSelf(global, chatId); if (origin === MediaViewerOrigin.SearchResult) { if (!(chatId && mediaId)) { - return { animationLevel }; + return { animationLevel, shouldSkipHistoryAnimations }; } const message = selectChatMessage(global, chatId, mediaId); if (!message) { - return { animationLevel }; + return { animationLevel, shouldSkipHistoryAnimations }; } return { @@ -369,6 +364,7 @@ export default memo(withGlobal( origin, message, animationLevel, + shouldSkipHistoryAnimations, }; } @@ -383,11 +379,12 @@ export default memo(withGlobal( isChatWithSelf, animationLevel, origin, + shouldSkipHistoryAnimations, }; } if (!(chatId && threadId && mediaId)) { - return { animationLevel }; + return { animationLevel, shouldSkipHistoryAnimations }; } let message: ApiMessage | undefined; @@ -398,7 +395,7 @@ export default memo(withGlobal( } if (!message) { - return { animationLevel }; + return { animationLevel, shouldSkipHistoryAnimations }; } let chatMessages: Record | undefined; @@ -429,6 +426,7 @@ export default memo(withGlobal( chatMessages, collectionIds, animationLevel, + shouldSkipHistoryAnimations, }; }, )(MediaViewer)); diff --git a/src/components/mediaViewer/MediaViewerSlides.tsx b/src/components/mediaViewer/MediaViewerSlides.tsx index 934bd09e5..9c2382793 100644 --- a/src/components/mediaViewer/MediaViewerSlides.tsx +++ b/src/components/mediaViewer/MediaViewerSlides.tsx @@ -19,6 +19,7 @@ import useLang from '../../hooks/useLang'; import usePrevious from '../../hooks/usePrevious'; import useTimeout from '../../hooks/useTimeout'; import useWindowSize from '../../hooks/useWindowSize'; +import useHistoryBack from '../../hooks/useHistoryBack'; import MediaViewerContent from './MediaViewerContent'; @@ -104,6 +105,12 @@ const MediaViewerSlides: FC = ({ const lang = useLang(); + useHistoryBack({ + isActive: isOpen, + onBack: onClose, + shouldBeReplaced: true, + }); + const setTransform = useCallback((value: Transform) => { transformRef.current = value; forceUpdate(); @@ -370,7 +377,7 @@ const MediaViewerSlides: FC = ({ onUpdate: (value) => setTransform({ y: 0, x: value, - scale: transformRef.current.scale, + scale: transformRef.current?.scale ?? 1, }), }); }; diff --git a/src/components/ui/ShowTransition.tsx b/src/components/ui/ShowTransition.tsx index 530c3e865..e33d4e4c3 100644 --- a/src/components/ui/ShowTransition.tsx +++ b/src/components/ui/ShowTransition.tsx @@ -11,14 +11,24 @@ type OwnProps = { id?: string; className?: string; onClick?: (e: React.MouseEvent) => void; + noCloseTransition?: boolean; children: React.ReactNode; }; const ShowTransition: FC = ({ - isOpen, isCustom, id, className, onClick, children, + isOpen, + isCustom, + id, + className, + onClick, + noCloseTransition, + children, }) => { - const { shouldRender, transitionClassNames } = useShowTransition( - isOpen, undefined, undefined, isCustom ? false : undefined, + const { + shouldRender, + transitionClassNames, + } = useShowTransition( + isOpen, undefined, undefined, isCustom ? false : undefined, noCloseTransition, ); const prevIsOpen = usePrevious(isOpen); const prevChildren = usePrevious(children); diff --git a/src/hooks/useHistoryBack.ts b/src/hooks/useHistoryBack.ts index 769fbb9f7..f28f67021 100644 --- a/src/hooks/useHistoryBack.ts +++ b/src/hooks/useHistoryBack.ts @@ -142,12 +142,15 @@ function cleanupClosed(alreadyClosedCount = 1) { function cleanupTrashedState() { // Navigation to previous page reload, state of which was trashed by reload + let isAnimationDisabled = false; for (let i = historyState.length - 1; i > 0; i--) { if (historyState[i].isClosed) { continue; } - if (isSafariGestureAnimation) { + // TODO[history]: probably we should not call this inside the loop + if (!isAnimationDisabled && isSafariGestureAnimation) { getActions().disableHistoryAnimations(); + isAnimationDisabled = true; } historyState[i].onBack?.(); } @@ -188,13 +191,16 @@ window.addEventListener('popstate', ({ state }: PopStateEvent) => { if (index < historyCursor) { // Navigating back let alreadyClosedCount = 0; + let isAnimationDisabled = false; for (let i = historyCursor; i > index - alreadyClosedCount; i--) { if (historyState[i].isClosed) { alreadyClosedCount++; continue; } - if (isSafariGestureAnimation) { + // TODO[history]: probably we should not call this inside the loop + if (!isAnimationDisabled && isSafariGestureAnimation) { getActions().disableHistoryAnimations(); + isAnimationDisabled = true; } historyState[i].onBack?.(); }