Media Viewer: Fix navigating back in history (#2056)

This commit is contained in:
Alexander Zinchuk 2022-10-10 14:37:46 +02:00
parent e55b78a2dc
commit 15527f925d
4 changed files with 50 additions and 29 deletions

View File

@ -37,7 +37,6 @@ import { renderMessageText } from '../common/helpers/renderMessageText';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import useForceUpdate from '../../hooks/useForceUpdate'; import useForceUpdate from '../../hooks/useForceUpdate';
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck'; import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
import useHistoryBack from '../../hooks/useHistoryBack';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
import { useMediaProps } from './hooks/useMediaProps'; import { useMediaProps } from './hooks/useMediaProps';
@ -64,6 +63,7 @@ type StateProps = {
chatMessages?: Record<number, ApiMessage>; chatMessages?: Record<number, ApiMessage>;
collectionIds?: number[]; collectionIds?: number[];
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
shouldSkipHistoryAnimations?: boolean;
}; };
const ANIMATION_DURATION = 350; const ANIMATION_DURATION = 350;
@ -80,6 +80,7 @@ const MediaViewer: FC<StateProps> = ({
chatMessages, chatMessages,
collectionIds, collectionIds,
animationLevel, animationLevel,
shouldSkipHistoryAnimations,
}) => { }) => {
const { const {
openMediaViewer, openMediaViewer,
@ -95,7 +96,7 @@ const MediaViewer: FC<StateProps> = ({
const animationKey = useRef<number>(); const animationKey = useRef<number>();
const prevSenderId = usePrevious<string | undefined>(senderId); const prevSenderId = usePrevious<string | undefined>(senderId);
const headerAnimation = animationLevel === 2 ? 'slide-fade' : 'none'; const headerAnimation = animationLevel === 2 ? 'slide-fade' : 'none';
const isGhostAnimation = animationLevel === 2; const isGhostAnimation = animationLevel === 2 && !shouldSkipHistoryAnimations;
/* Controls */ /* Controls */
const [isReportModalOpen, openReportModal, closeReportModal] = useFlag(); const [isReportModalOpen, openReportModal, closeReportModal] = useFlag();
@ -184,12 +185,10 @@ const MediaViewer: FC<StateProps> = ({
bestImageData, prevBestImageData, dimensions, isVideo, hasFooter, bestImageData, prevBestImageData, dimensions, isVideo, hasFooter,
]); ]);
const close = useCallback(() => { const handleClose = useCallback(() => closeMediaViewer(), [closeMediaViewer]);
closeMediaViewer();
}, [closeMediaViewer]);
const handleFooterClick = useCallback(() => { const handleFooterClick = useCallback(() => {
close(); handleClose();
if (IS_SINGLE_COLUMN_LAYOUT) { if (IS_SINGLE_COLUMN_LAYOUT) {
setTimeout(() => { setTimeout(() => {
@ -199,7 +198,7 @@ const MediaViewer: FC<StateProps> = ({
} else { } else {
focusMessage({ chatId, threadId, mediaId }); focusMessage({ chatId, threadId, mediaId });
} }
}, [close, chatId, threadId, focusMessage, toggleChatInfo, mediaId]); }, [handleClose, chatId, threadId, focusMessage, toggleChatInfo, mediaId]);
const handleForward = useCallback(() => { const handleForward = useCallback(() => {
openForwardMenu({ openForwardMenu({
@ -221,8 +220,8 @@ const MediaViewer: FC<StateProps> = ({
}, [avatarOwner?.id, chatId, openMediaViewer, origin, threadId]); }, [avatarOwner?.id, chatId, openMediaViewer, origin, threadId]);
useEffect(() => (isOpen ? captureEscKeyListener(() => { useEffect(() => (isOpen ? captureEscKeyListener(() => {
close(); handleClose();
}) : undefined), [close, isOpen]); }) : undefined), [handleClose, isOpen]);
useEffect(() => { useEffect(() => {
if (isVideo && !isGif) { if (isVideo && !isGif) {
@ -235,7 +234,6 @@ const MediaViewer: FC<StateProps> = ({
if (!isOpen) { if (!isOpen) {
return undefined; return undefined;
} }
windowSize.disableRefresh(); windowSize.disableRefresh();
return () => { return () => {
@ -254,11 +252,6 @@ const MediaViewer: FC<StateProps> = ({
const lang = useLang(); const lang = useLang();
useHistoryBack({
isActive: isOpen,
onBack: closeMediaViewer,
});
function renderSenderInfo() { function renderSenderInfo() {
return avatarOwner ? ( return avatarOwner ? (
<SenderInfo <SenderInfo
@ -276,7 +269,7 @@ const MediaViewer: FC<StateProps> = ({
} }
return ( return (
<ShowTransition id="MediaViewer" isOpen={isOpen}> <ShowTransition id="MediaViewer" isOpen={isOpen} noCloseTransition={shouldSkipHistoryAnimations}>
<div className="media-viewer-head" dir={lang.isRtl ? 'rtl' : undefined}> <div className="media-viewer-head" dir={lang.isRtl ? 'rtl' : undefined}>
{IS_SINGLE_COLUMN_LAYOUT && ( {IS_SINGLE_COLUMN_LAYOUT && (
<Button <Button
@ -285,7 +278,7 @@ const MediaViewer: FC<StateProps> = ({
size="smaller" size="smaller"
color="translucent-white" color="translucent-white"
ariaLabel={lang('Close')} ariaLabel={lang('Close')}
onClick={close} onClick={handleClose}
> >
<i className="icon-close" /> <i className="icon-close" />
</Button> </Button>
@ -300,7 +293,7 @@ const MediaViewer: FC<StateProps> = ({
fileName={fileName} fileName={fileName}
canReport={canReport} canReport={canReport}
onReport={openReportModal} onReport={openReportModal}
onCloseMediaViewer={close} onCloseMediaViewer={handleClose}
onForward={handleForward} onForward={handleForward}
zoomLevelChange={zoomLevelChange} zoomLevelChange={zoomLevelChange}
setZoomLevelChange={setZoomLevelChange} setZoomLevelChange={setZoomLevelChange}
@ -328,7 +321,7 @@ const MediaViewer: FC<StateProps> = ({
zoomLevelChange={zoomLevelChange} zoomLevelChange={zoomLevelChange}
isVideo={isVideo} isVideo={isVideo}
animationLevel={animationLevel} animationLevel={animationLevel}
onClose={close} onClose={handleClose}
selectMedia={selectMedia} selectMedia={selectMedia}
onFooterClick={handleFooterClick} onFooterClick={handleFooterClick}
/> />
@ -349,16 +342,18 @@ export default memo(withGlobal(
animationLevel, animationLevel,
} = global.settings.byKey; } = global.settings.byKey;
const { shouldSkipHistoryAnimations } = global;
let isChatWithSelf = !!chatId && selectIsChatWithSelf(global, chatId); let isChatWithSelf = !!chatId && selectIsChatWithSelf(global, chatId);
if (origin === MediaViewerOrigin.SearchResult) { if (origin === MediaViewerOrigin.SearchResult) {
if (!(chatId && mediaId)) { if (!(chatId && mediaId)) {
return { animationLevel }; return { animationLevel, shouldSkipHistoryAnimations };
} }
const message = selectChatMessage(global, chatId, mediaId); const message = selectChatMessage(global, chatId, mediaId);
if (!message) { if (!message) {
return { animationLevel }; return { animationLevel, shouldSkipHistoryAnimations };
} }
return { return {
@ -369,6 +364,7 @@ export default memo(withGlobal(
origin, origin,
message, message,
animationLevel, animationLevel,
shouldSkipHistoryAnimations,
}; };
} }
@ -383,11 +379,12 @@ export default memo(withGlobal(
isChatWithSelf, isChatWithSelf,
animationLevel, animationLevel,
origin, origin,
shouldSkipHistoryAnimations,
}; };
} }
if (!(chatId && threadId && mediaId)) { if (!(chatId && threadId && mediaId)) {
return { animationLevel }; return { animationLevel, shouldSkipHistoryAnimations };
} }
let message: ApiMessage | undefined; let message: ApiMessage | undefined;
@ -398,7 +395,7 @@ export default memo(withGlobal(
} }
if (!message) { if (!message) {
return { animationLevel }; return { animationLevel, shouldSkipHistoryAnimations };
} }
let chatMessages: Record<number, ApiMessage> | undefined; let chatMessages: Record<number, ApiMessage> | undefined;
@ -429,6 +426,7 @@ export default memo(withGlobal(
chatMessages, chatMessages,
collectionIds, collectionIds,
animationLevel, animationLevel,
shouldSkipHistoryAnimations,
}; };
}, },
)(MediaViewer)); )(MediaViewer));

View File

@ -19,6 +19,7 @@ import useLang from '../../hooks/useLang';
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
import useTimeout from '../../hooks/useTimeout'; import useTimeout from '../../hooks/useTimeout';
import useWindowSize from '../../hooks/useWindowSize'; import useWindowSize from '../../hooks/useWindowSize';
import useHistoryBack from '../../hooks/useHistoryBack';
import MediaViewerContent from './MediaViewerContent'; import MediaViewerContent from './MediaViewerContent';
@ -104,6 +105,12 @@ const MediaViewerSlides: FC<OwnProps> = ({
const lang = useLang(); const lang = useLang();
useHistoryBack({
isActive: isOpen,
onBack: onClose,
shouldBeReplaced: true,
});
const setTransform = useCallback((value: Transform) => { const setTransform = useCallback((value: Transform) => {
transformRef.current = value; transformRef.current = value;
forceUpdate(); forceUpdate();
@ -370,7 +377,7 @@ const MediaViewerSlides: FC<OwnProps> = ({
onUpdate: (value) => setTransform({ onUpdate: (value) => setTransform({
y: 0, y: 0,
x: value, x: value,
scale: transformRef.current.scale, scale: transformRef.current?.scale ?? 1,
}), }),
}); });
}; };

View File

@ -11,14 +11,24 @@ type OwnProps = {
id?: string; id?: string;
className?: string; className?: string;
onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void; onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
noCloseTransition?: boolean;
children: React.ReactNode; children: React.ReactNode;
}; };
const ShowTransition: FC<OwnProps> = ({ const ShowTransition: FC<OwnProps> = ({
isOpen, isCustom, id, className, onClick, children, isOpen,
isCustom,
id,
className,
onClick,
noCloseTransition,
children,
}) => { }) => {
const { shouldRender, transitionClassNames } = useShowTransition( const {
isOpen, undefined, undefined, isCustom ? false : undefined, shouldRender,
transitionClassNames,
} = useShowTransition(
isOpen, undefined, undefined, isCustom ? false : undefined, noCloseTransition,
); );
const prevIsOpen = usePrevious(isOpen); const prevIsOpen = usePrevious(isOpen);
const prevChildren = usePrevious(children); const prevChildren = usePrevious(children);

View File

@ -142,12 +142,15 @@ function cleanupClosed(alreadyClosedCount = 1) {
function cleanupTrashedState() { function cleanupTrashedState() {
// Navigation to previous page reload, state of which was trashed by reload // Navigation to previous page reload, state of which was trashed by reload
let isAnimationDisabled = false;
for (let i = historyState.length - 1; i > 0; i--) { for (let i = historyState.length - 1; i > 0; i--) {
if (historyState[i].isClosed) { if (historyState[i].isClosed) {
continue; continue;
} }
if (isSafariGestureAnimation) { // TODO[history]: probably we should not call this inside the loop
if (!isAnimationDisabled && isSafariGestureAnimation) {
getActions().disableHistoryAnimations(); getActions().disableHistoryAnimations();
isAnimationDisabled = true;
} }
historyState[i].onBack?.(); historyState[i].onBack?.();
} }
@ -188,13 +191,16 @@ window.addEventListener('popstate', ({ state }: PopStateEvent) => {
if (index < historyCursor) { if (index < historyCursor) {
// Navigating back // Navigating back
let alreadyClosedCount = 0; let alreadyClosedCount = 0;
let isAnimationDisabled = false;
for (let i = historyCursor; i > index - alreadyClosedCount; i--) { for (let i = historyCursor; i > index - alreadyClosedCount; i--) {
if (historyState[i].isClosed) { if (historyState[i].isClosed) {
alreadyClosedCount++; alreadyClosedCount++;
continue; continue;
} }
if (isSafariGestureAnimation) { // TODO[history]: probably we should not call this inside the loop
if (!isAnimationDisabled && isSafariGestureAnimation) {
getActions().disableHistoryAnimations(); getActions().disableHistoryAnimations();
isAnimationDisabled = true;
} }
historyState[i].onBack?.(); historyState[i].onBack?.();
} }