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 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<number, ApiMessage>;
collectionIds?: number[];
animationLevel: AnimationLevel;
shouldSkipHistoryAnimations?: boolean;
};
const ANIMATION_DURATION = 350;
@ -80,6 +80,7 @@ const MediaViewer: FC<StateProps> = ({
chatMessages,
collectionIds,
animationLevel,
shouldSkipHistoryAnimations,
}) => {
const {
openMediaViewer,
@ -95,7 +96,7 @@ const MediaViewer: FC<StateProps> = ({
const animationKey = useRef<number>();
const prevSenderId = usePrevious<string | undefined>(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<StateProps> = ({
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<StateProps> = ({
} 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<StateProps> = ({
}, [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<StateProps> = ({
if (!isOpen) {
return undefined;
}
windowSize.disableRefresh();
return () => {
@ -254,11 +252,6 @@ const MediaViewer: FC<StateProps> = ({
const lang = useLang();
useHistoryBack({
isActive: isOpen,
onBack: closeMediaViewer,
});
function renderSenderInfo() {
return avatarOwner ? (
<SenderInfo
@ -276,7 +269,7 @@ const MediaViewer: FC<StateProps> = ({
}
return (
<ShowTransition id="MediaViewer" isOpen={isOpen}>
<ShowTransition id="MediaViewer" isOpen={isOpen} noCloseTransition={shouldSkipHistoryAnimations}>
<div className="media-viewer-head" dir={lang.isRtl ? 'rtl' : undefined}>
{IS_SINGLE_COLUMN_LAYOUT && (
<Button
@ -285,7 +278,7 @@ const MediaViewer: FC<StateProps> = ({
size="smaller"
color="translucent-white"
ariaLabel={lang('Close')}
onClick={close}
onClick={handleClose}
>
<i className="icon-close" />
</Button>
@ -300,7 +293,7 @@ const MediaViewer: FC<StateProps> = ({
fileName={fileName}
canReport={canReport}
onReport={openReportModal}
onCloseMediaViewer={close}
onCloseMediaViewer={handleClose}
onForward={handleForward}
zoomLevelChange={zoomLevelChange}
setZoomLevelChange={setZoomLevelChange}
@ -328,7 +321,7 @@ const MediaViewer: FC<StateProps> = ({
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<number, ApiMessage> | undefined;
@ -429,6 +426,7 @@ export default memo(withGlobal(
chatMessages,
collectionIds,
animationLevel,
shouldSkipHistoryAnimations,
};
},
)(MediaViewer));

View File

@ -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<OwnProps> = ({
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<OwnProps> = ({
onUpdate: (value) => setTransform({
y: 0,
x: value,
scale: transformRef.current.scale,
scale: transformRef.current?.scale ?? 1,
}),
});
};

View File

@ -11,14 +11,24 @@ type OwnProps = {
id?: string;
className?: string;
onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
noCloseTransition?: boolean;
children: React.ReactNode;
};
const ShowTransition: FC<OwnProps> = ({
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);

View File

@ -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?.();
}