127 lines
3.5 KiB
TypeScript

import React, {
FC, memo, useCallback, useEffect, useRef, useState,
} from '../../lib/teact/teact';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import buildClassName from '../../util/buildClassName';
import usePrevious from '../../hooks/usePrevious';
import useShowTransition from '../../hooks/useShowTransition';
import useLang from '../../hooks/useLang';
import Button from '../ui/Button';
import './ZoomControls.scss';
type OwnProps = {
isShown: boolean;
onChangeZoom: (level: number, canCloseZoom?: boolean) => void;
};
export const MAX_ZOOM_LEVEL = 3;
export const MIN_ZOOM_LEVEL = 1;
const ONE_STEP_PERCENT = 100 / (MAX_ZOOM_LEVEL - MIN_ZOOM_LEVEL);
const RESET_ZOOM_LEVEL = 1.5;
const ZoomControls: FC<OwnProps> = ({ isShown, onChangeZoom }) => {
const { transitionClassNames } = useShowTransition(isShown);
const prevIsShown = usePrevious<boolean>(isShown);
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const [zoomLevel, setZoomLevel] = useState(1);
const isSeeking = useRef<boolean>(false);
useEffect(() => {
if (isShown && !prevIsShown) {
setZoomLevel(RESET_ZOOM_LEVEL);
}
}, [isShown, prevIsShown]);
const handleZoomOut = () => {
if (inputRef.current) {
setZoomLevel(Math.max(MIN_ZOOM_LEVEL, zoomLevel - 0.5));
}
};
const handleZoomIn = () => {
if (inputRef.current) {
setZoomLevel(Math.min(MAX_ZOOM_LEVEL, zoomLevel + 0.5));
}
};
const handleStartSeek = useCallback(() => {
isSeeking.current = true;
}, []);
const handleStopSeek = useCallback(() => {
isSeeking.current = false;
if (zoomLevel === 1) {
onChangeZoom(zoomLevel, !isSeeking.current);
}
}, [onChangeZoom, zoomLevel]);
const handleSeeklineChange = (e:React.ChangeEvent<HTMLInputElement>) => {
setZoomLevel(Math.min(MAX_ZOOM_LEVEL, Math.max(Number(e.target.value), MIN_ZOOM_LEVEL)));
};
useEffect(() => {
onChangeZoom(zoomLevel, !isSeeking.current);
}, [zoomLevel, onChangeZoom]);
const lang = useLang();
const className = buildClassName(
'ZoomControls',
transitionClassNames,
);
return (
<div className={className}>
<Button
disabled={zoomLevel === MIN_ZOOM_LEVEL}
size="tiny"
color="translucent-white"
ariaLabel={lang('ZoomOut')}
className="zoom-out"
ripple={!IS_SINGLE_COLUMN_LAYOUT}
onClick={handleZoomOut}
>
<i className="icon-zoom-out" />
</Button>
<Button
disabled={zoomLevel === MAX_ZOOM_LEVEL}
size="tiny"
color="translucent-white"
ariaLabel="Zoom In"
className="zoom-in"
ripple={!IS_SINGLE_COLUMN_LAYOUT}
onClick={handleZoomIn}
>
<i className="icon-zoom-in" />
</Button>
<div className="seekline">
<div className="seekline-track">
<div
className="seekline-played"
// @ts-ignore teact feature
style={`width: ${(zoomLevel - 1) * ONE_STEP_PERCENT}%`}
/>
<input
ref={inputRef}
min={MIN_ZOOM_LEVEL}
max={MAX_ZOOM_LEVEL}
step="0.5"
value={zoomLevel}
type="range"
className="seekline-input"
onChange={handleSeeklineChange}
onMouseDown={handleStartSeek}
onMouseUp={handleStopSeek}
/>
</div>
</div>
</div>
);
};
export default memo(ZoomControls);