Media Viewer: Allow to hide caption by tap on mobile (#1196)

This commit is contained in:
Alexander Zinchuk 2021-06-22 13:54:25 +03:00
parent c6550ca3e4
commit 2c7c23715c
49 changed files with 169 additions and 135 deletions

View File

@ -8,7 +8,7 @@ import {
} from '../../api/types';
import { ISettings } from '../../types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { formatMediaDateTime, formatMediaDuration, formatPastTimeShort } from '../../util/dateFormat';
import {
getMediaDuration,
@ -65,8 +65,8 @@ interface ISeekMethods {
}
const AVG_VOICE_DURATION = 30;
const MIN_SPIKES = IS_MOBILE_SCREEN ? 20 : 25;
const MAX_SPIKES = IS_MOBILE_SCREEN ? 50 : 75;
const MIN_SPIKES = IS_SINGLE_COLUMN_LAYOUT ? 20 : 25;
const MAX_SPIKES = IS_SINGLE_COLUMN_LAYOUT ? 50 : 75;
// This is needed for browsers requiring user interaction before playing.
const PRELOAD = true;
@ -286,7 +286,7 @@ const Audio: FC<OwnProps & StateProps> = ({
)}
<Button
round
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
size={renderingFor ? 'smaller' : 'tiny'}
className={buttonClassNames.join(' ')}
ariaLabel={isPlaying ? 'Pause audio' : 'Play audio'}

View File

@ -6,7 +6,7 @@ import buildClassName from '../../util/buildClassName';
import {
formatMonthAndYear, formatHumanDate, formatTime,
} from '../../util/dateFormat';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import useLang, { LangFn } from '../../hooks/useLang';
import Modal from '../ui/Modal';
@ -183,7 +183,7 @@ const CalendarModal: FC<OwnProps> = ({
</Button>
<h4>
{formatMonthAndYear(lang, selectedDate, IS_MOBILE_SCREEN)}
{formatMonthAndYear(lang, selectedDate, IS_SINGLE_COLUMN_LAYOUT)}
</h4>
<Button

View File

@ -4,7 +4,7 @@ import React, {
} from '../../lib/teact/teact';
import { MIN_PASSWORD_LENGTH } from '../../config';
import { IS_TOUCH_ENV, IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_TOUCH_ENV, IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import buildClassName from '../../util/buildClassName';
import useLang from '../../hooks/useLang';
@ -23,7 +23,7 @@ type OwnProps = {
onSubmit: (password: string) => void;
};
const FOCUS_DELAY_TIMEOUT_MS = IS_MOBILE_SCREEN ? 550 : 400;
const FOCUS_DELAY_TIMEOUT_MS = IS_SINGLE_COLUMN_LAYOUT ? 550 : 400;
const PasswordForm: FC<OwnProps> = ({
isLoading = false,

View File

@ -3,7 +3,7 @@ import React, {
} from '../../lib/teact/teact';
import { STICKER_SIZE_AUTH, STICKER_SIZE_AUTH_MOBILE, STICKER_SIZE_TWO_FA } from '../../config';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import getAnimationData from './helpers/animatedAssets';
import AnimatedSticker from './AnimatedSticker';
@ -19,7 +19,7 @@ const PEEK_MONKEY_SHOW_DELAY = 2000;
const SEGMENT_COVER_EYES: [number, number] = [0, 50];
const SEGMENT_UNCOVER_EYE: [number, number] = [0, 20];
const SEGMENT_COVER_EYE: [number, number] = [20, 0];
const STICKER_SIZE = IS_MOBILE_SCREEN ? STICKER_SIZE_AUTH_MOBILE : STICKER_SIZE_AUTH;
const STICKER_SIZE = IS_SINGLE_COLUMN_LAYOUT ? STICKER_SIZE_AUTH_MOBILE : STICKER_SIZE_AUTH;
const PasswordMonkey: FC<OwnProps> = ({ isPasswordVisible, isBig }) => {
const [closeMonkeyData, setCloseMonkeyData] = useState<Record<string, any>>();

View File

@ -3,7 +3,7 @@ import React, {
} from '../../lib/teact/teact';
import { STICKER_SIZE_AUTH, STICKER_SIZE_AUTH_MOBILE, STICKER_SIZE_TWO_FA } from '../../config';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import getAnimationData from './helpers/animatedAssets';
import AnimatedSticker from './AnimatedSticker';
@ -20,7 +20,7 @@ type OwnProps = {
const TRACKING_START_FRAME = 15;
const TRACKING_END_FRAME = 180;
const STICKER_SIZE = IS_MOBILE_SCREEN ? STICKER_SIZE_AUTH_MOBILE : STICKER_SIZE_AUTH;
const STICKER_SIZE = IS_SINGLE_COLUMN_LAYOUT ? STICKER_SIZE_AUTH_MOBILE : STICKER_SIZE_AUTH;
const TrackingMonkey: FC<OwnProps> = ({
code,

View File

@ -1,7 +1,7 @@
import { ApiPhoto, ApiVideo, ApiSticker } from '../../../api/types';
import { getPhotoInlineDimensions, getVideoDimensions, IDimensions } from '../../../modules/helpers';
import windowSize from '../../../util/windowSize';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import { STICKER_SIZE_INLINE_DESKTOP_FACTOR, STICKER_SIZE_INLINE_MOBILE_FACTOR } from '../../../config';
export const MEDIA_VIEWER_MEDIA_QUERY = '(max-height: 640px)';
@ -17,7 +17,7 @@ let cachedMaxWidth: number | undefined;
function getMaxMessageWidthRem(fromOwnMessage: boolean) {
const regularMaxWidth = fromOwnMessage ? 30 : 29;
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
return regularMaxWidth;
}
@ -154,7 +154,11 @@ export function getStickerDimensions(sticker: ApiSticker): IDimensions {
}
const aspectRatio = (height && width) && height / width;
const baseWidth = (IS_MOBILE_SCREEN ? STICKER_SIZE_INLINE_MOBILE_FACTOR : STICKER_SIZE_INLINE_DESKTOP_FACTOR) * REM;
const baseWidth = REM * (
IS_SINGLE_COLUMN_LAYOUT
? STICKER_SIZE_INLINE_MOBILE_FACTOR
: STICKER_SIZE_INLINE_DESKTOP_FACTOR
);
const calculatedHeight = aspectRatio ? baseWidth * aspectRatio : baseWidth;
if (aspectRatio && calculatedHeight > baseWidth) {

View File

@ -6,7 +6,7 @@ import { withGlobal } from '../../lib/teact/teactn';
import { GlobalActions } from '../../global/types';
import { LeftColumnContent, SettingsScreens } from '../../types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import captureEscKeyListener from '../../util/captureEscKeyListener';
import { pick } from '../../util/iteratees';
@ -240,7 +240,7 @@ const LeftColumn: FC<StateProps & DispatchProps> = ({
return (
<Transition
id="LeftColumn"
name={IS_MOBILE_SCREEN ? 'slide-layers' : 'push-slide'}
name={IS_SINGLE_COLUMN_LAYOUT ? 'slide-layers' : 'push-slide'}
renderCount={RENDER_COUNT}
activeKey={contentType}
>

View File

@ -11,7 +11,7 @@ import {
} from '../../../api/types';
import { ANIMATION_END_DELAY } from '../../../config';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import {
getChatTitle,
isChatPrivate,
@ -241,7 +241,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
const className = buildClassName(
'Chat chat-item-clickable',
isChatPrivate(chatId) ? 'private' : 'group',
isSelected && !IS_MOBILE_SCREEN && 'selected',
isSelected && !IS_SINGLE_COLUMN_LAYOUT && 'selected',
);
return (
@ -249,7 +249,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
ref={ref}
className={className}
style={style}
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
contextActions={contextActions}
onClick={handleClick}
>

View File

@ -6,7 +6,7 @@ import { withGlobal } from '../../../lib/teact/teactn';
import { GlobalActions } from '../../../global/types';
import { ApiUser } from '../../../api/types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import { throttle } from '../../../util/schedulers';
import searchWords from '../../../util/searchWords';
import { pick } from '../../../util/iteratees';
@ -77,7 +77,7 @@ const ContactList: FC<OwnProps & StateProps & DispatchProps> = ({
key={id}
className="chat-item-clickable"
onClick={() => handleClick(id)}
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
>
<PrivateChatInfo userId={id} forceShowSelf avatarSize="large" />
</ListItem>

View File

@ -8,7 +8,7 @@ import { LeftColumnContent, ISettings } from '../../../types';
import { ApiChat } from '../../../api/types';
import { APP_NAME, APP_VERSION, FEEDBACK_URL } from '../../../config';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName';
import { pick } from '../../../util/iteratees';
import { isChatArchived } from '../../../modules/helpers';
@ -109,7 +109,7 @@ const LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({
return ({ onTrigger, isOpen }) => (
<Button
round
ripple={hasMenu && !IS_MOBILE_SCREEN}
ripple={hasMenu && !IS_SINGLE_COLUMN_LAYOUT}
size="smaller"
color="translucent"
className={isOpen ? 'active' : ''}

View File

@ -4,7 +4,7 @@ import React, {
import { LeftColumnContent } from '../../../types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import Transition from '../../ui/Transition';
import NewChatStep1 from './NewChatStep1';
@ -36,7 +36,7 @@ const NewChat: FC<OwnProps> = ({
return (
<Transition
id="NewChat"
name={IS_MOBILE_SCREEN ? 'slide-layers' : 'push-slide'}
name={IS_SINGLE_COLUMN_LAYOUT ? 'slide-layers' : 'push-slide'}
renderCount={RENDER_COUNT}
activeKey={content}
>

View File

@ -8,7 +8,7 @@ import {
ApiChat, ApiUser, ApiMessage, ApiMessageOutgoingStatus,
} from '../../../api/types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import {
getChatTitle,
getPrivateChatUserId,
@ -76,7 +76,7 @@ const ChatMessage: FC<OwnProps & StateProps & DispatchProps> = ({
return (
<ListItem
className="ChatMessage chat-item-clickable"
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
onClick={handleClick}
buttonRef={buttonRef}
>

View File

@ -7,7 +7,7 @@ import { ApiUser, ApiChat, ApiMessage } from '../../../api/types';
import { GlobalActions } from '../../../global/types';
import { LoadMoreDirection } from '../../../types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import searchWords from '../../../util/searchWords';
import { unique, pick } from '../../../util/iteratees';
import { getUserFullName, getMessageSummaryText, sortChatIds } from '../../../modules/helpers';
@ -88,7 +88,7 @@ const ChatResults: FC<OwnProps & StateProps & DispatchProps> = ({
addRecentlyFoundChatId({ id });
}
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
onReset();
}
},

View File

@ -2,7 +2,7 @@ import React, { FC, memo, useCallback } from '../../../lib/teact/teact';
import { SettingsScreens } from '../../../types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import useFoldersReducer from '../../../hooks/reducers/useFoldersReducer';
import useTwoFaReducer from '../../../hooks/reducers/useTwoFaReducer';
@ -213,7 +213,7 @@ const Settings: FC<OwnProps> = ({
return (
<Transition
id="Settings"
name={IS_MOBILE_SCREEN ? 'slide-layers' : 'push-slide'}
name={IS_SINGLE_COLUMN_LAYOUT ? 'slide-layers' : 'push-slide'}
activeKey={currentScreen}
renderCount={TRANSITION_RENDER_COUNT}
>

View File

@ -6,7 +6,7 @@ import { withGlobal } from '../../../lib/teact/teactn';
import { GlobalActions } from '../../../global/types';
import { SettingsScreens } from '../../../types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import { pick } from '../../../util/iteratees';
import useLang from '../../../hooks/useLang';
@ -66,7 +66,7 @@ const SettingsHeader: FC<OwnProps & DispatchProps> = ({
return ({ onTrigger, isOpen }) => (
<Button
round
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
size="smaller"
color="translucent"
className={isOpen ? 'active' : ''}

View File

@ -5,7 +5,7 @@ import { withGlobal } from '../../../../lib/teact/teactn';
import { ApiSticker } from '../../../../api/types';
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV } from '../../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../../../util/environment';
import { selectAnimatedEmoji } from '../../../../modules/selectors';
import useLang from '../../../../hooks/useLang';
@ -25,7 +25,7 @@ type StateProps = {
codeLength: number;
};
const FOCUS_DELAY_TIMEOUT_MS = IS_MOBILE_SCREEN ? 550 : 400;
const FOCUS_DELAY_TIMEOUT_MS = IS_SINGLE_COLUMN_LAYOUT ? 550 : 400;
const SettingsTwoFaEmailCode: FC<OwnProps & StateProps> = ({
animatedEmoji,

View File

@ -5,7 +5,7 @@ import { withGlobal } from '../../../../lib/teact/teactn';
import { ApiSticker } from '../../../../api/types';
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV } from '../../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../../../util/environment';
import { selectAnimatedEmoji } from '../../../../modules/selectors';
import useFlag from '../../../../hooks/useFlag';
import useLang from '../../../../hooks/useLang';
@ -31,7 +31,7 @@ type StateProps = {
animatedEmoji: ApiSticker;
};
const FOCUS_DELAY_TIMEOUT_MS = IS_MOBILE_SCREEN ? 550 : 400;
const FOCUS_DELAY_TIMEOUT_MS = IS_SINGLE_COLUMN_LAYOUT ? 550 : 400;
const SettingsTwoFaSkippableForm: FC<OwnProps & StateProps> = ({
animatedEmoji,

View File

@ -6,7 +6,7 @@ import { withGlobal } from '../../lib/teact/teactn';
import { GlobalActions } from '../../global/types';
import { ApiChat, MAIN_THREAD_ID } from '../../api/types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import {
getCanPostInChat, getChatTitle, isChatPrivate, sortChatIds,
} from '../../modules/helpers';
@ -65,7 +65,7 @@ const ForwardPicker: FC<OwnProps & StateProps & DispatchProps> = ({
useEffect(() => {
if (isOpen) {
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
setTimeout(() => {
requestAnimationFrame(() => {
if (inputRef.current) {

View File

@ -10,7 +10,7 @@ import {
import { MediaViewerOrigin } from '../../types';
import { ANIMATION_END_DELAY } from '../../config';
import { IS_IOS, IS_MOBILE_SCREEN, IS_TOUCH_ENV } from '../../util/environment';
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/environment';
import {
AVATAR_FULL_DIMENSIONS,
MEDIA_VIEWER_MEDIA_QUERY,
@ -126,6 +126,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
const [isZoomed, setIsZoomed] = useState<boolean>(false);
const [zoomLevel, setZoomLevel] = useState<number>(1);
const [panDelta, setPanDelta] = useState({ x: 0, y: 0 });
const [isFooterHidden, setIsFooterHidden] = useState<boolean>(false);
const messageIds = useMemo(() => {
return isWebPagePhoto && messageId
@ -189,7 +190,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
const videoDimensions = isVideo ? getVideoDimensions(getMessageVideo(message!)!) : undefined;
useEffect(() => {
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
return;
}
@ -373,7 +374,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
// eslint-disable-next-line max-len
excludedClosestSelector: `.backdrop, .navigation, .media-viewer-head, .media-viewer-footer${!shouldCloseOnVideo ? ', .VideoPlayer' : ''}`,
onClick: () => {
if (!isZoomed) {
if (!isZoomed && !IS_TOUCH_ENV) {
close();
}
},
@ -382,17 +383,23 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
selectPreviousMedia();
} else if (direction === SwipeDirection.Left) {
selectNextMedia();
} else {
} else if (!(e.target && (e.target as HTMLElement).closest('.MediaViewerFooter'))) {
close();
}
} : undefined,
});
}, [close, isGif, isZoomed, selectNextMedia, selectPreviousMedia, canPanZoomWrap]);
}, [close, isFooterHidden, isGif, isPhoto, isZoomed, selectNextMedia, selectPreviousMedia]);
const handlePan = useCallback((x: number, y: number) => {
setPanDelta({ x, y });
}, []);
const handleToggleFooterVisibility = useCallback(() => {
if (IS_TOUCH_ENV && (isPhoto || isGif)) {
setIsFooterHidden(!isFooterHidden);
}
}, [isFooterHidden, isGif, isPhoto]);
const lang = useLang();
function renderSlide(isActive: boolean) {
@ -402,7 +409,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
{renderPhoto(
fullMediaData || blobUrlPreview,
calculateMediaViewerDimensions(AVATAR_FULL_DIMENSIONS, false),
!IS_MOBILE_SCREEN && !isZoomed,
!IS_SINGLE_COLUMN_LAYOUT && !isZoomed,
)}
</div>
);
@ -411,11 +418,15 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
const hasFooter = Boolean(textParts);
return (
<div key={messageId} className={`media-viewer-content ${hasFooter ? 'has-footer' : ''}`}>
<div
key={messageId}
className={`media-viewer-content ${hasFooter ? 'has-footer' : ''}`}
onClick={handleToggleFooterVisibility}
>
{isPhoto && renderPhoto(
localBlobUrl || fullMediaData || blobUrlPreview || blobUrlPictogram,
message && calculateMediaViewerDimensions(photoDimensions!, hasFooter),
!IS_MOBILE_SCREEN && !isZoomed,
!IS_SINGLE_COLUMN_LAYOUT && !isZoomed,
)}
{isVideo && (
<VideoPlayer
@ -435,7 +446,8 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
<MediaViewerFooter
text={textParts}
onClick={handleFooterClick}
isHideable={isVideo}
isHidden={isFooterHidden && (!isVideo || isGif)}
isForVideo={isVideo && !isGif}
/>
)}
</div>
@ -465,7 +477,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
{() => (
<>
<div className="media-viewer-head" dir={lang.isRtl ? 'rtl' : undefined}>
{IS_MOBILE_SCREEN && (
{IS_SINGLE_COLUMN_LAYOUT && (
<Button
className="media-viewer-close"
round

View File

@ -2,7 +2,7 @@ import React, { FC, useMemo } from '../../lib/teact/teact';
import { ApiMessage } from '../../api/types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { getMessageMediaHash } from '../../modules/helpers';
import useLang from '../../hooks/useLang';
@ -60,7 +60,7 @@ const MediaViewerActions: FC<OwnProps> = ({
);
}, []);
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
return (
<div className="MediaViewerActions-mobile">
<DropdownMenu

View File

@ -16,7 +16,7 @@
padding-bottom: 4.5rem;
background: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0) 100%);
&.hideable {
&.is-for-video {
opacity: 0;
pointer-events: none;
@ -44,6 +44,12 @@
}
}
&.is-hidden {
.media-viewer-footer-content {
opacity: 0;
}
}
.media-text {
margin-bottom: 0;
overflow: auto;

View File

@ -1,7 +1,10 @@
import React, { FC, useEffect, useState } from '../../lib/teact/teact';
import { throttle } from '../../util/schedulers';
import { TextPart } from '../common/helpers/renderMessageText';
import buildClassName from '../../util/buildClassName';
import { REM } from '../common/helpers/mediaDimensions';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import './MediaViewerFooter.scss';
@ -10,10 +13,13 @@ const RESIZE_THROTTLE_MS = 500;
type OwnProps = {
text: TextPart | TextPart[];
onClick: () => void;
isHideable: boolean;
isHidden?: boolean;
isForVideo: boolean;
};
const MediaViewerFooter: FC<OwnProps> = ({ text = '', isHideable, onClick }) => {
const MediaViewerFooter: FC<OwnProps> = ({
text = '', isHidden, isForVideo, onClick,
}) => {
const [isMultiline, setIsMultiline] = useState(false);
useEffect(() => {
const footerContent = document.querySelector('.MediaViewerFooter .media-text') as HTMLDivElement | null;
@ -42,10 +48,16 @@ const MediaViewerFooter: FC<OwnProps> = ({ text = '', isHideable, onClick }) =>
}
}
const classNames = buildClassName(
'MediaViewerFooter',
isForVideo && 'is-for-video',
isHidden && 'is-hidden',
);
return (
<div className={`MediaViewerFooter ${isHideable ? 'hideable' : ''}`} onClick={stopEvent}>
<div className={classNames} onClick={stopEvent}>
{text && (
<div className="media-viewer-footer-content" onClick={onClick}>
<div className="media-viewer-footer-content" onClick={!IS_SINGLE_COLUMN_LAYOUT ? onClick : undefined}>
<p className={`media-text custom-scroll ${isMultiline ? 'multiline' : ''}`} dir="auto">{text}</p>
</div>
)}

View File

@ -4,7 +4,7 @@ import React, {
import { IDimensions } from '../../modules/helpers';
import { IS_IOS, IS_MOBILE_SCREEN, IS_TOUCH_ENV } from '../../util/environment';
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/environment';
import useShowTransition from '../../hooks/useShowTransition';
import useBuffering from '../../hooks/useBuffering';
import useFullscreenStatus from '../../hooks/useFullscreen';
@ -144,7 +144,7 @@ const VideoPlayer: FC<OwnProps> = ({
return (
<div
className="VideoPlayer"
onClick={!isGif && IS_MOBILE_SCREEN ? toggleControls : undefined}
onClick={!isGif && IS_SINGLE_COLUMN_LAYOUT ? toggleControls : undefined}
onMouseOver={!isGif ? handleMouseOver : undefined}
onMouseOut={!isGif ? handleMouseOut : undefined}
>
@ -164,7 +164,7 @@ const VideoPlayer: FC<OwnProps> = ({
// @ts-ignore
style={videoStyle}
onEnded={handleEnded}
onClick={togglePlayState}
onClick={!IS_SINGLE_COLUMN_LAYOUT ? togglePlayState : undefined}
onDoubleClick={handleFullscreenChange}
// eslint-disable-next-line react/jsx-props-no-spreading
{...bufferingHandlers}

View File

@ -1,6 +1,6 @@
import React, { FC, useState, useEffect } from '../../lib/teact/teact';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { formatMediaDuration } from '../../util/dateFormat';
import formatFileSize from './helpers/formatFileSize';
import useLang from '../../hooks/useLang';
@ -58,7 +58,7 @@ const VideoPlayerControls: FC<IProps> = ({
let timeout: number | undefined;
if (!isForceVisible) {
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
setVisibility(false);
} else {
timeout = window.setTimeout(() => {
@ -96,7 +96,7 @@ const VideoPlayerControls: FC<IProps> = ({
<Button
ariaLabel={lang('AccActionPlay')}
size="tiny"
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
color="translucent-white"
className="play"
onClick={onPlayPause}

View File

@ -2,7 +2,7 @@ import React, {
FC, memo, useCallback, useEffect, useRef, useState,
} from '../../lib/teact/teact';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import buildClassName from '../../util/buildClassName';
import usePrevious from '../../hooks/usePrevious';
import useShowTransition from '../../hooks/useShowTransition';
@ -82,7 +82,7 @@ const ZoomControls: FC<OwnProps> = ({ isShown, onChangeZoom }) => {
color="translucent-white"
ariaLabel={lang('ZoomOut')}
className="zoom-out"
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
onClick={handleZoomOut}
>
<i className="icon-zoom-out" />
@ -93,7 +93,7 @@ const ZoomControls: FC<OwnProps> = ({ isShown, onChangeZoom }) => {
color="translucent-white"
ariaLabel="Zoom In"
className="zoom-in"
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
onClick={handleZoomIn}
>
<i className="icon-zoom-in" />

View File

@ -6,7 +6,7 @@ import {
ApiAudio, ApiChat, ApiMessage, ApiUser,
} from '../../api/types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import * as mediaLoader from '../../util/mediaLoader';
import {
getMediaDuration, getMessageAudio, getMessageKey, getMessageMediaHash, getSenderTitle,
@ -67,7 +67,7 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
<div className={buildClassName('AudioPlayer', className)} dir={lang.isRtl ? 'rtl' : undefined}>
<Button
round
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
color="translucent"
size="smaller"
className={buildClassName('toggle-play', isPlaying ? 'pause' : 'play')}

View File

@ -11,7 +11,7 @@ import { GlobalActions, MessageListType } from '../../global/types';
import { MAIN_THREAD_ID } from '../../api/types';
import { IAnchorPosition } from '../../types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { pick } from '../../util/iteratees';
import { isChatChannel, isChatSuperGroup } from '../../modules/helpers';
import {
@ -94,7 +94,7 @@ const HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({
const handleSearchClick = useCallback(() => {
openLocalTextSearch();
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
// iOS requires synchronous focus on user event.
const searchInput = document.querySelector<HTMLInputElement>('#MobileSearch input')!;
searchInput.focus();
@ -112,7 +112,7 @@ const HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({
return (
<div className="HeaderActions">
{!IS_MOBILE_SCREEN && canSubscribe && (
{!IS_SINGLE_COLUMN_LAYOUT && canSubscribe && (
<Button
size="tiny"
ripple
@ -122,7 +122,7 @@ const HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({
{lang(isChannel ? 'Subscribe' : 'Join Group')}
</Button>
)}
{!IS_MOBILE_SCREEN && canStartBot && (
{!IS_SINGLE_COLUMN_LAYOUT && canStartBot && (
<Button
size="tiny"
ripple
@ -132,7 +132,7 @@ const HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({
{lang('Start')}
</Button>
)}
{!IS_MOBILE_SCREEN && canSearch && (
{!IS_SINGLE_COLUMN_LAYOUT && canSearch && (
<Button
round
ripple={isRightColumnShown}
@ -144,12 +144,12 @@ const HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({
<i className="icon-search" />
</Button>
)}
{(IS_MOBILE_SCREEN || !canSubscribe) && (
{(IS_SINGLE_COLUMN_LAYOUT || !canSubscribe) && (
<Button
ref={menuButtonRef}
className={isMenuOpen ? 'active' : ''}
round
ripple={!IS_MOBILE_SCREEN}
ripple={!IS_SINGLE_COLUMN_LAYOUT}
size="smaller"
color="translucent"
disabled={noMenu}
@ -207,8 +207,8 @@ export default memo(withGlobal<OwnProps>(
const canLeave = isMainThread && !canSubscribe;
const noMenu = !(
(IS_MOBILE_SCREEN && canSubscribe)
|| (IS_MOBILE_SCREEN && canSearch)
(IS_SINGLE_COLUMN_LAYOUT && canSubscribe)
|| (IS_SINGLE_COLUMN_LAYOUT && canSearch)
|| canMute
|| canSelect
|| canLeave

View File

@ -7,7 +7,7 @@ import { GlobalActions } from '../../global/types';
import { ApiChat } from '../../api/types';
import { IAnchorPosition } from '../../types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { disableScrolling, enableScrolling } from '../../util/scrollLock';
import { selectChat } from '../../modules/selectors';
import { pick } from '../../util/iteratees';
@ -127,7 +127,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps & DispatchProps> = ({
style={`left: ${x}px;top: ${y}px;`}
onClose={closeMenu}
>
{IS_MOBILE_SCREEN && canSubscribe && (
{IS_SINGLE_COLUMN_LAYOUT && canSubscribe && (
<MenuItem
icon={isChannel ? 'channel' : 'group'}
onClick={handleSubscribe}
@ -135,7 +135,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps & DispatchProps> = ({
{lang(isChannel ? 'Subscribe' : 'Join Group')}
</MenuItem>
)}
{IS_MOBILE_SCREEN && canSearch && (
{IS_SINGLE_COLUMN_LAYOUT && canSearch && (
<MenuItem
icon="search"
onClick={handleSearch}

View File

@ -8,7 +8,7 @@ import { GlobalActions, MessageListType } from '../../global/types';
import { LoadMoreDirection } from '../../types';
import { ANIMATION_END_DELAY, MESSAGE_LIST_SLICE, SCHEDULED_WHEN_ONLINE } from '../../config';
import { IS_ANDROID, IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_ANDROID, IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import {
selectChatMessages,
selectIsViewportNewest,
@ -102,7 +102,7 @@ const UNREAD_DIVIDER_TOP = 10;
const UNREAD_DIVIDER_TOP_WITH_TOOLS = 60;
const SCROLL_DEBOUNCE = 200;
const INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;
const INTERSECTION_MARGIN_FOR_MEDIA = IS_MOBILE_SCREEN ? 300 : 500;
const INTERSECTION_MARGIN_FOR_MEDIA = IS_SINGLE_COLUMN_LAYOUT ? 300 : 500;
const FOCUSING_DURATION = 1000;
const BOTTOM_FOCUS_MARGIN = 20;
const SELECT_MODE_ANIMATION_DURATION = 200;

View File

@ -19,7 +19,7 @@ import {
DARK_THEME_BG_COLOR,
LIGHT_THEME_BG_COLOR,
} from '../../config';
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV, MASK_IMAGE_DISABLED } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV, MASK_IMAGE_DISABLED } from '../../util/environment';
import { DropAreaState } from './composer/DropArea';
import {
selectChat,
@ -76,7 +76,7 @@ type StateProps = {
type DispatchProps = Pick<GlobalActions, 'openChat' | 'unpinAllMessages' | 'loadUser'>;
const CLOSE_ANIMATION_DURATION = IS_MOBILE_SCREEN ? 450 + ANIMATION_END_DELAY : undefined;
const CLOSE_ANIMATION_DURATION = IS_SINGLE_COLUMN_LAYOUT ? 450 + ANIMATION_END_DELAY : undefined;
function canBeQuicklyUploaded(item: DataTransferItem) {
return item.kind === 'file' && item.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.includes(item.type);
@ -308,7 +308,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
canPost={renderingCanPost}
/>
</div>
{IS_MOBILE_SCREEN && <MobileSearch isActive={Boolean(isMobileSearchActive)} />}
{IS_SINGLE_COLUMN_LAYOUT && <MobileSearch isActive={Boolean(isMobileSearchActive)} />}
</>
)}
{chatId && (
@ -341,7 +341,7 @@ export default memo(withGlobal(
patternColor,
isRightColumnShown: selectIsRightColumnShown(global),
isBackgroundBlurred,
isMobileSearchActive: Boolean(IS_MOBILE_SCREEN && selectCurrentTextSearch(global)),
isMobileSearchActive: Boolean(IS_SINGLE_COLUMN_LAYOUT && selectCurrentTextSearch(global)),
isSelectModeActive: selectIsInSelectMode(global),
animationLevel: global.settings.byKey.animationLevel,
};
@ -365,7 +365,7 @@ export default memo(withGlobal(
threadId,
messageListType,
isPrivate: isChatPrivate(chatId),
canPost: !isPinnedMessageList && (!chat || canPost) && (!isBotNotStarted || IS_MOBILE_SCREEN),
canPost: !isPinnedMessageList && (!chat || canPost) && (!isBotNotStarted || IS_SINGLE_COLUMN_LAYOUT),
isPinnedMessageList,
messageSendingRestrictionReason: chat && getMessageSendingRestrictionReason(chat),
hasPinnedOrAudioMessage: (

View File

@ -21,7 +21,7 @@ import {
SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,
} from '../../config';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import {
isChatPrivate,
isChatArchived,
@ -184,14 +184,14 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
}, [openChat, chatId]);
const handleBackClick = useCallback(() => {
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
const messageInput = document.getElementById(EDITABLE_INPUT_ID);
if (messageInput) {
messageInput.blur();
}
}
if (threadId === MAIN_THREAD_ID && messageListType === 'thread') {
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
openChat({ id: undefined });
} else {
toggleLeftColumn();

View File

@ -19,7 +19,7 @@ import {
import { LangCode } from '../../../types';
import { EDITABLE_INPUT_ID, SCHEDULED_WHEN_ONLINE } from '../../../config';
import { IS_VOICE_RECORDING_SUPPORTED, IS_MOBILE_SCREEN, IS_EMOJI_SUPPORTED } from '../../../util/environment';
import { IS_VOICE_RECORDING_SUPPORTED, IS_SINGLE_COLUMN_LAYOUT, IS_EMOJI_SUPPORTED } from '../../../util/environment';
import {
selectChat,
selectIsChatWithBot,
@ -337,7 +337,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
setHtml(`${htmlRef.current!}${newHtml}`);
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
// If selection is outside of input, set cursor at the end of input
requestAnimationFrame(() => {
focusEditableElement(messageInput);
@ -368,7 +368,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
closeMentionTooltip();
closeEmojiTooltip();
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
// @perf
setTimeout(() => closeSymbolMenu(), SENDING_ANIMATION_DURATION);
} else {
@ -582,7 +582,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
const handleSymbolMenuOpen = useCallback(() => {
const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;
if (!IS_MOBILE_SCREEN || messageInput !== document.activeElement) {
if (!IS_SINGLE_COLUMN_LAYOUT || messageInput !== document.activeElement) {
openSymbolMenu();
return;
}
@ -598,7 +598,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
}, [openChat, chatId, threadId]);
useEffect(() => {
if (isRightColumnShown && IS_MOBILE_SCREEN) {
if (isRightColumnShown && IS_SINGLE_COLUMN_LAYOUT) {
closeSymbolMenu();
}
}, [isRightColumnShown, closeSymbolMenu]);
@ -751,7 +751,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
disabled={!allowedAttachmentOptions.canAttachEmbedLinks}
/>
<div className="message-input-wrapper">
{IS_MOBILE_SCREEN ? (
{IS_SINGLE_COLUMN_LAYOUT ? (
<Button
className={symbolMenuButtonClassName}
round
@ -782,7 +782,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
activeVoiceRecording && window.innerWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER ? '' : lang('Message')
}
shouldSetFocus={isSymbolMenuOpen}
shouldSupressFocus={IS_MOBILE_SCREEN && isSymbolMenuOpen}
shouldSupressFocus={IS_SINGLE_COLUMN_LAYOUT && isSymbolMenuOpen}
shouldSupressTextFormatter={isEmojiTooltipOpen || isMentionTooltipOpen}
onUpdate={setHtml}
onSend={onSend}

View File

@ -1,6 +1,6 @@
import React, { FC, memo, useRef } from '../../../lib/teact/teact';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName';
import windowSize from '../../../util/windowSize';
import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';
@ -35,7 +35,7 @@ const EmojiCategory: FC<OwnProps> = ({
const lang = useLang();
const emojisPerRow = IS_MOBILE_SCREEN
const emojisPerRow = IS_SINGLE_COLUMN_LAYOUT
? Math.floor((windowSize.get().width - MOBILE_CONTAINER_PADDING) / (EMOJI_SIZE + EMOJI_MARGIN))
: EMOJIS_PER_ROW_ON_DESKTOP;
const height = Math.ceil(category.emojis.length / emojisPerRow) * (EMOJI_SIZE + EMOJI_MARGIN);

View File

@ -7,7 +7,7 @@ import { GlobalState } from '../../../global/types';
import { MENU_TRANSITION_DURATION } from '../../../config';
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import {
EmojiModule,
EmojiRawData,
@ -99,7 +99,7 @@ const EmojiPicker: FC<OwnProps & StateProps> = ({
setActiveCategoryIndex(intersectingWithIndexes[Math.floor(intersectingWithIndexes.length / 2)].index);
});
useHorizontalScroll(headerRef.current, !IS_MOBILE_SCREEN);
useHorizontalScroll(headerRef.current, !IS_SINGLE_COLUMN_LAYOUT);
// Scroll header when active set updates
useEffect(() => {

View File

@ -14,7 +14,7 @@ import focusEditableElement from '../../../util/focusEditableElement';
import buildClassName from '../../../util/buildClassName';
import { pick } from '../../../util/iteratees';
import {
IS_ANDROID, IS_IOS, IS_MOBILE_SCREEN, IS_TOUCH_ENV,
IS_ANDROID, IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV,
} from '../../../util/environment';
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
import useLayoutEffectWithPrevDeps from '../../../hooks/useLayoutEffectWithPrevDeps';
@ -52,7 +52,7 @@ type StateProps = {
type DispatchProps = Pick<GlobalActions, 'editLastMessage' | 'replyToNextMessage'>;
const MAX_INPUT_HEIGHT = IS_MOBILE_SCREEN ? 256 : 416;
const MAX_INPUT_HEIGHT = IS_SINGLE_COLUMN_LAYOUT ? 256 : 416;
const TAB_INDEX_PRIORITY_TIMEOUT = 2000;
const TEXT_FORMATTER_SAFE_AREA_PX = 90;
// For some reason Safari inserts `<br>` after user removes text from input

View File

@ -5,7 +5,7 @@ import { StickerSetOrRecent } from '../../../types';
import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';
import { STICKER_SIZE_PICKER } from '../../../config';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import windowSize from '../../../util/windowSize';
import StickerButton from '../../common/StickerButton';
import useShowTransition from '../../../hooks/useShowTransition';
@ -22,7 +22,7 @@ type OwnProps = {
};
const STICKERS_PER_ROW_ON_DESKTOP = 5;
const STICKER_MARGIN = IS_MOBILE_SCREEN ? 8 : 16;
const STICKER_MARGIN = IS_SINGLE_COLUMN_LAYOUT ? 8 : 16;
const MOBILE_CONTAINER_PADDING = 8;
const StickerSet: FC<OwnProps> = ({
@ -41,7 +41,7 @@ const StickerSet: FC<OwnProps> = ({
const { transitionClassNames } = useShowTransition(shouldRender, undefined, undefined, 'slow');
const stickersPerRow = IS_MOBILE_SCREEN
const stickersPerRow = IS_SINGLE_COLUMN_LAYOUT
? Math.floor((windowSize.get().width - MOBILE_CONTAINER_PADDING) / (STICKER_SIZE_PICKER + STICKER_MARGIN))
: STICKERS_PER_ROW_ON_DESKTOP;
const height = Math.ceil(stickerSet.count / stickersPerRow) * (STICKER_SIZE_PICKER + STICKER_MARGIN);

View File

@ -5,7 +5,7 @@ import React, {
import { ApiSticker, ApiVideo } from '../../../api/types';
import { IAllowedAttachmentOptions } from '../../../modules/helpers';
import { IS_MOBILE_SCREEN, IS_TOUCH_ENV } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../../util/environment';
import { fastRaf } from '../../../util/schedulers';
import buildClassName from '../../../util/buildClassName';
import useShowTransition from '../../../hooks/useShowTransition';
@ -49,7 +49,7 @@ const SymbolMenu: FC<OwnProps> = ({
const [activeTab, setActiveTab] = useState<number>(0);
const [recentEmojis, setRecentEmojis] = useState<string[]>([]);
const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose, undefined, IS_MOBILE_SCREEN);
const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose, undefined, IS_SINGLE_COLUMN_LAYOUT);
const { shouldRender, transitionClassNames } = useShowTransition(isOpen, onClose, false, false);
if (!isActivated && isOpen) {
@ -61,7 +61,7 @@ const SymbolMenu: FC<OwnProps> = ({
}, [onLoad]);
useLayoutEffect(() => {
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
return undefined;
}
@ -158,7 +158,7 @@ const SymbolMenu: FC<OwnProps> = ({
</Transition>
)}
</div>
{IS_MOBILE_SCREEN && (
{IS_SINGLE_COLUMN_LAYOUT && (
<Button
round
faded
@ -180,7 +180,7 @@ const SymbolMenu: FC<OwnProps> = ({
</>
);
if (IS_MOBILE_SCREEN) {
if (IS_SINGLE_COLUMN_LAYOUT) {
if (!shouldRender) {
return undefined;
}

View File

@ -3,7 +3,7 @@ import {
} from '../../../../lib/teact/teact';
import { EDITABLE_INPUT_ID } from '../../../../config';
import { IS_MOBILE_SCREEN } from '../../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';
import {
EmojiData, EmojiModule, EmojiRawData, uncompressEmoji,
} from '../../../../util/emoji';
@ -154,7 +154,7 @@ export default function useEmojiTooltip(
if (atIndex !== -1) {
onUpdateHtml(`${html.substr(0, atIndex)}${textEmoji}`);
const messageInput = document.getElementById(inputId)!;
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
requestAnimationFrame(() => {
focusEditableElement(messageInput, true);
});

View File

@ -4,7 +4,7 @@ import { ApiMessageEntityTypes, ApiChatMember, ApiUser } from '../../../../api/t
import { EDITABLE_INPUT_ID } from '../../../../config';
import { getUserFirstOrLastName } from '../../../../modules/helpers';
import searchUserName from '../helpers/searchUserName';
import { IS_MOBILE_SCREEN } from '../../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';
import focusEditableElement from '../../../../util/focusEditableElement';
import useFlag from '../../../../hooks/useFlag';
@ -80,7 +80,7 @@ export default function useMentionTooltip(
if (atIndex !== -1) {
onUpdateHtml(`${html.substr(0, atIndex)}${insertedHtml}&nbsp;`);
const messageInput = document.getElementById(inputId)!;
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
requestAnimationFrame(() => {
focusEditableElement(messageInput, forceFocus);
});

View File

@ -1,6 +1,6 @@
import { ApiMessage } from '../../../../api/types';
import { IS_CANVAS_FILTER_SUPPORTED, IS_MOBILE_SCREEN } from '../../../../util/environment';
import { IS_CANVAS_FILTER_SUPPORTED, IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';
import { getMessageMediaThumbDataUri } from '../../../../modules/helpers';
import useCanvasBlur from '../../../../hooks/useCanvasBlur';
@ -8,6 +8,6 @@ export default function useBlurredMediaThumbRef(message: ApiMessage, fullMediaDa
return useCanvasBlur(
getMessageMediaThumbDataUri(message),
Boolean(fullMediaData),
IS_MOBILE_SCREEN && !IS_CANVAS_FILTER_SUPPORTED,
IS_SINGLE_COLUMN_LAYOUT && !IS_CANVAS_FILTER_SUPPORTED,
);
}

View File

@ -6,7 +6,7 @@ import { withGlobal } from '../../lib/teact/teactn';
import { GlobalActions } from '../../global/types';
import { ManagementScreens, ProfileState } from '../../types';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { debounce } from '../../util/schedulers';
import { pick } from '../../util/iteratees';
import buildClassName from '../../util/buildClassName';
@ -270,7 +270,7 @@ const RightHeader: FC<OwnProps & StateProps & DispatchProps> = ({
}
const isBackButton = (
IS_MOBILE_SCREEN
IS_SINGLE_COLUMN_LAYOUT
|| contentKey === HeaderContent.SharedMedia
|| contentKey === HeaderContent.MemberList
|| isManagement

View File

@ -5,7 +5,7 @@ import React, {
import { withGlobal } from '../../lib/teact/teactn';
import { ANIMATION_END_DELAY } from '../../config';
import { IS_MOBILE_SCREEN } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import useForceUpdate from '../../hooks/useForceUpdate';
import usePrevious from '../../hooks/usePrevious';
import buildClassName from '../../util/buildClassName';
@ -44,7 +44,7 @@ const ANIMATION_DURATION = {
'zoom-fade': 150,
'scroll-slide': 500,
fade: 150,
'slide-layers': IS_MOBILE_SCREEN ? 450 : 300,
'slide-layers': IS_SINGLE_COLUMN_LAYOUT ? 450 : 300,
'push-slide': 300,
reveal: 350,
};

View File

@ -14,7 +14,7 @@ import {
LEGACY_SESSION_KEY,
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN, GLOBAL_STATE_CACHE_USER_LIST_LIMIT, SESSION_USER_KEY,
} from '../config';
import { IS_MOBILE_SCREEN } from '../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
import { pick } from '../util/iteratees';
import { INITIAL_STATE } from './initial';
import { selectCurrentMessageList } from '../modules/selectors';
@ -205,7 +205,7 @@ function reduceMessages(global: GlobalState): GlobalState['messages'] {
return {
byChatId,
messageLists: !currentMessageList || IS_MOBILE_SCREEN ? undefined : [{
messageLists: !currentMessageList || IS_SINGLE_COLUMN_LAYOUT ? undefined : [{
...currentMessageList,
threadId: MAIN_THREAD_ID,
type: 'thread',

View File

@ -2,7 +2,7 @@ import { RefObject } from 'react';
import { useState, useEffect, useCallback } from '../lib/teact/teact';
import { IAnchorPosition } from '../types';
import { IS_TOUCH_ENV, IS_MOBILE_SCREEN } from '../util/environment';
import { IS_TOUCH_ENV, IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
const LONG_TAP_DURATION_MS = 250;
const SELECTION_ANIMATION_DURATION_MS = 200;
@ -10,7 +10,7 @@ const SELECTION_ANIMATION_DURATION_MS = 200;
let contextMenuCounter = 0;
function checkIsDisabledForMobile() {
return IS_MOBILE_SCREEN
return IS_SINGLE_COLUMN_LAYOUT
&& window.document.body.classList.contains('enable-symbol-menu-transforms');
}

View File

@ -2,7 +2,7 @@ import Worker from 'worker-loader!./rlottie.worker';
import {
DPR,
IS_MOBILE_SCREEN,
IS_SINGLE_COLUMN_LAYOUT,
IS_SAFARI,
} from '../../util/environment';
import WorkerConnector from '../../util/WorkerConnector';
@ -22,7 +22,7 @@ type Chunks = (Frames | undefined)[];
// TODO Consider removing chunks
const CHUNK_SIZE = 1;
const MAX_WORKERS = 4;
const HIGH_PRIORITY_QUALITY = IS_MOBILE_SCREEN ? 0.75 : 1;
const HIGH_PRIORITY_QUALITY = IS_SINGLE_COLUMN_LAYOUT ? 0.75 : 1;
const LOW_PRIORITY_QUALITY = 0.75;
const HIGH_PRIORITY_MAX_FPS = 60;
const LOW_PRIORITY_MAX_FPS = 30;

View File

@ -2,7 +2,7 @@ import { addReducer } from '../../../lib/teact/teactn';
import { GlobalState } from '../../../global/types';
import { IS_MOBILE_SCREEN } from '../../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import getReadableErrorText from '../../../util/getReadableErrorText';
import { selectCurrentMessageList } from '../../selectors';
@ -58,7 +58,7 @@ addReducer('closeManagement', (global): GlobalState | undefined => {
});
addReducer('openChat', (global, actions, payload) => {
if (!IS_MOBILE_SCREEN) {
if (!IS_SINGLE_COLUMN_LAYOUT) {
return undefined;
}

View File

@ -1,7 +1,7 @@
import { GlobalState } from '../../global/types';
import { RightColumnContent } from '../../types';
import { IS_MOBILE_SCREEN, SYSTEM_THEME } from '../../util/environment';
import { IS_SINGLE_COLUMN_LAYOUT, SYSTEM_THEME } from '../../util/environment';
import { selectCurrentMessageList, selectIsPollResultsOpen } from './messages';
import { selectCurrentTextSearch } from './localSearch';
import { selectCurrentStickerSearch, selectCurrentGifSearch } from './symbols';
@ -20,7 +20,7 @@ export function selectRightColumnContentKey(global: GlobalState) {
} = global;
const isPollResults = selectIsPollResultsOpen(global);
const isSearch = Boolean(!IS_MOBILE_SCREEN && selectCurrentTextSearch(global));
const isSearch = Boolean(!IS_SINGLE_COLUMN_LAYOUT && selectCurrentTextSearch(global));
const isManagement = selectCurrentManagement(global);
const stickerSearch = selectCurrentStickerSearch(global);
const isStickerSearch = stickerSearch.query !== undefined;

View File

@ -35,7 +35,7 @@ export const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAge
export const IS_TOUCH_ENV = window.matchMedia('(pointer: coarse)').matches;
// Keep in mind the landscape orientation
export const IS_MOBILE_SCREEN = window.innerWidth <= MOBILE_SCREEN_MAX_WIDTH || (
export const IS_SINGLE_COLUMN_LAYOUT = window.innerWidth <= MOBILE_SCREEN_MAX_WIDTH || (
window.innerWidth <= MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH && window.innerHeight <= MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT
);
export const IS_VOICE_RECORDING_SUPPORTED = (navigator.mediaDevices && 'getUserMedia' in navigator.mediaDevices && (

View File

@ -4,21 +4,21 @@ import {
MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH,
MOBILE_SCREEN_MAX_WIDTH,
} from '../config';
import { IS_IOS, IS_MOBILE_SCREEN } from './environment';
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT } from './environment';
type IDimensions = {
width: number;
height: number;
};
const IS_LANDSCAPE = IS_MOBILE_SCREEN && isLandscape();
const IS_LANDSCAPE = IS_SINGLE_COLUMN_LAYOUT && isLandscape();
let windowSize = updateSizes();
const handleResize = throttle(() => {
windowSize = updateSizes();
if ((isMobileScreen() !== IS_MOBILE_SCREEN) || (IS_MOBILE_SCREEN && IS_LANDSCAPE !== isLandscape())) {
if ((isMobileScreen() !== IS_SINGLE_COLUMN_LAYOUT) || (IS_SINGLE_COLUMN_LAYOUT && IS_LANDSCAPE !== isLandscape())) {
window.location.reload();
}
}, 250, true);