Stickers: premium effect & toast
This commit is contained in:
parent
dfcc4d11a5
commit
0c4a99f67d
@ -15,7 +15,8 @@ import indexOfAndSplice from '../helpers/array/indexOfAndSplice';
|
|||||||
export type NavigationItem = {
|
export type NavigationItem = {
|
||||||
type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' |
|
type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' |
|
||||||
'esg' | 'multiselect' | 'input-helper' | 'autocomplete-helper' | 'markup' |
|
'esg' | 'multiselect' | 'input-helper' | 'autocomplete-helper' | 'markup' |
|
||||||
'global-search' | 'voice' | 'mobile-search' | 'filters' | 'global-search-focus',
|
'global-search' | 'voice' | 'mobile-search' | 'filters' | 'global-search-focus' |
|
||||||
|
'toast',
|
||||||
onPop: (canAnimate: boolean) => boolean | void,
|
onPop: (canAnimate: boolean) => boolean | void,
|
||||||
onEscape?: () => boolean,
|
onEscape?: () => boolean,
|
||||||
noHistory?: boolean,
|
noHistory?: boolean,
|
||||||
|
@ -62,7 +62,7 @@ const ButtonMenuItem = (options: ButtonMenuItemOptions) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!keepOpen) {
|
if(!keepOpen) {
|
||||||
contextMenuController.closeBtnMenu();
|
contextMenuController.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(checkboxField && !noCheckboxClickListener/* && result !== false */) {
|
if(checkboxField && !noCheckboxClickListener/* && result !== false */) {
|
||||||
|
@ -49,7 +49,7 @@ const ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void |
|
|||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
|
|
||||||
if(el.classList.contains('menu-open')) {
|
if(el.classList.contains('menu-open')) {
|
||||||
contextMenuController.closeBtnMenu();
|
contextMenuController.close();
|
||||||
} else {
|
} else {
|
||||||
const result = onOpen && onOpen(e);
|
const result = onOpen && onOpen(e);
|
||||||
const open = () => {
|
const open = () => {
|
||||||
|
@ -4016,7 +4016,8 @@ export default class ChatBubbles {
|
|||||||
loop: true,
|
loop: true,
|
||||||
emoji: bubble.classList.contains('emoji-big') ? messageMessage : undefined,
|
emoji: bubble.classList.contains('emoji-big') ? messageMessage : undefined,
|
||||||
withThumb: true,
|
withThumb: true,
|
||||||
loadPromises
|
loadPromises,
|
||||||
|
isOut
|
||||||
});
|
});
|
||||||
} else if(doc.type === 'video' || doc.type === 'gif' || doc.type === 'round'/* && doc.size <= 20e6 */) {
|
} else if(doc.type === 'video' || doc.type === 'gif' || doc.type === 'round'/* && doc.size <= 20e6 */) {
|
||||||
// this.log('never get free 2', doc);
|
// this.log('never get free 2', doc);
|
||||||
|
@ -605,13 +605,13 @@ export default class Chat extends EventListenerBase<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isOurMessage(message: Message.message | Message.messageService) {
|
public isOurMessage(message: Message.message | Message.messageService) {
|
||||||
return message.fromId === rootScope.myId || (message.pFlags.out && this.isMegagroup);
|
return message.fromId === rootScope.myId || (!!message.pFlags.out && this.isMegagroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isOutMessage(message: Message.message | Message.messageService) {
|
public isOutMessage(message: Message.message | Message.messageService) {
|
||||||
const fwdFrom = (message as Message.message).fwd_from;
|
const fwdFrom = (message as Message.message).fwd_from;
|
||||||
const isOut = this.isOurMessage(message) && (!fwdFrom || this.peerId !== rootScope.myId);
|
const isOut = this.isOurMessage(message) && (!fwdFrom || this.peerId !== rootScope.myId);
|
||||||
return isOut;
|
return !!isOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAvatarNeeded(message: Message.message | Message.messageService) {
|
public isAvatarNeeded(message: Message.message | Message.messageService) {
|
||||||
|
@ -411,8 +411,8 @@ export default class ChatContextMenu {
|
|||||||
if(!doc) return false;
|
if(!doc) return false;
|
||||||
|
|
||||||
let hasTarget = !!IS_TOUCH_SUPPORTED;
|
let hasTarget = !!IS_TOUCH_SUPPORTED;
|
||||||
const isGoodType = !doc.type || !(['gif', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);
|
const isGoodType = !doc.type || !(['gif', 'video'/* , 'sticker' */] as MyDocument['type'][]).includes(doc.type);
|
||||||
if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio');
|
if(isGoodType) hasTarget ||= !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio') || !!findUpClassName(this.target, 'media-sticker-wrapper');
|
||||||
return isGoodType && hasTarget;
|
return isGoodType && hasTarget;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
@ -136,7 +136,7 @@ export class GroupCallParticipantContextMenu {
|
|||||||
if(this.instance.id === groupCallId) {
|
if(this.instance.id === groupCallId) {
|
||||||
const peerId = getPeerId(participant.peer);
|
const peerId = getPeerId(participant.peer);
|
||||||
if(this.targetPeerId === peerId) {
|
if(this.targetPeerId === peerId) {
|
||||||
contextMenuController.closeBtnMenu();
|
contextMenuController.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -147,7 +147,7 @@ export class GroupCallParticipantContextMenu {
|
|||||||
appendTo = isFull ? PopupElement.getPopups(PopupGroupCall)[0].getContainer(): document.body;
|
appendTo = isFull ? PopupElement.getPopups(PopupGroupCall)[0].getContainer(): document.body;
|
||||||
|
|
||||||
if(!isFull) {
|
if(!isFull) {
|
||||||
contextMenuController.closeBtnMenu();
|
contextMenuController.close();
|
||||||
}
|
}
|
||||||
}, listenerSetter);
|
}, listenerSetter);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
|||||||
btnMenuFooter.classList.add('btn-menu-footer');
|
btnMenuFooter.classList.add('btn-menu-footer');
|
||||||
btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => {
|
btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
contextMenuController.closeBtnMenu();
|
contextMenuController.close();
|
||||||
});
|
});
|
||||||
const t = document.createElement('span');
|
const t = document.createElement('span');
|
||||||
t.classList.add('btn-menu-footer-text');
|
t.classList.add('btn-menu-footer-text');
|
||||||
|
@ -5,24 +5,58 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import replaceContent from '../helpers/dom/replaceContent';
|
import replaceContent from '../helpers/dom/replaceContent';
|
||||||
|
import OverlayClickHandler from '../helpers/overlayClickHandler';
|
||||||
import {FormatterArguments, i18n, LangPackKey} from '../lib/langPack';
|
import {FormatterArguments, i18n, LangPackKey} from '../lib/langPack';
|
||||||
|
|
||||||
const toastEl = document.createElement('div');
|
const toastEl = document.createElement('div');
|
||||||
toastEl.classList.add('toast');
|
toastEl.classList.add('toast');
|
||||||
export function toast(content: string | Node) {
|
let timeout: number;
|
||||||
replaceContent(toastEl, content);
|
|
||||||
document.body.append(toastEl);
|
|
||||||
|
|
||||||
if(toastEl.dataset.timeout) clearTimeout(+toastEl.dataset.timeout);
|
const x = new OverlayClickHandler('toast');
|
||||||
toastEl.dataset.timeout = '' + setTimeout(() => {
|
x.addEventListener('toggle', (open) => {
|
||||||
|
if(!open) {
|
||||||
|
hideToast();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export function hideToast() {
|
||||||
|
x.close();
|
||||||
|
|
||||||
|
toastEl.classList.remove('is-visible');
|
||||||
|
timeout && clearTimeout(+timeout);
|
||||||
|
|
||||||
|
timeout = window.setTimeout(() => {
|
||||||
toastEl.remove();
|
toastEl.remove();
|
||||||
delete toastEl.dataset.timeout;
|
timeout = undefined;
|
||||||
}, 3000);
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toast(content: string | Node, onClose?: () => void) {
|
||||||
|
x.close();
|
||||||
|
|
||||||
|
replaceContent(toastEl, content);
|
||||||
|
|
||||||
|
if(!toastEl.parentElement) {
|
||||||
|
document.body.append(toastEl);
|
||||||
|
void toastEl.offsetLeft; // reflow
|
||||||
|
}
|
||||||
|
|
||||||
|
toastEl.classList.add('is-visible');
|
||||||
|
|
||||||
|
timeout && clearTimeout(+timeout);
|
||||||
|
x.open(toastEl);
|
||||||
|
|
||||||
|
timeout = window.setTimeout(hideToast, 3000);
|
||||||
|
|
||||||
|
if(onClose) {
|
||||||
|
x.addEventListener('toggle', onClose, {once: true});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toastNew(options: Partial<{
|
export function toastNew(options: Partial<{
|
||||||
langPackKey: LangPackKey,
|
langPackKey: LangPackKey,
|
||||||
langPackArguments: FormatterArguments
|
langPackArguments: FormatterArguments,
|
||||||
|
onClose: () => void
|
||||||
}>) {
|
}>) {
|
||||||
toast(i18n(options.langPackKey, options.langPackArguments));
|
toast(i18n(options.langPackKey, options.langPackArguments), options.onClose);
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,14 @@ import onMediaLoad from '../../helpers/onMediaLoad';
|
|||||||
import {isSavingLottiePreview, saveLottiePreview} from '../../helpers/saveLottiePreview';
|
import {isSavingLottiePreview, saveLottiePreview} from '../../helpers/saveLottiePreview';
|
||||||
import throttle from '../../helpers/schedulers/throttle';
|
import throttle from '../../helpers/schedulers/throttle';
|
||||||
import sequentialDom from '../../helpers/sequentialDom';
|
import sequentialDom from '../../helpers/sequentialDom';
|
||||||
import {PhotoSize} from '../../layer';
|
import {PhotoSize, VideoSize} from '../../layer';
|
||||||
import {MyDocument} from '../../lib/appManagers/appDocsManager';
|
import {MyDocument} from '../../lib/appManagers/appDocsManager';
|
||||||
import appDownloadManager from '../../lib/appManagers/appDownloadManager';
|
import appDownloadManager from '../../lib/appManagers/appDownloadManager';
|
||||||
import appImManager from '../../lib/appManagers/appImManager';
|
import appImManager from '../../lib/appManagers/appImManager';
|
||||||
import {AppManagers} from '../../lib/appManagers/managers';
|
import {AppManagers} from '../../lib/appManagers/managers';
|
||||||
import getServerMessageId from '../../lib/appManagers/utils/messageId/getServerMessageId';
|
import getServerMessageId from '../../lib/appManagers/utils/messageId/getServerMessageId';
|
||||||
import choosePhotoSize from '../../lib/appManagers/utils/photos/choosePhotoSize';
|
import choosePhotoSize from '../../lib/appManagers/utils/photos/choosePhotoSize';
|
||||||
|
import getStickerEffectThumb from '../../lib/appManagers/utils/stickers/getStickerEffectThumb';
|
||||||
import lottieLoader from '../../lib/rlottie/lottieLoader';
|
import lottieLoader from '../../lib/rlottie/lottieLoader';
|
||||||
import RLottiePlayer from '../../lib/rlottie/rlottiePlayer';
|
import RLottiePlayer from '../../lib/rlottie/rlottiePlayer';
|
||||||
import rootScope from '../../lib/rootScope';
|
import rootScope from '../../lib/rootScope';
|
||||||
@ -35,9 +36,15 @@ import {SendMessageEmojiInteractionData} from '../../types';
|
|||||||
import {getEmojiToneIndex} from '../../vendor/emoji';
|
import {getEmojiToneIndex} from '../../vendor/emoji';
|
||||||
import animationIntersector from '../animationIntersector';
|
import animationIntersector from '../animationIntersector';
|
||||||
import LazyLoadQueue from '../lazyLoadQueue';
|
import LazyLoadQueue from '../lazyLoadQueue';
|
||||||
|
import PopupStickers from '../popups/stickers';
|
||||||
|
import {hideToast, toastNew} from '../toast';
|
||||||
import wrapStickerAnimation from './stickerAnimation';
|
import wrapStickerAnimation from './stickerAnimation';
|
||||||
|
|
||||||
export default async function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic, managers = rootScope.managers}: {
|
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp#L40
|
||||||
|
const STICKER_EFFECT_MULTIPLIER = 1 + 0.245 * 2;
|
||||||
|
const EMOJI_EFFECT_MULTIPLIER = 3;
|
||||||
|
|
||||||
|
export default async function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic, managers = rootScope.managers, fullThumb, isOut}: {
|
||||||
doc: MyDocument,
|
doc: MyDocument,
|
||||||
div: HTMLElement,
|
div: HTMLElement,
|
||||||
middleware?: () => boolean,
|
middleware?: () => boolean,
|
||||||
@ -55,7 +62,9 @@ export default async function wrapSticker({doc, div, middleware, lazyLoadQueue,
|
|||||||
needUpscale?: boolean,
|
needUpscale?: boolean,
|
||||||
skipRatio?: number,
|
skipRatio?: number,
|
||||||
static?: boolean,
|
static?: boolean,
|
||||||
managers?: AppManagers
|
managers?: AppManagers,
|
||||||
|
fullThumb?: PhotoSize | VideoSize,
|
||||||
|
isOut?: boolean
|
||||||
}) {
|
}) {
|
||||||
const stickerType = doc.sticker;
|
const stickerType = doc.sticker;
|
||||||
if(stickerType === 1) {
|
if(stickerType === 1) {
|
||||||
@ -118,17 +127,23 @@ export default async function wrapSticker({doc, div, middleware, lazyLoadQueue,
|
|||||||
return cacheContext = await managers.thumbsStorage.getCacheContext(doc, type);
|
return cacheContext = await managers.thumbsStorage.getCacheContext(doc, type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAnimated = !asStatic && (stickerType === 2 || stickerType === 3);
|
||||||
|
|
||||||
|
const effectThumb = getStickerEffectThumb(doc);
|
||||||
|
if(isOut !== undefined && effectThumb && !isOut) {
|
||||||
|
div.classList.add('reflect-x');
|
||||||
|
}
|
||||||
|
|
||||||
if(asStatic && stickerType !== 1) {
|
if(asStatic && stickerType !== 1) {
|
||||||
const thumb = choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize;
|
const thumb = choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize;
|
||||||
await getCacheContext(thumb.type);
|
await getCacheContext(thumb.type);
|
||||||
} else {
|
} else {
|
||||||
await getCacheContext();
|
await getCacheContext(fullThumb?.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;
|
const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;
|
||||||
const downloaded = cacheContext.downloaded && !needFadeIn;
|
const downloaded = cacheContext.downloaded && !needFadeIn;
|
||||||
|
|
||||||
const isAnimated = !asStatic && (stickerType === 2 || stickerType === 3);
|
|
||||||
const isThumbNeededForType = isAnimated;
|
const isThumbNeededForType = isAnimated;
|
||||||
const lottieCachedThumb = stickerType === 2 || stickerType === 3 ? await managers.appDocsManager.getLottieCachedThumb(doc.id, toneIndex) : undefined;
|
const lottieCachedThumb = stickerType === 2 || stickerType === 3 ? await managers.appDocsManager.getLottieCachedThumb(doc.id, toneIndex) : undefined;
|
||||||
|
|
||||||
@ -293,7 +308,7 @@ export default async function wrapSticker({doc, div, middleware, lazyLoadQueue,
|
|||||||
|
|
||||||
// appDocsManager.downloadDocNew(doc.id).promise.then((res) => res.json()).then(async(json) => {
|
// appDocsManager.downloadDocNew(doc.id).promise.then((res) => res.json()).then(async(json) => {
|
||||||
// fetch(doc.url).then((res) => res.json()).then(async(json) => {
|
// fetch(doc.url).then((res) => res.json()).then(async(json) => {
|
||||||
return await appDownloadManager.downloadMedia({media: doc, queueId: lazyLoadQueue?.queueId})
|
return await appDownloadManager.downloadMedia({media: doc, queueId: lazyLoadQueue?.queueId, thumb: fullThumb})
|
||||||
.then(async(blob) => {
|
.then(async(blob) => {
|
||||||
// console.timeEnd('download sticker' + doc.id);
|
// console.timeEnd('download sticker' + doc.id);
|
||||||
// console.log('loaded sticker:', doc, div/* , blob */);
|
// console.log('loaded sticker:', doc, div/* , blob */);
|
||||||
@ -406,24 +421,18 @@ export default async function wrapSticker({doc, div, middleware, lazyLoadQueue,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bubble = findUpClassName(div, 'bubble');
|
|
||||||
const isOut = bubble.classList.contains('is-out');
|
|
||||||
|
|
||||||
const {animationDiv} = wrapStickerAnimation({
|
const {animationDiv} = wrapStickerAnimation({
|
||||||
doc,
|
doc,
|
||||||
middleware,
|
middleware,
|
||||||
side: isOut ? 'right' : 'left',
|
side: isOut ? 'right' : 'left',
|
||||||
size: 280,
|
size: 280,
|
||||||
target: div,
|
target: div,
|
||||||
play: true
|
play: true,
|
||||||
|
withRandomOffset: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if(bubble) {
|
if(isOut !== undefined && !isOut) {
|
||||||
if(isOut) {
|
animationDiv.classList.add('reflect-x');
|
||||||
animationDiv.classList.add('is-out');
|
|
||||||
} else {
|
|
||||||
animationDiv.classList.add('is-in');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sendInteractionThrottled) {
|
if(!sendInteractionThrottled) {
|
||||||
@ -464,6 +473,54 @@ export default async function wrapSticker({doc, div, middleware, lazyLoadQueue,
|
|||||||
sendInteractionThrottled();
|
sendInteractionThrottled();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if(effectThumb && isOut !== undefined) {
|
||||||
|
managers.appStickersManager.preloadSticker(doc.id, true);
|
||||||
|
|
||||||
|
let playing = false;
|
||||||
|
attachClickEvent(div, async(e) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
if(playing) {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.onclick = () => {
|
||||||
|
hideToast();
|
||||||
|
new PopupStickers(doc.stickerSetInput).show();
|
||||||
|
};
|
||||||
|
|
||||||
|
toastNew({
|
||||||
|
langPackKey: 'Sticker.Premium.Click.Info',
|
||||||
|
langPackArguments: [a]
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
playing = true;
|
||||||
|
|
||||||
|
const {animationDiv, stickerPromise} = wrapStickerAnimation({
|
||||||
|
doc,
|
||||||
|
middleware,
|
||||||
|
side: isOut ? 'right' : 'left',
|
||||||
|
size: width * STICKER_EFFECT_MULTIPLIER,
|
||||||
|
target: div,
|
||||||
|
play: true,
|
||||||
|
fullThumb: effectThumb
|
||||||
|
});
|
||||||
|
|
||||||
|
if(isOut !== undefined && !isOut) {
|
||||||
|
animationDiv.classList.add('reflect-x');
|
||||||
|
}
|
||||||
|
|
||||||
|
stickerPromise.then((player) => {
|
||||||
|
const onFrame = (frameNo: number) => {
|
||||||
|
if(frameNo === player.maxFrame) {
|
||||||
|
playing = false;
|
||||||
|
player.removeEventListener('enterFrame', onFrame);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
player.addEventListener('enterFrame', onFrame);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return animation;
|
return animation;
|
||||||
|
@ -8,6 +8,7 @@ import IS_VIBRATE_SUPPORTED from '../../environment/vibrateSupport';
|
|||||||
import assumeType from '../../helpers/assumeType';
|
import assumeType from '../../helpers/assumeType';
|
||||||
import isInDOM from '../../helpers/dom/isInDOM';
|
import isInDOM from '../../helpers/dom/isInDOM';
|
||||||
import throttleWithRaf from '../../helpers/schedulers/throttleWithRaf';
|
import throttleWithRaf from '../../helpers/schedulers/throttleWithRaf';
|
||||||
|
import {PhotoSize, VideoSize} from '../../layer';
|
||||||
import {MyDocument} from '../../lib/appManagers/appDocsManager';
|
import {MyDocument} from '../../lib/appManagers/appDocsManager';
|
||||||
import appImManager from '../../lib/appManagers/appImManager';
|
import appImManager from '../../lib/appManagers/appImManager';
|
||||||
import {AppManagers} from '../../lib/appManagers/managers';
|
import {AppManagers} from '../../lib/appManagers/managers';
|
||||||
@ -22,7 +23,9 @@ export default function wrapStickerAnimation({
|
|||||||
side,
|
side,
|
||||||
skipRatio,
|
skipRatio,
|
||||||
play,
|
play,
|
||||||
managers
|
managers,
|
||||||
|
fullThumb,
|
||||||
|
withRandomOffset
|
||||||
}: {
|
}: {
|
||||||
size: number,
|
size: number,
|
||||||
doc: MyDocument,
|
doc: MyDocument,
|
||||||
@ -31,7 +34,9 @@ export default function wrapStickerAnimation({
|
|||||||
side: 'left' | 'center' | 'right',
|
side: 'left' | 'center' | 'right',
|
||||||
skipRatio?: number,
|
skipRatio?: number,
|
||||||
play: boolean,
|
play: boolean,
|
||||||
managers?: AppManagers
|
managers?: AppManagers,
|
||||||
|
fullThumb?: PhotoSize | VideoSize,
|
||||||
|
withRandomOffset?: boolean
|
||||||
}) {
|
}) {
|
||||||
const animationDiv = document.createElement('div');
|
const animationDiv = document.createElement('div');
|
||||||
animationDiv.classList.add('emoji-animation');
|
animationDiv.classList.add('emoji-animation');
|
||||||
@ -52,7 +57,8 @@ export default function wrapStickerAnimation({
|
|||||||
play,
|
play,
|
||||||
group: 'none',
|
group: 'none',
|
||||||
skipRatio,
|
skipRatio,
|
||||||
managers
|
managers,
|
||||||
|
fullThumb
|
||||||
}).then(({render}) => render).then((animation) => {
|
}).then(({render}) => render).then((animation) => {
|
||||||
assumeType<RLottiePlayer>(animation);
|
assumeType<RLottiePlayer>(animation);
|
||||||
animation.addEventListener('enterFrame', (frameNo) => {
|
animation.addEventListener('enterFrame', (frameNo) => {
|
||||||
@ -77,9 +83,9 @@ export default function wrapStickerAnimation({
|
|||||||
return r > max ? -r % max : r;
|
return r > max ? -r % max : r;
|
||||||
};
|
};
|
||||||
|
|
||||||
const randomOffsetX = generateRandomSigned(16);
|
const randomOffsetX = withRandomOffset ? generateRandomSigned(16) : 0;
|
||||||
const randomOffsetY = generateRandomSigned(4);
|
const randomOffsetY = withRandomOffset ? generateRandomSigned(4) : 0;
|
||||||
const stableOffsetX = size / 8 * (side === 'right' ? 1 : -1);
|
const stableOffsetX = /* size / 8 */16 * (side === 'right' ? 1 : -1);
|
||||||
const setPosition = () => {
|
const setPosition = () => {
|
||||||
if(!isInDOM(target)) {
|
if(!isInDOM(target)) {
|
||||||
return;
|
return;
|
||||||
|
@ -4,27 +4,17 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import appNavigationController from '../components/appNavigationController';
|
|
||||||
import IS_TOUCH_SUPPORTED from '../environment/touchSupport';
|
import IS_TOUCH_SUPPORTED from '../environment/touchSupport';
|
||||||
import {IS_MOBILE_SAFARI} from '../environment/userAgent';
|
|
||||||
import cancelEvent from './dom/cancelEvent';
|
|
||||||
import {CLICK_EVENT_NAME} from './dom/clickEvent';
|
|
||||||
import EventListenerBase from './eventListenerBase';
|
|
||||||
import mediaSizes from './mediaSizes';
|
import mediaSizes from './mediaSizes';
|
||||||
|
import OverlayClickHandler from './overlayClickHandler';
|
||||||
|
|
||||||
class ContextMenuController extends EventListenerBase<{
|
class ContextMenuController extends OverlayClickHandler {
|
||||||
toggle: (open: boolean) => void
|
|
||||||
}> {
|
|
||||||
private openedMenu: HTMLElement;
|
|
||||||
private menuOverlay: HTMLElement;
|
|
||||||
private openedMenuOnClose: () => void;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super('menu', true);
|
||||||
|
|
||||||
mediaSizes.addEventListener('resize', () => {
|
mediaSizes.addEventListener('resize', () => {
|
||||||
if(this.openedMenu) {
|
if(this.element) {
|
||||||
this.closeBtnMenu();
|
this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(openedMenu && (openedMenu.style.top || openedMenu.style.left)) {
|
/* if(openedMenu && (openedMenu.style.top || openedMenu.style.left)) {
|
||||||
@ -33,118 +23,53 @@ class ContextMenuController extends EventListenerBase<{
|
|||||||
|
|
||||||
console.log(innerWidth, innerHeight, rect);
|
console.log(innerWidth, innerHeight, rect);
|
||||||
} */
|
} */
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public isOpened() {
|
public isOpened() {
|
||||||
return !!this.openedMenu;
|
return !!this.element;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onMouseMove = (e: MouseEvent) => {
|
private onMouseMove = (e: MouseEvent) => {
|
||||||
const rect = this.openedMenu.getBoundingClientRect();
|
const rect = this.element.getBoundingClientRect();
|
||||||
const {clientX, clientY} = e;
|
const {clientX, clientY} = e;
|
||||||
|
|
||||||
const diffX = clientX >= rect.right ? clientX - rect.right : rect.left - clientX;
|
const diffX = clientX >= rect.right ? clientX - rect.right : rect.left - clientX;
|
||||||
const diffY = clientY >= rect.bottom ? clientY - rect.bottom : rect.top - clientY;
|
const diffY = clientY >= rect.bottom ? clientY - rect.bottom : rect.top - clientY;
|
||||||
|
|
||||||
if(diffX >= 100 || diffY >= 100) {
|
if(diffX >= 100 || diffY >= 100) {
|
||||||
this.closeBtnMenu();
|
this.close();
|
||||||
// openedMenu.parentElement.click();
|
// openedMenu.parentElement.click();
|
||||||
}
|
}
|
||||||
// console.log('mousemove', diffX, diffY);
|
// console.log('mousemove', diffX, diffY);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClick = (e: MouseEvent | TouchEvent) => {
|
public close() {
|
||||||
// cancelEvent(e);
|
if(this.element) {
|
||||||
this.closeBtnMenu();
|
this.element.classList.remove('active');
|
||||||
};
|
this.element.parentElement.classList.remove('menu-open');
|
||||||
|
|
||||||
// ! no need in this due to the same handler in appNavigationController
|
|
||||||
/* const onKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if(e.key === 'Escape') {
|
|
||||||
closeBtnMenu();
|
|
||||||
cancelEvent(e);
|
|
||||||
}
|
|
||||||
}; */
|
|
||||||
|
|
||||||
public closeBtnMenu = () => {
|
|
||||||
if(this.openedMenu) {
|
|
||||||
this.openedMenu.classList.remove('active');
|
|
||||||
this.openedMenu.parentElement.classList.remove('menu-open');
|
|
||||||
// openedMenu.previousElementSibling.remove(); // remove overlay
|
|
||||||
if(this.menuOverlay) this.menuOverlay.remove();
|
|
||||||
this.openedMenu = undefined;
|
|
||||||
|
|
||||||
this.dispatchEvent('toggle', false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.openedMenuOnClose) {
|
super.close();
|
||||||
this.openedMenuOnClose();
|
|
||||||
this.openedMenuOnClose = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!IS_TOUCH_SUPPORTED) {
|
if(!IS_TOUCH_SUPPORTED) {
|
||||||
window.removeEventListener('mousemove', this.onMouseMove);
|
window.removeEventListener('mousemove', this.onMouseMove);
|
||||||
// window.removeEventListener('keydown', onKeyDown, {capture: true});
|
|
||||||
window.removeEventListener('contextmenu', this.onClick);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.removeEventListener(CLICK_EVENT_NAME, this.onClick);
|
public openBtnMenu(element: HTMLElement, onClose?: () => void) {
|
||||||
|
super.open(element);
|
||||||
|
|
||||||
if(!IS_MOBILE_SAFARI) {
|
this.element.classList.add('active');
|
||||||
appNavigationController.removeByType('menu');
|
this.element.parentElement.classList.add('menu-open');
|
||||||
|
|
||||||
|
if(onClose) {
|
||||||
|
this.addEventListener('toggle', onClose, {once: true});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
public openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
|
|
||||||
this.closeBtnMenu();
|
|
||||||
|
|
||||||
if(!IS_MOBILE_SAFARI) {
|
|
||||||
appNavigationController.pushItem({
|
|
||||||
type: 'menu',
|
|
||||||
onPop: (canAnimate) => {
|
|
||||||
this.closeBtnMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openedMenu = menuElement;
|
|
||||||
this.openedMenu.classList.add('active');
|
|
||||||
this.openedMenu.parentElement.classList.add('menu-open');
|
|
||||||
|
|
||||||
if(!this.menuOverlay) {
|
|
||||||
this.menuOverlay = document.createElement('div');
|
|
||||||
this.menuOverlay.classList.add('btn-menu-overlay');
|
|
||||||
|
|
||||||
// ! because this event must be canceled, and can't cancel on menu click (below)
|
|
||||||
this.menuOverlay.addEventListener(CLICK_EVENT_NAME, (e) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
this.onClick(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openedMenu.parentElement.insertBefore(this.menuOverlay, this.openedMenu);
|
|
||||||
|
|
||||||
// document.body.classList.add('disable-hover');
|
|
||||||
|
|
||||||
this.openedMenuOnClose = onClose;
|
|
||||||
|
|
||||||
if(!IS_TOUCH_SUPPORTED) {
|
if(!IS_TOUCH_SUPPORTED) {
|
||||||
window.addEventListener('mousemove', this.onMouseMove);
|
window.addEventListener('mousemove', this.onMouseMove);
|
||||||
// window.addEventListener('keydown', onKeyDown, {capture: true});
|
|
||||||
window.addEventListener('contextmenu', this.onClick, {once: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* // ! because this event must be canceled, and can't cancel on menu click (below)
|
|
||||||
overlay.addEventListener(CLICK_EVENT_NAME, (e) => {
|
|
||||||
cancelEvent(e);
|
|
||||||
onClick(e);
|
|
||||||
}); */
|
|
||||||
|
|
||||||
// ! safari iOS doesn't handle window click event on overlay, idk why
|
|
||||||
document.addEventListener(CLICK_EVENT_NAME, this.onClick);
|
|
||||||
|
|
||||||
this.dispatchEvent('toggle', true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ export function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* To
|
|||||||
add(CLICK_EVENT_NAME, callback, options);
|
add(CLICK_EVENT_NAME, callback, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function detachClickEvent(elem: HTMLElement, callback: (e: /* TouchEvent | */MouseEvent) => void, options?: AddEventListenerOptions) {
|
export function detachClickEvent(elem: HTMLElement | Window, callback: (e: /* TouchEvent | */MouseEvent) => void, options?: AddEventListenerOptions) {
|
||||||
// if(CLICK_EVENT_NAME === 'touchend') {
|
// if(CLICK_EVENT_NAME === 'touchend') {
|
||||||
// elem.removeEventListener('touchstart', callback, options);
|
// elem.removeEventListener('touchstart', callback, options);
|
||||||
// } else {
|
// } else {
|
||||||
elem.removeEventListener(CLICK_EVENT_NAME, callback, options);
|
elem.removeEventListener(CLICK_EVENT_NAME, callback as any, options);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
src/helpers/overlayClickHandler.ts
Normal file
103
src/helpers/overlayClickHandler.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import appNavigationController, {NavigationItem} from '../components/appNavigationController';
|
||||||
|
import IS_TOUCH_SUPPORTED from '../environment/touchSupport';
|
||||||
|
import {IS_MOBILE_SAFARI} from '../environment/userAgent';
|
||||||
|
import cancelEvent from './dom/cancelEvent';
|
||||||
|
import {CLICK_EVENT_NAME} from './dom/clickEvent';
|
||||||
|
import findUpAsChild from './dom/findUpAsChild';
|
||||||
|
import EventListenerBase from './eventListenerBase';
|
||||||
|
|
||||||
|
export default class OverlayClickHandler extends EventListenerBase<{
|
||||||
|
toggle: (open: boolean) => void
|
||||||
|
}> {
|
||||||
|
protected element: HTMLElement;
|
||||||
|
protected overlay: HTMLElement;
|
||||||
|
protected listenerOptions: AddEventListenerOptions;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected navigationType: NavigationItem['type'],
|
||||||
|
protected withOverlay?: boolean
|
||||||
|
) {
|
||||||
|
super(false);
|
||||||
|
this.listenerOptions = withOverlay ? undefined : {capture: true};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onClick = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if(this.element && findUpAsChild(e.target, this.element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEvent(e);
|
||||||
|
this.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
if(this.element) {
|
||||||
|
this.overlay?.remove();
|
||||||
|
this.element = undefined;
|
||||||
|
this.dispatchEvent('toggle', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!IS_TOUCH_SUPPORTED) {
|
||||||
|
// window.removeEventListener('keydown', onKeyDown, {capture: true});
|
||||||
|
window.removeEventListener('contextmenu', this.onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.removeEventListener(CLICK_EVENT_NAME, this.onClick, this.listenerOptions);
|
||||||
|
|
||||||
|
if(!IS_MOBILE_SAFARI) {
|
||||||
|
appNavigationController.removeByType(this.navigationType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public open(element: HTMLElement) {
|
||||||
|
this.close();
|
||||||
|
|
||||||
|
if(!IS_MOBILE_SAFARI) {
|
||||||
|
appNavigationController.pushItem({
|
||||||
|
type: this.navigationType,
|
||||||
|
onPop: (canAnimate) => {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element = element;
|
||||||
|
|
||||||
|
if(!this.overlay && this.withOverlay) {
|
||||||
|
this.overlay = document.createElement('div');
|
||||||
|
this.overlay.classList.add('btn-menu-overlay');
|
||||||
|
|
||||||
|
// ! because this event must be canceled, and can't cancel on menu click (below)
|
||||||
|
this.overlay.addEventListener(CLICK_EVENT_NAME, (e) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
this.onClick(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.overlay && this.element.parentElement.insertBefore(this.overlay, this.element);
|
||||||
|
|
||||||
|
// document.body.classList.add('disable-hover');
|
||||||
|
|
||||||
|
if(!IS_TOUCH_SUPPORTED) {
|
||||||
|
// window.addEventListener('keydown', onKeyDown, {capture: true});
|
||||||
|
window.addEventListener('contextmenu', this.onClick, {once: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* // ! because this event must be canceled, and can't cancel on menu click (below)
|
||||||
|
overlay.addEventListener(CLICK_EVENT_NAME, (e) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
onClick(e);
|
||||||
|
}); */
|
||||||
|
|
||||||
|
// ! safari iOS doesn't handle window click event on overlay, idk why
|
||||||
|
document.addEventListener(CLICK_EVENT_NAME, this.onClick, this.listenerOptions);
|
||||||
|
|
||||||
|
this.dispatchEvent('toggle', true);
|
||||||
|
}
|
||||||
|
}
|
@ -1119,6 +1119,7 @@ const lang = {
|
|||||||
'Schedule.SendToday': 'Send today at %@',
|
'Schedule.SendToday': 'Send today at %@',
|
||||||
'Schedule.SendDate': 'Send on %@ at %@',
|
'Schedule.SendDate': 'Send on %@ at %@',
|
||||||
'Schedule.SendWhenOnline': 'Send When Online',
|
'Schedule.SendWhenOnline': 'Send When Online',
|
||||||
|
'Sticker.Premium.Click.Info': 'This pack contains premium stickers like this one. [View Pack]()',
|
||||||
'Stickers.Recent': 'Recent',
|
'Stickers.Recent': 'Recent',
|
||||||
// "Stickers.Favorite": "Favorite",
|
// "Stickers.Favorite": "Favorite",
|
||||||
'StickerSet.DontExist': 'Sorry, this sticker set doesn\'t seem to exist.',
|
'StickerSet.DontExist': 'Sorry, this sticker set doesn\'t seem to exist.',
|
||||||
|
@ -249,7 +249,7 @@ export class AppStickersManager extends AppManager {
|
|||||||
const id = isAnimation ? EMOJI_ANIMATIONS_SET_LOCAL_ID : EMOJI_SET_LOCAL_ID;
|
const id = isAnimation ? EMOJI_ANIMATIONS_SET_LOCAL_ID : EMOJI_SET_LOCAL_ID;
|
||||||
const stickerSet = this.storage.getFromCache(id);
|
const stickerSet = this.storage.getFromCache(id);
|
||||||
// const stickerSet = await this.getStickerSet({id});
|
// const stickerSet = await this.getStickerSet({id});
|
||||||
if(!stickerSet || !stickerSet.documents) return;
|
if(!stickerSet?.documents) return;
|
||||||
|
|
||||||
if(isAnimation) {
|
if(isAnimation) {
|
||||||
if(['🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎'].includes(emoji)) {
|
if(['🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎'].includes(emoji)) {
|
||||||
@ -293,14 +293,19 @@ export class AppStickersManager extends AppManager {
|
|||||||
|
|
||||||
const sound = this.getAnimatedEmojiSoundDocument(emoji);
|
const sound = this.getAnimatedEmojiSoundDocument(emoji);
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.apiFileManager.downloadMedia({media: doc}),
|
this.preloadSticker(doc.id),
|
||||||
sound ? this.apiFileManager.downloadMedia({media: sound}) : undefined
|
sound ? this.preloadSticker(sound.id) : undefined
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
return {doc, sound};
|
return {doc, sound};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public preloadSticker(docId: DocId, isPremiumEffect?: boolean) {
|
||||||
|
const doc = this.appDocsManager.getDoc(docId);
|
||||||
|
return this.apiFileManager.downloadMedia({media: doc, thumb: isPremiumEffect ? doc.video_thumbs?.[0] : undefined});
|
||||||
|
}
|
||||||
|
|
||||||
private saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: DocId) {
|
private saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: DocId) {
|
||||||
const newSet: MessagesStickerSet = {
|
const newSet: MessagesStickerSet = {
|
||||||
_: 'messages.stickerSet',
|
_: 'messages.stickerSet',
|
||||||
|
@ -4,15 +4,15 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Document, PhotoSize} from '../../../../layer';
|
import type {Document, PhotoSize, VideoSize} from '../../../../layer';
|
||||||
import type {DownloadOptions} from '../../../mtproto/apiFileManager';
|
import type {DownloadOptions} from '../../../mtproto/apiFileManager';
|
||||||
import getDocumentInput from './getDocumentInput';
|
import getDocumentInput from './getDocumentInput';
|
||||||
|
|
||||||
export default function getDocumentDownloadOptions(doc: Document.document, thumb?: PhotoSize.photoSize, queueId?: number, onlyCache?: boolean): DownloadOptions {
|
export default function getDocumentDownloadOptions(doc: Document.document, thumb?: PhotoSize.photoSize | VideoSize, queueId?: number, onlyCache?: boolean): DownloadOptions {
|
||||||
const inputFileLocation = getDocumentInput(doc, thumb?.type);
|
const inputFileLocation = getDocumentInput(doc, thumb?.type);
|
||||||
|
|
||||||
let mimeType: string;
|
let mimeType: string;
|
||||||
if(thumb) {
|
if(thumb?._ === 'photoSize') {
|
||||||
mimeType = doc.sticker ? 'image/webp' : 'image/jpeg'/* doc.mime_type */;
|
mimeType = doc.sticker ? 'image/webp' : 'image/jpeg'/* doc.mime_type */;
|
||||||
} else {
|
} else {
|
||||||
mimeType = doc.mime_type || 'application/octet-stream';
|
mimeType = doc.mime_type || 'application/octet-stream';
|
||||||
|
@ -16,7 +16,7 @@ export default function getDownloadMediaDetails(options: DownloadMediaOptions) {
|
|||||||
|
|
||||||
let downloadOptions: DownloadOptions;
|
let downloadOptions: DownloadOptions;
|
||||||
if(media._ === 'document') downloadOptions = getDocumentDownloadOptions(media, thumb as any, queueId, onlyCache);
|
if(media._ === 'document') downloadOptions = getDocumentDownloadOptions(media, thumb as any, queueId, onlyCache);
|
||||||
else if(media._ === 'photo') downloadOptions = getPhotoDownloadOptions(media, thumb, queueId, onlyCache);
|
else if(media._ === 'photo') downloadOptions = getPhotoDownloadOptions(media, thumb as any, queueId, onlyCache);
|
||||||
else if(isWebDocument(media)) downloadOptions = getWebDocumentDownloadOptions(media);
|
else if(isWebDocument(media)) downloadOptions = getWebDocumentDownloadOptions(media);
|
||||||
|
|
||||||
downloadOptions.downloadId = options.downloadId;
|
downloadOptions.downloadId = options.downloadId;
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
import {MyDocument} from '../../appDocsManager';
|
||||||
|
|
||||||
|
export default function getStickerEffectThumb(doc: MyDocument) {
|
||||||
|
return doc.video_thumbs?.[0];
|
||||||
|
}
|
@ -13,7 +13,7 @@ import type {ReferenceBytes} from './referenceDatabase';
|
|||||||
import Modes from '../../config/modes';
|
import Modes from '../../config/modes';
|
||||||
import deferredPromise, {CancellablePromise} from '../../helpers/cancellablePromise';
|
import deferredPromise, {CancellablePromise} from '../../helpers/cancellablePromise';
|
||||||
import {randomLong} from '../../helpers/random';
|
import {randomLong} from '../../helpers/random';
|
||||||
import {Document, InputFile, InputFileLocation, InputWebFileLocation, Photo, PhotoSize, UploadFile, UploadWebFile, WebDocument} from '../../layer';
|
import {Document, InputFile, InputFileLocation, InputWebFileLocation, Photo, PhotoSize, UploadFile, UploadWebFile, VideoSize, WebDocument} from '../../layer';
|
||||||
import {DcId} from '../../types';
|
import {DcId} from '../../types';
|
||||||
import CacheStorageController from '../files/cacheStorage';
|
import CacheStorageController from '../files/cacheStorage';
|
||||||
import {logger, LogTypes} from '../logger';
|
import {logger, LogTypes} from '../logger';
|
||||||
@ -62,7 +62,7 @@ export type DownloadOptions = {
|
|||||||
|
|
||||||
export type DownloadMediaOptions = {
|
export type DownloadMediaOptions = {
|
||||||
media: Photo.photo | Document.document | WebDocument,
|
media: Photo.photo | Document.document | WebDocument,
|
||||||
thumb?: PhotoSize,
|
thumb?: PhotoSize | VideoSize,
|
||||||
queueId?: number,
|
queueId?: number,
|
||||||
onlyCache?: boolean,
|
onlyCache?: boolean,
|
||||||
downloadId?: string
|
downloadId?: string
|
||||||
|
@ -177,6 +177,10 @@ Utility Classes
|
|||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reflect-x {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
/* .flex-grow {
|
/* .flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,6 @@
|
|||||||
|
|
||||||
// @include sidebar-transform(true);
|
// @include sidebar-transform(true);
|
||||||
|
|
||||||
&.is-in {
|
|
||||||
.rlottie {
|
|
||||||
transform: scaleX(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-container {
|
&-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -699,13 +699,27 @@ input:-webkit-autofill:active {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
border-radius: $border-radius-medium;
|
border-radius: $border-radius-medium;
|
||||||
animation: fade-in-opacity-fade-out-opacity 3s linear forwards;
|
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
max-width: 22.5rem;
|
max-width: unquote('min(30rem, calc(100vw - 2rem))');
|
||||||
|
opacity: 0;
|
||||||
|
backdrop-filter: blur(25px);
|
||||||
|
|
||||||
|
&.is-visible {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include animation-level(2) {
|
||||||
|
transition: opacity var(--transition-standard-in);
|
||||||
|
}
|
||||||
|
|
||||||
b {
|
b {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #60a5e9!important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user