Message: Play effect on deletion (#5125)
This commit is contained in:
parent
a68ee36582
commit
6babbae9f9
@ -1,13 +1,13 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, {
|
||||
memo, useCallback, useEffect, useState,
|
||||
memo, useCallback, useEffect, useRef, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import { DEBUG_LOG_FILENAME } from '../../../config';
|
||||
import { getDebugLogs } from '../../../util/debugConsole';
|
||||
import download from '../../../util/download';
|
||||
import { IS_ELECTRON, IS_WAVE_TRANSFORM_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
import { IS_ELECTRON, IS_SNAP_EFFECT_SUPPORTED, IS_WAVE_TRANSFORM_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
||||
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
@ -15,6 +15,7 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
|
||||
import { animateSnap } from '../../main/visualEffects/SnapEffectContainer';
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
|
||||
@ -39,6 +40,11 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
||||
shouldDebugExportedSenders,
|
||||
}) => {
|
||||
const { requestConfetti, setSettingOption, requestWave } = getActions();
|
||||
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const snapButtonRef = useRef<HTMLDivElement>(null);
|
||||
const [isSnapButtonAnimating, setIsSnapButtonAnimating] = useState(false);
|
||||
|
||||
const lang = useOldLang();
|
||||
|
||||
const [isAutoUpdateEnabled, setIsAutoUpdateEnabled] = useState(false);
|
||||
@ -65,6 +71,19 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
||||
requestWave({ startX: e.clientX, startY: e.clientY });
|
||||
});
|
||||
|
||||
const handleSnap = useLastCallback(() => {
|
||||
const button = snapButtonRef.current;
|
||||
if (!button) return;
|
||||
|
||||
if (animateSnap(button)) {
|
||||
setIsSnapButtonAnimating(true);
|
||||
// Manual reset for debug
|
||||
setTimeout(() => {
|
||||
setIsSnapButtonAnimating(false);
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="settings-content custom-scroll">
|
||||
<div className="settings-content-header no-border">
|
||||
@ -92,6 +111,15 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
||||
>
|
||||
<div className="title">Start wave</div>
|
||||
</ListItem>
|
||||
<ListItem
|
||||
ref={snapButtonRef}
|
||||
onClick={handleSnap}
|
||||
icon="spoiler"
|
||||
disabled={!IS_SNAP_EFFECT_SUPPORTED}
|
||||
style={isSnapButtonAnimating ? 'visibility: hidden' : ''}
|
||||
>
|
||||
<div className="title">Vaporize this button</div>
|
||||
</ListItem>
|
||||
|
||||
<Checkbox
|
||||
label="Allow HTTP Transport"
|
||||
|
||||
@ -15,7 +15,7 @@ import {
|
||||
} from '../../../global/initialState';
|
||||
import { selectPerformanceSettings } from '../../../global/selectors';
|
||||
import { areDeepEqual } from '../../../util/areDeepEqual';
|
||||
import { IS_BACKDROP_BLUR_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
import { IS_BACKDROP_BLUR_SUPPORTED, IS_SNAP_EFFECT_SUPPORTED } from '../../../util/windowEnvironment';
|
||||
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
@ -60,6 +60,7 @@ const PERFORMANCE_OPTIONS: PerformanceSection[] = [
|
||||
{ key: 'contextMenuAnimations', label: 'Context Menu Animation' },
|
||||
{ key: 'contextMenuBlur', label: 'Context Menu Blur', disabled: !IS_BACKDROP_BLUR_SUPPORTED },
|
||||
{ key: 'rightColumnAnimations', label: 'Right Column Animation' },
|
||||
{ key: 'snapEffect', label: 'Dust-effect deletion' },
|
||||
]],
|
||||
['Stickers and Emoji', [
|
||||
{ key: 'animatedEmoji', label: 'Allow Animated Emoji' },
|
||||
@ -195,16 +196,19 @@ function SettingsPerformance({
|
||||
</div>
|
||||
{Boolean(sectionExpandedStates[index]) && (
|
||||
<div className="DropdownList DropdownList--open">
|
||||
{options.map(({ key, label, disabled }) => (
|
||||
<Checkbox
|
||||
key={key}
|
||||
name={key}
|
||||
checked={performanceSettings[key]}
|
||||
label={lang(label)}
|
||||
disabled={disabled}
|
||||
onChange={handlePropertyChange}
|
||||
/>
|
||||
))}
|
||||
{options.map(({ key, label, disabled }) => {
|
||||
if (key === 'snapEffect' && !IS_SNAP_EFFECT_SUPPORTED) return undefined;
|
||||
return (
|
||||
<Checkbox
|
||||
key={key}
|
||||
name={key}
|
||||
checked={performanceSettings[key]}
|
||||
label={lang(label)}
|
||||
disabled={disabled}
|
||||
onChange={handlePropertyChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -87,6 +87,7 @@ import PremiumMainModal from './premium/PremiumMainModal.async';
|
||||
import StarsGiftingPickerModal from './premium/StarsGiftingPickerModal.async';
|
||||
import SafeLinkModal from './SafeLinkModal.async';
|
||||
import ConfettiContainer from './visualEffects/ConfettiContainer';
|
||||
import SnapEffectContainer from './visualEffects/SnapEffectContainer';
|
||||
import WaveContainer from './visualEffects/WaveContainer';
|
||||
|
||||
import './Main.scss';
|
||||
@ -566,6 +567,7 @@ const Main = ({
|
||||
<DownloadManager />
|
||||
<ConfettiContainer />
|
||||
{IS_WAVE_TRANSFORM_SUPPORTED && <WaveContainer />}
|
||||
<SnapEffectContainer />
|
||||
<PhoneCall isActive={isPhoneCallActive} />
|
||||
<UnreadCount isForAppBadge />
|
||||
<RatePhoneCallModal isOpen={isRatePhoneCallModalOpen} />
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
.root {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
|
||||
z-index: var(--z-overlay-effects);
|
||||
}
|
||||
|
||||
.ghost {
|
||||
position: absolute;
|
||||
overflow: visible !important;
|
||||
|
||||
animation: scale 1s ease-in forwards !important;
|
||||
transform-origin: bottom;
|
||||
}
|
||||
|
||||
.elementContainer {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
@keyframes scale {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
172
src/components/main/visualEffects/SnapEffectContainer.tsx
Normal file
172
src/components/main/visualEffects/SnapEffectContainer.tsx
Normal file
@ -0,0 +1,172 @@
|
||||
import React, { memo } from '../../../lib/teact/teact';
|
||||
import { getGlobal } from '../../../global';
|
||||
|
||||
import { SNAP_EFFECT_CONTAINER_ID, SNAP_EFFECT_ID } from '../../../config';
|
||||
import { selectCanAnimateSnapEffect } from '../../../global/selectors';
|
||||
import generateUniqueId from '../../../util/generateUniqueId';
|
||||
import { SVG_NAMESPACE } from '../../../util/svgController';
|
||||
|
||||
import styles from './SnapEffectContainer.module.scss';
|
||||
|
||||
const VISIBLITY_MARGIN = 50;
|
||||
const DURATION = 1000;
|
||||
|
||||
const SnapEffectContainer = () => {
|
||||
return (
|
||||
<div className={styles.root} id={SNAP_EFFECT_CONTAINER_ID} />
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(SnapEffectContainer);
|
||||
|
||||
export function animateSnap(element: HTMLElement) {
|
||||
const global = getGlobal();
|
||||
const canPlayEffect = selectCanAnimateSnapEffect(global);
|
||||
if (!canPlayEffect) return false;
|
||||
// Get element current fixed position on screen
|
||||
const rect = element.getBoundingClientRect();
|
||||
const x = rect.left + window.scrollX;
|
||||
const y = rect.top + window.scrollY;
|
||||
const width = rect.width;
|
||||
const height = rect.height;
|
||||
|
||||
// Check for visibility
|
||||
if (x + width + VISIBLITY_MARGIN < 0 || x - VISIBLITY_MARGIN > window.innerWidth
|
||||
|| y + height + VISIBLITY_MARGIN < 0 || y - VISIBLITY_MARGIN > window.innerHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const seed = Math.floor(Date.now() / 1000);
|
||||
const filterId = `${SNAP_EFFECT_ID}-${generateUniqueId()}`;
|
||||
|
||||
const svg = document.createElementNS(SVG_NAMESPACE, 'svg');
|
||||
svg.setAttribute('class', styles.ghost);
|
||||
svg.setAttribute('width', `${width}px`);
|
||||
svg.setAttribute('height', `${height}px`);
|
||||
svg.setAttribute('style', `left: ${x}px; top: ${y}px;`);
|
||||
svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
|
||||
|
||||
const defs = document.createElementNS(SVG_NAMESPACE, 'defs');
|
||||
svg.appendChild(defs);
|
||||
|
||||
const filter = createFilter(Math.min(width, height), seed);
|
||||
filter.setAttribute('id', filterId);
|
||||
defs.appendChild(filter);
|
||||
|
||||
const g = document.createElementNS(SVG_NAMESPACE, 'g');
|
||||
g.setAttribute('filter', `url(#${filterId})`);
|
||||
svg.appendChild(g);
|
||||
|
||||
const foreignObject = document.createElementNS(SVG_NAMESPACE, 'foreignObject');
|
||||
foreignObject.setAttribute('class', styles.elementContainer);
|
||||
foreignObject.setAttribute('width', `${width}px`);
|
||||
foreignObject.setAttribute('height', `${height}px`);
|
||||
g.appendChild(foreignObject);
|
||||
|
||||
const computedStyle = window.getComputedStyle(element);
|
||||
const clone = element.cloneNode(true) as HTMLElement;
|
||||
Array.from(computedStyle).forEach((key) => (
|
||||
clone.style.setProperty(key, computedStyle.getPropertyValue(key), 'important')
|
||||
));
|
||||
|
||||
foreignObject.appendChild(clone);
|
||||
|
||||
const snapContainer = document.getElementById(SNAP_EFFECT_CONTAINER_ID)!;
|
||||
snapContainer.appendChild(svg);
|
||||
|
||||
svg.addEventListener('animationend', () => {
|
||||
snapContainer.removeChild(svg);
|
||||
}, {
|
||||
once: true,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function createFilter(smallestSide: number, baseSeed: number = 42) {
|
||||
const filter = document.createElementNS(SVG_NAMESPACE, 'filter');
|
||||
filter.setAttribute('x', '-150%');
|
||||
filter.setAttribute('y', '-150%');
|
||||
filter.setAttribute('width', '400%');
|
||||
filter.setAttribute('height', '400%');
|
||||
filter.setAttribute('color-interpolation-filters', 'sRGB');
|
||||
|
||||
const feTurbulence = document.createElementNS(SVG_NAMESPACE, 'feTurbulence');
|
||||
feTurbulence.setAttribute('type', 'fractalNoise');
|
||||
feTurbulence.setAttribute('baseFrequency', '0.5');
|
||||
feTurbulence.setAttribute('numOctaves', '1');
|
||||
feTurbulence.setAttribute('result', 'dustNoise');
|
||||
feTurbulence.setAttribute('seed', baseSeed.toString());
|
||||
filter.appendChild(feTurbulence);
|
||||
|
||||
const feComponentTransfer = document.createElementNS(SVG_NAMESPACE, 'feComponentTransfer');
|
||||
feComponentTransfer.setAttribute('in', 'dustNoise');
|
||||
feComponentTransfer.setAttribute('result', 'dustNoiseMask');
|
||||
filter.appendChild(feComponentTransfer);
|
||||
|
||||
const feFuncA = document.createElementNS(SVG_NAMESPACE, 'feFuncA');
|
||||
feFuncA.setAttribute('type', 'linear');
|
||||
feFuncA.setAttribute('slope', '5');
|
||||
feFuncA.setAttribute('intercept', '0');
|
||||
feComponentTransfer.appendChild(feFuncA);
|
||||
|
||||
const feFuncAAnimate = document.createElementNS(SVG_NAMESPACE, 'animate');
|
||||
feFuncAAnimate.setAttribute('attributeName', 'slope');
|
||||
feFuncAAnimate.setAttribute('values', '5; 2; 1; 0');
|
||||
feFuncAAnimate.setAttribute('dur', `${DURATION}ms`);
|
||||
feFuncAAnimate.setAttribute('fill', 'freeze');
|
||||
feFuncA.appendChild(feFuncAAnimate);
|
||||
|
||||
const feComposite = document.createElementNS(SVG_NAMESPACE, 'feComposite');
|
||||
feComposite.setAttribute('in', 'SourceGraphic');
|
||||
feComposite.setAttribute('in2', 'dustNoiseMask');
|
||||
feComposite.setAttribute('operator', 'in');
|
||||
feComposite.setAttribute('result', 'dustySource');
|
||||
filter.appendChild(feComposite);
|
||||
|
||||
const feTurbulence2 = document.createElementNS(SVG_NAMESPACE, 'feTurbulence');
|
||||
feTurbulence2.setAttribute('type', 'fractalNoise');
|
||||
feTurbulence2.setAttribute('baseFrequency', '0.015');
|
||||
feTurbulence2.setAttribute('numOctaves', '1');
|
||||
feTurbulence2.setAttribute('result', 'displacementNoice1');
|
||||
feTurbulence2.setAttribute('seed', (baseSeed + 1).toString());
|
||||
filter.appendChild(feTurbulence2);
|
||||
|
||||
const feTurbulence3 = document.createElementNS(SVG_NAMESPACE, 'feTurbulence');
|
||||
feTurbulence3.setAttribute('type', 'fractalNoise');
|
||||
feTurbulence3.setAttribute('baseFrequency', '1');
|
||||
feTurbulence3.setAttribute('numOctaves', '2');
|
||||
feTurbulence3.setAttribute('result', 'displacementNoice2');
|
||||
feTurbulence3.setAttribute('seed', (baseSeed + 2).toString());
|
||||
filter.appendChild(feTurbulence3);
|
||||
|
||||
const feMerge = document.createElementNS(SVG_NAMESPACE, 'feMerge');
|
||||
feMerge.setAttribute('result', 'combinedNoise');
|
||||
filter.appendChild(feMerge);
|
||||
|
||||
const feMergeNode1 = document.createElementNS(SVG_NAMESPACE, 'feMergeNode');
|
||||
feMergeNode1.setAttribute('in', 'displacementNoice1');
|
||||
feMerge.appendChild(feMergeNode1);
|
||||
|
||||
const feMergeNode2 = document.createElementNS(SVG_NAMESPACE, 'feMergeNode');
|
||||
feMergeNode2.setAttribute('in', 'displacementNoice2');
|
||||
feMerge.appendChild(feMergeNode2);
|
||||
|
||||
const feDisplacementMap = document.createElementNS(SVG_NAMESPACE, 'feDisplacementMap');
|
||||
feDisplacementMap.setAttribute('in', 'dustySource');
|
||||
feDisplacementMap.setAttribute('in2', 'combinedNoise');
|
||||
feDisplacementMap.setAttribute('scale', '0');
|
||||
|
||||
feDisplacementMap.setAttribute('xChannelSelector', 'R');
|
||||
feDisplacementMap.setAttribute('yChannelSelector', 'G');
|
||||
filter.appendChild(feDisplacementMap);
|
||||
|
||||
const feDisplacementMapAnimate = document.createElementNS(SVG_NAMESPACE, 'animate');
|
||||
feDisplacementMapAnimate.setAttribute('attributeName', 'scale');
|
||||
feDisplacementMapAnimate.setAttribute('values', `0; ${smallestSide * 3}`);
|
||||
feDisplacementMapAnimate.setAttribute('dur', `${DURATION}ms`);
|
||||
feDisplacementMapAnimate.setAttribute('fill', 'freeze');
|
||||
feDisplacementMap.appendChild(feDisplacementMapAnimate);
|
||||
|
||||
return filter;
|
||||
}
|
||||
@ -268,6 +268,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-dissolving {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.is-story-mention {
|
||||
--background-color: var(--pattern-color);
|
||||
|
||||
|
||||
@ -157,6 +157,7 @@ import StarIcon from '../../common/icons/StarIcon';
|
||||
import MessageText from '../../common/MessageText';
|
||||
import ReactionStaticEmoji from '../../common/reactions/ReactionStaticEmoji';
|
||||
import TopicChip from '../../common/TopicChip';
|
||||
import { animateSnap } from '../../main/visualEffects/SnapEffectContainer';
|
||||
import Button from '../../ui/Button';
|
||||
import Album from './Album';
|
||||
import AnimatedCustomEmoji from './AnimatedCustomEmoji';
|
||||
@ -443,6 +444,8 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
const lang = useOldLang();
|
||||
|
||||
const [isTranscriptionHidden, setTranscriptionHidden] = useState(false);
|
||||
const [isPlayingSnapAnimation, setIsPlayingSnapAnimation] = useState(false);
|
||||
const [isPlayingDeleteAnimation, setIsPlayingDeleteAnimation] = useState(false);
|
||||
const [shouldPlayEffect, requestEffect, hideEffect] = useFlag();
|
||||
const { isMobile, isTouchScreen } = useAppLayout();
|
||||
|
||||
@ -666,6 +669,17 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
}, [focusLastMessage, isLastInList, transcribedText, withVoiceTranscription]);
|
||||
|
||||
useEffect(() => {
|
||||
const element = ref.current;
|
||||
if (message.isDeleting && element) {
|
||||
if (animateSnap(element)) {
|
||||
setIsPlayingSnapAnimation(true);
|
||||
} else {
|
||||
setIsPlayingDeleteAnimation(true);
|
||||
}
|
||||
}
|
||||
}, [message.isDeleting]);
|
||||
|
||||
const textMessage = album?.hasMultipleCaptions ? undefined : (album?.captionMessage || message);
|
||||
const hasTextContent = textMessage && hasMessageText(textMessage);
|
||||
const hasText = hasTextContent || hasFactCheck;
|
||||
@ -685,7 +699,8 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
isContextMenuOpen && 'has-menu-open',
|
||||
isFocused && !noFocusHighlight && 'focused',
|
||||
isForwarding && 'is-forwarding',
|
||||
message.isDeleting && 'is-deleting',
|
||||
isPlayingDeleteAnimation && 'is-deleting',
|
||||
isPlayingSnapAnimation && 'is-dissolving',
|
||||
isInDocumentGroup && 'is-in-document-group',
|
||||
isAlbum && 'is-album',
|
||||
message.hasUnreadMention && 'has-unread-mention',
|
||||
|
||||
@ -148,6 +148,9 @@ export const CUSTOM_APPENDIX_ATTRIBUTE = 'data-has-custom-appendix';
|
||||
export const MESSAGE_CONTENT_CLASS_NAME = 'message-content';
|
||||
export const MESSAGE_CONTENT_SELECTOR = '.message-content';
|
||||
|
||||
export const SNAP_EFFECT_CONTAINER_ID = 'snap-effect-container';
|
||||
export const SNAP_EFFECT_ID = 'snap-effect';
|
||||
|
||||
export const STARS_ICON_PLACEHOLDER = '⭐';
|
||||
export const STARS_CURRENCY_CODE = 'XTR';
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ import {
|
||||
import { updateUnreadReactions } from '../../reducers/reactions';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
import {
|
||||
selectCanAnimateSnapEffect,
|
||||
selectChat,
|
||||
selectChatLastMessageId,
|
||||
selectChatMessage,
|
||||
@ -85,6 +86,7 @@ import {
|
||||
} from '../../selectors';
|
||||
|
||||
const ANIMATION_DELAY = 350;
|
||||
const SNAP_ANIMATION_DELAY = 1000;
|
||||
|
||||
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
switch (update['@type']) {
|
||||
@ -1056,11 +1058,13 @@ export function deleteMessages<T extends GlobalState>(
|
||||
|
||||
setGlobal(global);
|
||||
|
||||
const isAnimatingAsSnap = selectCanAnimateSnapEffect(global);
|
||||
|
||||
setTimeout(() => {
|
||||
global = getGlobal();
|
||||
global = deleteChatMessages(global, chatId, ids);
|
||||
setGlobal(global);
|
||||
}, ANIMATION_DELAY);
|
||||
}, isAnimatingAsSnap ? SNAP_ANIMATION_DELAY : ANIMATION_DELAY);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1099,11 +1103,13 @@ export function deleteMessages<T extends GlobalState>(
|
||||
global = deletePeerPhoto(global, commonBoxChatId, message.content.action.photo.id, true);
|
||||
}
|
||||
|
||||
const isAnimatingAsSnap = selectCanAnimateSnapEffect(global);
|
||||
|
||||
setTimeout(() => {
|
||||
global = getGlobal();
|
||||
global = deleteChatMessages(global, commonBoxChatId, [id]);
|
||||
setGlobal(global);
|
||||
}, ANIMATION_DELAY);
|
||||
}, isAnimatingAsSnap ? SNAP_ANIMATION_DELAY : ANIMATION_DELAY);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1129,6 +1135,8 @@ function deleteScheduledMessages<T extends GlobalState>(
|
||||
|
||||
setGlobal(global);
|
||||
|
||||
const isAnimatingAsSnap = selectCanAnimateSnapEffect(global);
|
||||
|
||||
setTimeout(() => {
|
||||
global = getGlobal();
|
||||
global = deleteChatScheduledMessages(global, chatId, ids);
|
||||
@ -1137,5 +1145,5 @@ function deleteScheduledMessages<T extends GlobalState>(
|
||||
global, chatId, MAIN_THREAD_ID, 'scheduledIds', Object.keys(scheduledMessages || {}).map(Number),
|
||||
);
|
||||
setGlobal(global);
|
||||
}, ANIMATION_DELAY);
|
||||
}, isAnimatingAsSnap ? SNAP_ANIMATION_DELAY : ANIMATION_DELAY);
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ export const INITIAL_PERFORMANCE_STATE_MAX: PerformanceType = {
|
||||
rightColumnAnimations: true,
|
||||
stickerEffects: true,
|
||||
storyRibbonAnimations: true,
|
||||
snapEffect: true,
|
||||
};
|
||||
|
||||
export const INITIAL_PERFORMANCE_STATE_MID: PerformanceType = {
|
||||
@ -46,6 +47,7 @@ export const INITIAL_PERFORMANCE_STATE_MID: PerformanceType = {
|
||||
rightColumnAnimations: false,
|
||||
stickerEffects: false,
|
||||
storyRibbonAnimations: false,
|
||||
snapEffect: false,
|
||||
};
|
||||
|
||||
export const INITIAL_PERFORMANCE_STATE_MIN: PerformanceType = {
|
||||
@ -63,6 +65,7 @@ export const INITIAL_PERFORMANCE_STATE_MIN: PerformanceType = {
|
||||
rightColumnAnimations: false,
|
||||
stickerEffects: false,
|
||||
storyRibbonAnimations: false,
|
||||
snapEffect: false,
|
||||
};
|
||||
|
||||
export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
|
||||
@ -4,6 +4,7 @@ import type { GlobalState, TabArgs } from '../types';
|
||||
import { NewChatMembersProgress, RightColumnContent } from '../../types';
|
||||
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { IS_SNAP_EFFECT_SUPPORTED } from '../../util/windowEnvironment';
|
||||
import { getMessageVideo, getMessageWebPageVideo } from '../helpers/messageMedia';
|
||||
import { selectCurrentManagement } from './management';
|
||||
import { selectIsStatisticsShown } from './statistics';
|
||||
@ -145,3 +146,7 @@ export function selectIsContextMenuTranslucent<T extends GlobalState>(global: T)
|
||||
export function selectIsSynced<T extends GlobalState>(global: T) {
|
||||
return global.isSynced;
|
||||
}
|
||||
|
||||
export function selectCanAnimateSnapEffect<T extends GlobalState>(global: T) {
|
||||
return IS_SNAP_EFFECT_SUPPORTED && selectPerformanceSettingsValue(global, 'snapEffect');
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ export type PerformanceTypeKey = (
|
||||
'pageTransitions' | 'messageSendingAnimations' | 'mediaViewerAnimations'
|
||||
| 'messageComposerAnimations' | 'contextMenuAnimations' | 'contextMenuBlur' | 'rightColumnAnimations'
|
||||
| 'animatedEmoji' | 'loopAnimatedStickers' | 'reactionEffects' | 'stickerEffects' | 'autoplayGifs' | 'autoplayVideos'
|
||||
| 'storyRibbonAnimations'
|
||||
| 'storyRibbonAnimations' | 'snapEffect'
|
||||
);
|
||||
export type PerformanceType = {
|
||||
[key in PerformanceTypeKey]: boolean;
|
||||
|
||||
@ -3,6 +3,8 @@ import generateUniqueId from './generateUniqueId';
|
||||
export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
||||
|
||||
const CONTAINER = document.createElementNS(SVG_NAMESPACE, 'svg');
|
||||
CONTAINER.setAttribute('width', '0');
|
||||
CONTAINER.setAttribute('height', '0');
|
||||
CONTAINER.setAttribute('viewBox', '0 0 1 1');
|
||||
CONTAINER.classList.add('svg-definitions');
|
||||
document.body.appendChild(CONTAINER);
|
||||
|
||||
@ -71,9 +71,13 @@ export const IS_CANVAS_FILTER_SUPPORTED = (
|
||||
export const IS_REQUEST_FULLSCREEN_SUPPORTED = 'requestFullscreen' in document.createElement('div');
|
||||
export const ARE_CALLS_SUPPORTED = !IS_FIREFOX; // https://bugzilla.mozilla.org/show_bug.cgi?id=1923416
|
||||
export const LAYERS_ANIMATION_NAME = IS_ANDROID ? 'slideFade' : IS_IOS ? 'slideLayers' : 'pushSlide';
|
||||
|
||||
export const IS_WAVE_TRANSFORM_SUPPORTED = !IS_MOBILE
|
||||
&& !IS_FIREFOX // https://bugzilla.mozilla.org/show_bug.cgi?id=1808785
|
||||
&& !IS_SAFARI; // https://bugs.webkit.org/show_bug.cgi?id=245510
|
||||
export const IS_SNAP_EFFECT_SUPPORTED = !IS_MOBILE
|
||||
&& !IS_FIREFOX // https://bugzilla.mozilla.org/show_bug.cgi?id=1896504
|
||||
&& !IS_SAFARI;
|
||||
|
||||
const TEST_VIDEO = document.createElement('video');
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user