diff --git a/src/components/animationIntersector.ts b/src/components/animationIntersector.ts index 278518d2..585c4de8 100644 --- a/src/components/animationIntersector.ts +++ b/src/components/animationIntersector.ts @@ -6,7 +6,7 @@ import { RLottiePlayer } from "../lib/lottieLoader"; import rootScope from "../lib/rootScope"; -import { isSafari } from "../helpers/userAgent"; +import { IS_SAFARI } from "../environment/userAgent"; import { MOUNT_CLASS_TO } from "../config/debug"; import isInDOM from "../helpers/dom/isInDOM"; @@ -93,7 +93,7 @@ export class AnimationIntersector { const {el, animation} = player; animation.remove(); - if(animation instanceof HTMLVideoElement && isSafari) { + if(animation instanceof HTMLVideoElement && IS_SAFARI) { setTimeout(() => { // TODO: очистка по очереди, а не все вместе с этим таймаутом animation.src = ''; animation.load(); diff --git a/src/components/appMediaPlaybackController.ts b/src/components/appMediaPlaybackController.ts index c59c5afe..f79a53b9 100644 --- a/src/components/appMediaPlaybackController.ts +++ b/src/components/appMediaPlaybackController.ts @@ -8,7 +8,7 @@ import rootScope from "../lib/rootScope"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager"; import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise"; -import { isApple, isSafari } from "../helpers/userAgent"; +import { IS_APPLE, IS_SAFARI } from "../environment/userAgent"; import { MOUNT_CLASS_TO } from "../config/debug"; import appDownloadManager from "../lib/appManagers/appDownloadManager"; import simulateEvent from "../helpers/dom/dispatchEvent"; @@ -16,7 +16,7 @@ import type { SearchSuperContext } from "./appSearchSuper."; import { copy, deepEqual } from "../helpers/object"; import { DocumentAttribute, Message, MessageMedia, PhotoSize } from "../layer"; import appPhotosManager from "../lib/appManagers/appPhotosManager"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import appAvatarsManager from "../lib/appManagers/appAvatarsManager"; import appPeersManager from "../lib/appManagers/appPeersManager"; import I18n from "../lib/langPack"; @@ -34,7 +34,7 @@ type HTMLMediaElement = HTMLAudioElement | HTMLVideoElement; const SHOULD_USE_SAFARI_FIX = (() => { try { - return isSafari && +navigator.userAgent.match(/ Version\/(\d+)/)[1] < 14; + return IS_SAFARI && +navigator.userAgent.match(/ Version\/(\d+)/)[1] < 14; } catch(err) { return false; } @@ -296,8 +296,8 @@ class AppMediaPlaybackController { } if(!artwork.length) { - if(isApple) { - if(isTouchSupported) { + if(IS_APPLE) { + if(IS_TOUCH_SUPPORTED) { artwork.push({ src: `assets/img/apple-touch-icon-precomposed.png`, sizes: '180x180', diff --git a/src/components/appMediaViewer.ts b/src/components/appMediaViewer.ts index eec0b660..db3500b6 100644 --- a/src/components/appMediaViewer.ts +++ b/src/components/appMediaViewer.ts @@ -6,8 +6,8 @@ import { deferredPromise } from "../helpers/cancellablePromise"; import mediaSizes from "../helpers/mediaSizes"; -import { isTouchSupported } from "../helpers/touchSupport"; -import { isMobileSafari, isSafari } from "../helpers/userAgent"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; +import { IS_MOBILE_SAFARI, IS_SAFARI } from "../environment/userAgent"; import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager"; import appImManager from "../lib/appManagers/appImManager"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; @@ -52,6 +52,7 @@ import PopupDeleteMessages from "./popups/deleteMessages"; import RangeSelector from "./rangeSelector"; import windowSize from "../helpers/windowSize"; import ListLoader, { ListLoaderOptions } from "../helpers/listLoader"; +import MEDIA_MIME_TYPES_SUPPORTED from "../environment/mediaMimeTypesSupport"; const ZOOM_STEP = 0.5; const ZOOM_INITIAL_VALUE = 1; @@ -355,7 +356,7 @@ class AppMediaViewerBase { @@ -530,7 +531,7 @@ class AppMediaViewerBase { @@ -1401,7 +1402,7 @@ class AppMediaViewerBase { if(e.touches.length > 1) return; diff --git a/src/components/appSearchSuper..ts b/src/components/appSearchSuper..ts index 49fd15d8..bcc87b4b 100644 --- a/src/components/appSearchSuper..ts +++ b/src/components/appSearchSuper..ts @@ -38,7 +38,7 @@ import mediaSizes from "../helpers/mediaSizes"; import appImManager from "../lib/appManagers/appImManager"; import positionElementByIndex from "../helpers/dom/positionElementByIndex"; import cleanSearchText from "../helpers/cleanSearchText"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import handleTabSwipe from "../helpers/dom/handleTabSwipe"; import windowSize from "../helpers/windowSize"; import { formatPhoneNumber } from "../helpers/formatPhoneNumber"; @@ -133,7 +133,7 @@ class SearchContextMenu { }); }; - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { } else { attachContextMenuListener(attachTo, onContextMenu as any); @@ -326,7 +326,7 @@ export default class AppSearchSuper { this.tabsContainer = document.createElement('div'); this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container'); - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { handleTabSwipe(this.tabsContainer, (next) => { const prevId = this.selectTab.prevId(); this.selectTab(next ? prevId + 1 : prevId - 1); diff --git a/src/components/audio.ts b/src/components/audio.ts index 1b392086..bc773f13 100644 --- a/src/components/audio.ts +++ b/src/components/audio.ts @@ -12,7 +12,7 @@ import { MediaProgressLine } from "../lib/mediaPlayer"; import appMediaPlaybackController, { MediaItem } from "./appMediaPlaybackController"; import { DocumentAttribute } from "../layer"; import mediaSizes from "../helpers/mediaSizes"; -import { isSafari } from "../helpers/userAgent"; +import { IS_SAFARI } from "../environment/userAgent"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; import rootScope from "../lib/rootScope"; import './middleEllipsis'; @@ -558,7 +558,7 @@ export default class AudioElement extends HTMLElement { appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid); appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio - if(isSafari) { + if(IS_SAFARI) { this.audio.autoplay = true; } diff --git a/src/components/chat/autocompleteHelper.ts b/src/components/chat/autocompleteHelper.ts index 58e9fac8..272ac017 100644 --- a/src/components/chat/autocompleteHelper.ts +++ b/src/components/chat/autocompleteHelper.ts @@ -7,7 +7,7 @@ import attachListNavigation from "../../helpers/dom/attachListNavigation"; import EventListenerBase from "../../helpers/eventListenerBase"; import { safeAssign } from "../../helpers/object"; -import { isMobile } from "../../helpers/userAgent"; +import { IS_MOBILE } from "../../environment/userAgent"; import rootScope from "../../lib/rootScope"; import appNavigationController, { NavigationItem } from "../appNavigationController"; import SetTransition from "../singleTransition"; @@ -68,7 +68,7 @@ export default class AutocompleteHelper extends EventListenerBase<{ this.detach = detach; this.resetTarget = resetTarget; - if(!isMobile && !this.navigationItem) { + if(!IS_MOBILE && !this.navigationItem) { this.navigationItem = { type: 'autocomplete-helper', onPop: () => { diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 5dd0ad67..e55392ce 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -18,7 +18,7 @@ import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIds import type Chat from "./chat"; import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager"; import { getObjectKeysAndSort } from "../../helpers/object"; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import { logger } from "../../lib/logger"; import rootScope, { BroadcastEvents } from "../../lib/rootScope"; import AppMediaViewer from "../appMediaViewer"; @@ -32,7 +32,7 @@ import StickyIntersector from "../stickyIntersector"; import animationIntersector from "../animationIntersector"; import RichTextProcessor from "../../lib/richtextprocessor"; import mediaSizes from "../../helpers/mediaSizes"; -import { isAndroid, isApple, isMobile, isSafari } from "../../helpers/userAgent"; +import { IS_ANDROID, IS_APPLE, IS_MOBILE, IS_SAFARI } from "../../environment/userAgent"; import I18n, { i18n, langPack } from "../../lib/langPack"; import AvatarElement from "../avatar"; import { ripple } from "../ripple"; @@ -452,7 +452,7 @@ export default class ChatBubbles { }); } - if(!isMobile) { + if(!IS_MOBILE) { this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => { if(this.chat.selection.isSelecting || !this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId)) { @@ -864,7 +864,7 @@ export default class ChatBubbles { return; } - if(!isTouchSupported && findUpClassName(target, 'time')) { + if(!IS_TOUCH_SUPPORTED && findUpClassName(target, 'time')) { this.chat.selection.toggleByElement(bubble); return; } @@ -878,7 +878,7 @@ export default class ChatBubbles { cancelEvent(e); //console.log('bubble click', e); - if(isTouchSupported && this.chat.selection.selectedText) { + if(IS_TOUCH_SUPPORTED && this.chat.selection.selectedText) { this.chat.selection.selectedText = undefined; return; } @@ -1264,7 +1264,7 @@ export default class ChatBubbles { if(this.isHeavyAnimationInProgress && this.scrolledDown) return; //lottieLoader.checkAnimations(false, 'chat'); - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { if(this.isScrollingTimeout) { clearTimeout(this.isScrollingTimeout); } else if(!this.chatInner.classList.contains('is-scrolling')) { @@ -1313,7 +1313,7 @@ export default class ChatBubbles { this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false); //this.scrollable.attachSentinels(undefined, 300); - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { this.scrollable.container.addEventListener('touchmove', () => { if(this.isScrollingTimeout) { clearTimeout(this.isScrollingTimeout); @@ -2530,7 +2530,7 @@ export default class ChatBubbles { break; } - const withTail = !isAndroid && canHaveTail && !withReplies && USE_MEDIA_TAILS; + const withTail = !IS_ANDROID && canHaveTail && !withReplies && USE_MEDIA_TAILS; if(withTail) bubble.classList.add('with-media-tail'); wrapPhoto({ photo, @@ -2759,7 +2759,7 @@ export default class ChatBubbles { noAutoDownload: this.chat.noAutoDownloadMedia, }); } else { - const withTail = !isAndroid && !isApple && !isRound && canHaveTail && !withReplies && USE_MEDIA_TAILS; + const withTail = !IS_ANDROID && !IS_APPLE && !isRound && canHaveTail && !withReplies && USE_MEDIA_TAILS; if(withTail) bubble.classList.add('with-media-tail'); wrapVideo({ doc, @@ -3198,7 +3198,7 @@ export default class ChatBubbles { //this.scrollable.scrollTop = this.scrollable.scrollHeight; //isTouchSupported && isApple && (this.scrollable.container.style.overflow = ''); - if(isSafari/* && !isAppleMobile */) { // * fix blinking and jumping + if(IS_SAFARI/* && !isAppleMobile */) { // * fix blinking and jumping reflowScrollableElement(this.scrollable.container); } @@ -3376,7 +3376,7 @@ export default class ChatBubbles { // ! в хроме, каким-то образом из-за zoom-fade класса начинает прыгать скролл при подгрузке сообщений вверх, // ! т.е. скролл не ставится, так же, как в сафари при translateZ на блок выше scrollable - if(!isSafari) { + if(!IS_SAFARI) { this.needReflowScroll = true; } }); diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index c24b9441..83a57330 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -10,7 +10,7 @@ import type { AppPollsManager, Poll } from "../../lib/appManagers/appPollsManage import type { AppDocsManager, MyDocument } from "../../lib/appManagers/appDocsManager"; import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager"; import type Chat from "./chat"; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc"; import PopupDeleteMessages from "../popups/deleteMessages"; @@ -117,7 +117,7 @@ export default class ChatContextMenu { if(chat.selection.isSelecting && !button.withSelection) { good = false; } else { - good = contentWrapper || isTouchSupported || true ? + good = contentWrapper || IS_TOUCH_SUPPORTED || true ? button.verify() : button.notDirect && button.verify() && button.notDirect(); } @@ -135,7 +135,7 @@ export default class ChatContextMenu { }); }; - if(isTouchSupported/* && false */) { + if(IS_TOUCH_SUPPORTED/* && false */) { attachClickEvent(attachTo, (e) => { if(chat.selection.isSelecting) { return; @@ -284,7 +284,7 @@ export default class ChatContextMenu { const doc: MyDocument = this.message.media?.document; if(!doc) return false; - let hasTarget = !!isTouchSupported; + let hasTarget = !!IS_TOUCH_SUPPORTED; 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'); return isGoodType && hasTarget; diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index 7fb74432..9c017252 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -19,7 +19,7 @@ import type { AppInlineBotsManager } from '../../lib/appManagers/appInlineBotsMa import type { AppMessagesIdsManager } from '../../lib/appManagers/appMessagesIdsManager'; import type Chat from './chat'; import Recorder from '../../../public/recorder.min'; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import apiManager from "../../lib/mtproto/mtprotoworker"; //import Recorder from '../opus-recorder/dist/recorder.min'; import opusDecodeController from "../../lib/opusDecodeController"; @@ -44,7 +44,7 @@ import rootScope from '../../lib/rootScope'; import PopupPinMessage from '../popups/unpinMessage'; import { tsNow } from '../../helpers/date'; import appNavigationController, { NavigationItem } from '../appNavigationController'; -import { isMobile, isMobileSafari } from '../../helpers/userAgent'; +import { IS_MOBILE, IS_MOBILE_SAFARI } from '../../environment/userAgent'; import I18n, { i18n, join, LangPackKey } from '../../lib/langPack'; import { generateTail } from './bubbles'; import findUpClassName from '../../helpers/dom/findUpClassName'; @@ -79,6 +79,7 @@ import PopupDeleteMessages from '../popups/deleteMessages'; import fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing'; import { copy } from '../../helpers/object'; import PopupPeer from '../popups/peer'; +import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport'; const RECORD_MIN_TIME = 500; const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.'; @@ -331,9 +332,7 @@ export default class ChatInput { this.appImManager.openScheduled(this.chat.peerId); }, {listenerSetter: this.listenerSetter}); - this.listenerSetter.add(rootScope)('scheduled_new', (e) => { - const peerId = e.peerId; - + this.listenerSetter.add(rootScope)('scheduled_new', ({peerId}) => { if(this.chat.peerId !== peerId) { return; } @@ -341,9 +340,7 @@ export default class ChatInput { this.btnScheduled.classList.remove('hide'); }); - this.listenerSetter.add(rootScope)('scheduled_delete', (e) => { - const peerId = e.peerId; - + this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId}) => { if(this.chat.peerId !== peerId) { return; } @@ -370,7 +367,8 @@ export default class ChatInput { text: 'Chat.Input.Attach.PhotoOrVideo', onClick: () => { this.fileInput.value = ''; - this.fileInput.setAttribute('accept', 'image/*, video/*'); + const accept = [...MEDIA_MIME_TYPES_SUPPORTED].join(', '); + this.fileInput.setAttribute('accept', accept); this.willAttachType = 'media'; this.fileInput.click(); }, @@ -391,7 +389,7 @@ export default class ChatInput { onClick: () => { new PopupCreatePoll(this.chat).show(); }, - verify: (peerId, threadId) => this.appMessagesManager.canSendToPeer(peerId, threadId, 'send_polls') && peerId < 0 + verify: (peerId, threadId) => peerId < 0 && this.appMessagesManager.canSendToPeer(peerId, threadId, 'send_polls') }]; this.attachMenu = ButtonMenuToggle({noRipple: true, listenerSetter: this.listenerSetter}, 'top-left', this.attachMenuButtons); @@ -491,8 +489,7 @@ export default class ChatInput { } }); - this.listenerSetter.add(rootScope)('draft_updated', (e) => { - const {peerId, threadId, draft, force} = e; + this.listenerSetter.add(rootScope)('draft_updated', ({peerId, threadId, draft, force}) => { if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return; this.setDraft(draft, true, force); }); @@ -671,12 +668,12 @@ export default class ChatInput { }; private onEmoticonsOpen = () => { - const toggleClass = isTouchSupported ? 'flip-icon' : 'active'; + const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active'; this.btnToggleEmoticons.classList.toggle(toggleClass, true); }; private onEmoticonsClose = () => { - const toggleClass = isTouchSupported ? 'flip-icon' : 'active'; + const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active'; this.btnToggleEmoticons.classList.toggle(toggleClass, false); }; @@ -929,7 +926,7 @@ export default class ChatInput { } }); - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { attachClickEvent(this.messageInput, (e) => { this.appImManager.selectTab(1); // * set chat tab for album orientation //this.saveScroll(); @@ -1619,7 +1616,7 @@ export default class ChatInput { }; public clearInput(canSetDraft = true, fireEvent = true, clearValue = '') { - if(document.activeElement === this.messageInput && isMobileSafari) { // fix first char uppercase + if(document.activeElement === this.messageInput && IS_MOBILE_SAFARI) { // fix first char uppercase const i = document.createElement('input'); document.body.append(i); fixSafariStickyInput(i); @@ -1630,7 +1627,7 @@ export default class ChatInput { this.messageInputField.setValueSilently(clearValue); } - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { //this.messageInput.innerText = ''; } else { //this.attachMessageInputField(); @@ -1978,7 +1975,7 @@ export default class ChatInput { scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200); } */ - if(!isMobile) { + if(!IS_MOBILE) { appNavigationController.pushItem({ type: 'input-helper', onPop: () => { diff --git a/src/components/chat/markupTooltip.ts b/src/components/chat/markupTooltip.ts index efc2df82..1b2a4323 100644 --- a/src/components/chat/markupTooltip.ts +++ b/src/components/chat/markupTooltip.ts @@ -8,8 +8,8 @@ import type { AppImManager } from "../../lib/appManagers/appImManager"; import RichTextProcessor from "../../lib/richtextprocessor"; import ButtonIcon from "../buttonIcon"; import { clamp } from "../../helpers/number"; -import { isTouchSupported } from "../../helpers/touchSupport"; -import { isApple, isMobile } from "../../helpers/userAgent"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; +import { IS_APPLE, IS_MOBILE } from "../../environment/userAgent"; import appNavigationController from "../appNavigationController"; import { _i18n } from "../../lib/langPack"; import { cancelEvent } from "../../helpers/dom/cancelEvent"; @@ -313,7 +313,7 @@ export default class MarkupTooltip { this.container.classList.add('is-visible'); - if(!isMobile) { + if(!IS_MOBILE) { appNavigationController.pushItem({ type: 'markup', onPop: () => { @@ -337,7 +337,7 @@ export default class MarkupTooltip { //this.log('onMouseUpSingle'); this.waitingForMouseUp = false; - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { cancelEvent(e); if(this.mouseUpCounter++ === 0) { this.resetSelection(this.savedRange); @@ -362,7 +362,7 @@ export default class MarkupTooltip { } public cancelClosening() { - if(isTouchSupported && !isApple) { + if(IS_TOUCH_SUPPORTED && !IS_APPLE) { document.removeEventListener('mouseup', this.onMouseUpSingle); document.addEventListener('mouseup', (e) => { cancelEvent(e); @@ -394,8 +394,8 @@ export default class MarkupTooltip { return; } - if(isTouchSupported) { - if(isApple) { + if(IS_TOUCH_SUPPORTED) { + if(IS_APPLE) { this.show(); this.setTooltipPosition(); // * because can skip this in .show(); } else { diff --git a/src/components/chat/replyKeyboard.ts b/src/components/chat/replyKeyboard.ts index b544d8b1..2609ebb3 100644 --- a/src/components/chat/replyKeyboard.ts +++ b/src/components/chat/replyKeyboard.ts @@ -13,7 +13,7 @@ import rootScope from "../../lib/rootScope"; import { safeAssign } from "../../helpers/object"; import ListenerSetter, { Listener } from "../../helpers/listenerSetter"; import findUpClassName from "../../helpers/dom/findUpClassName"; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import findUpAsChild from "../../helpers/dom/findUpAsChild"; import { cancelEvent } from "../../helpers/dom/cancelEvent"; import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck"; @@ -64,7 +64,7 @@ export default class ReplyKeyboard extends DropdownHover { this.listenerSetter.add(this)('open', () => { this.render(); - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { this.touchListener = this.listenerSetter.add(document.body)('touchstart', this.onBodyTouchStart, {passive: false, capture: true}) as any as Listener; this.listenerSetter.add(this)('close', () => { this.listenerSetter.remove(this.touchListener); diff --git a/src/components/chat/selection.ts b/src/components/chat/selection.ts index 6b2cbf7f..163826e3 100644 --- a/src/components/chat/selection.ts +++ b/src/components/chat/selection.ts @@ -8,7 +8,7 @@ import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManage import type ChatBubbles from "./bubbles"; import type ChatInput from "./input"; import type Chat from "./chat"; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import Button from "../button"; import ButtonIcon from "../buttonIcon"; import CheckboxField from "../checkboxField"; @@ -19,7 +19,7 @@ import SetTransition from "../singleTransition"; import ListenerSetter from "../../helpers/listenerSetter"; import PopupSendNow from "../popups/sendNow"; import appNavigationController, { NavigationItem } from "../appNavigationController"; -import { isMobileSafari } from "../../helpers/userAgent"; +import { IS_MOBILE_SAFARI } from "../../environment/userAgent"; import I18n, { i18n, _i18n } from "../../lib/langPack"; import findUpClassName from "../../helpers/dom/findUpClassName"; import blurActiveElement from "../../helpers/dom/blurActiveElement"; @@ -85,7 +85,7 @@ class AppSelection { this.navigationType = 'multiselect-' + randomLong() as any; - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { this.listenerSetter.add(this.listenElement)('touchend', () => { if(!this.isSelecting) return; this.selectedText = getSelectedText(); @@ -367,7 +367,7 @@ class AppSelection { } } */ - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.listenElement.classList.toggle('no-select', this.isSelecting); if(wasSelecting) { @@ -390,7 +390,7 @@ class AppSelection { const forwards = !!size || forceSelection; this.onToggleSelection && this.onToggleSelection(forwards); - if(!isMobileSafari) { + if(!IS_MOBILE_SAFARI) { if(forwards) { appNavigationController.pushItem({ type: this.navigationType, diff --git a/src/components/chat/topbar.ts b/src/components/chat/topbar.ts index 53869479..0019ba8f 100644 --- a/src/components/chat/topbar.ts +++ b/src/components/chat/topbar.ts @@ -14,7 +14,7 @@ import type { AppUsersManager } from "../../lib/appManagers/appUsersManager"; import type Chat from "./chat"; import { RIGHT_COLUMN_ACTIVE_CLASSNAME } from "../sidebarRight"; import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes"; -import { isSafari } from "../../helpers/userAgent"; +import { IS_SAFARI } from "../../environment/userAgent"; import rootScope from "../../lib/rootScope"; import AvatarElement from "../avatar"; import Button from "../button"; @@ -685,7 +685,7 @@ export default class ChatTopbar { //return; if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF); - if(isSafari && resize) { + if(IS_SAFARI && resize) { this.chatUtils.classList.add('hide'); } @@ -695,7 +695,7 @@ export default class ChatTopbar { //mutationRAF = window.requestAnimationFrame(() => { //setTimeout(() => { - if(isSafari && resize) { + if(IS_SAFARI && resize) { this.chatUtils.classList.remove('hide'); } /* this.chatInfo.style.removeProperty('--utils-width'); diff --git a/src/components/emoticonsDropdown/index.ts b/src/components/emoticonsDropdown/index.ts index fba65642..44f88184 100644 --- a/src/components/emoticonsDropdown/index.ts +++ b/src/components/emoticonsDropdown/index.ts @@ -4,7 +4,7 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import appImManager from "../../lib/appManagers/appImManager"; import rootScope from "../../lib/rootScope"; import animationIntersector from "../animationIntersector"; @@ -61,7 +61,7 @@ export class EmoticonsDropdown extends DropdownHover { }); this.addEventListener('open', async() => { - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { //appImManager.chat.input.saveScroll(); if(blurActiveElement()) { await pause(100); diff --git a/src/components/emoticonsDropdown/tabs/emoji.ts b/src/components/emoticonsDropdown/tabs/emoji.ts index a38b62a9..1bc51b2e 100644 --- a/src/components/emoticonsDropdown/tabs/emoji.ts +++ b/src/components/emoticonsDropdown/tabs/emoji.ts @@ -9,7 +9,7 @@ import { cancelEvent } from "../../../helpers/dom/cancelEvent"; import findUpClassName from "../../../helpers/dom/findUpClassName"; import { fastRaf } from "../../../helpers/schedulers"; import { pause } from "../../../helpers/schedulers/pause"; -import { isTouchSupported } from "../../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../../environment/touchSupport"; import appEmojiManager from "../../../lib/appManagers/appEmojiManager"; import appImManager from "../../../lib/appManagers/appImManager"; import Config from "../../../lib/config"; @@ -20,6 +20,7 @@ import { emojiFromCodePoints } from "../../../vendor/emoji"; import { putPreloader } from "../../misc"; import Scrollable from "../../scrollable"; import StickyIntersector from "../../stickyIntersector"; +import IS_EMOJI_SUPPORTED from "../../../environment/emojiSupport"; const loadedURLs: Set = new Set(); export function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) { @@ -31,7 +32,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal spanEmoji.classList.add('super-emoji'); let kek: string; - if(unify && !RichTextProcessor.emojiSupported) { + if(unify && !IS_EMOJI_SUPPORTED) { kek = RichTextProcessor.wrapSingleEmoji(emoji); } else { emoji = RichTextProcessor.fixEmoji(emoji); @@ -53,7 +54,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal spanEmoji.append(first); } - if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) { + if(spanEmoji.firstElementChild && !IS_EMOJI_SUPPORTED) { const image = spanEmoji.firstElementChild as HTMLImageElement; const url = image.src; @@ -295,7 +296,7 @@ export default class EmojiTab implements EmoticonsTab { const html = RichTextProcessor.wrapEmojiText(emoji, true); let inserted = false; if(window.getSelection) { - const savedRange = isTouchSupported ? undefined : emoticonsDropdown.getSavedRange(); + const savedRange = IS_TOUCH_SUPPORTED ? undefined : emoticonsDropdown.getSavedRange(); let sel = window.getSelection(); if(savedRange) { sel.removeAllRanges(); diff --git a/src/components/misc.ts b/src/components/misc.ts index ab13e06c..a44e1691 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -9,8 +9,8 @@ import { cancelEvent } from "../helpers/dom/cancelEvent"; import { CLICK_EVENT_NAME } from "../helpers/dom/clickEvent"; import ListenerSetter from "../helpers/listenerSetter"; import mediaSizes from "../helpers/mediaSizes"; -import { isTouchSupported } from "../helpers/touchSupport"; -import { isApple, isMobileSafari } from "../helpers/userAgent"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; +import { IS_APPLE, IS_MOBILE_SAFARI } from "../environment/userAgent"; import rootScope from "../lib/rootScope"; import appNavigationController from "./appNavigationController"; @@ -101,7 +101,7 @@ export const closeBtnMenu = () => { openedMenuOnClose = null; } - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { window.removeEventListener('mousemove', onMouseMove); //window.removeEventListener('keydown', onKeyDown, {capture: true}); window.removeEventListener('contextmenu', onClick); @@ -109,7 +109,7 @@ export const closeBtnMenu = () => { document.removeEventListener(CLICK_EVENT_NAME, onClick); - if(!isMobileSafari) { + if(!IS_MOBILE_SAFARI) { appNavigationController.removeByType('menu'); } }; @@ -131,7 +131,7 @@ let openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null, menuOv export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) { closeBtnMenu(); - if(!isMobileSafari) { + if(!IS_MOBILE_SAFARI) { appNavigationController.pushItem({ type: 'menu', onPop: (canAnimate) => { @@ -161,7 +161,7 @@ export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) { openedMenuOnClose = onClose; - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { window.addEventListener('mousemove', onMouseMove); //window.addEventListener('keydown', onKeyDown, {capture: true}); window.addEventListener('contextmenu', onClick, {once: true}); @@ -297,7 +297,7 @@ export function attachContextMenuListener(element: HTMLElement, callback: (e: To const add = listenerSetter ? listenerSetter.add(element) : element.addEventListener.bind(element); const remove = listenerSetter ? listenerSetter.removeManual.bind(listenerSetter, element) : element.removeEventListener.bind(element); - if(isApple && isTouchSupported) { + if(IS_APPLE && IS_TOUCH_SUPPORTED) { let timeout: number; const options: EventListenerOptions = {capture: true}; @@ -343,7 +343,7 @@ export function attachContextMenuListener(element: HTMLElement, callback: (e: To }, {passive: false, capture: true}); } */ } else { - add('contextmenu', isTouchSupported ? (e: any) => { + add('contextmenu', IS_TOUCH_SUPPORTED ? (e: any) => { callback(e); if(openedMenu) { diff --git a/src/components/poll.ts b/src/components/poll.ts index 5ba5a5d5..0fabc713 100644 --- a/src/components/poll.ts +++ b/src/components/poll.ts @@ -5,7 +5,7 @@ */ import mediaSizes from "../helpers/mediaSizes"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import appImManager from "../lib/appManagers/appImManager"; import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsManager"; import serverTimeManager from "../lib/mtproto/serverTimeManager"; @@ -161,7 +161,7 @@ const setQuizHint = (solution: string, solution_entities: any[], onHide: () => v prevQuizHintOnHide = onHide; prevQuizHintTimeout = window.setTimeout(() => { hideQuizHint(element, onHide, prevQuizHintTimeout); - }, isTouchSupported ? 5000 : 7000); + }, IS_TOUCH_SUPPORTED ? 5000 : 7000); }; export default class PollElement extends HTMLElement { diff --git a/src/components/popups/newMedia.ts b/src/components/popups/newMedia.ts index 2c6eaa07..88e108b9 100644 --- a/src/components/popups/newMedia.ts +++ b/src/components/popups/newMedia.ts @@ -22,6 +22,7 @@ import rootScope from "../../lib/rootScope"; import RichTextProcessor from "../../lib/richtextprocessor"; import { MediaSize } from "../../helpers/mediaSizes"; import { attachClickEvent } from "../../helpers/dom/clickEvent"; +import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport'; type SendFileParams = Partial<{ file: File, @@ -368,13 +369,11 @@ export default class PopupNewMedia extends PopupElement { willAttach.type = 'document'; } */ - files = files.filter(file => { - if(willAttach.type === 'media') { - return ['image/', 'video/'].find(s => file.type.indexOf(s) === 0); - } else { - return true; - } - }); + if(willAttach.type === 'media') { + files = files.filter(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type)); + } else { + files = files.slice(); + } Promise.all(files.map(this.attachFile)).then(results => { this.container.classList.remove('is-media', 'is-document', 'is-album'); diff --git a/src/components/popups/pickUser.ts b/src/components/popups/pickUser.ts index 5e3d0e90..47021eab 100644 --- a/src/components/popups/pickUser.ts +++ b/src/components/popups/pickUser.ts @@ -4,7 +4,7 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import AppSelectPeers from "../appSelectPeers"; import PopupElement from "."; import { LangPackKey, _i18n } from "../../lib/langPack"; @@ -50,7 +50,7 @@ export default class PopupPickUser extends PopupElement { this.show(); this.selector.checkForTriggers(); // ! due to zero height before mounting - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.selector.input.focus(); } }, diff --git a/src/components/ripple.ts b/src/components/ripple.ts index 1eb51d1e..a6f34165 100644 --- a/src/components/ripple.ts +++ b/src/components/ripple.ts @@ -6,7 +6,7 @@ import findUpClassName from "../helpers/dom/findUpClassName"; import sequentialDom from "../helpers/sequentialDom"; -import {isTouchSupported} from "../helpers/touchSupport"; +import {IS_TOUCH_SUPPORTED} from "../environment/touchSupport"; import rootScope from "../lib/rootScope"; let rippleClickId = 0; @@ -63,7 +63,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise Promise { handler && handler(); }; diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts index b8a5341a..1c95a3b0 100644 --- a/src/components/scrollable.ts +++ b/src/components/scrollable.ts @@ -4,7 +4,7 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import { logger, LogTypes } from "../lib/logger"; import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll"; import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck"; @@ -248,7 +248,7 @@ export class ScrollableX extends ScrollableBase { this.container.classList.add('scrollable-x'); - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { const scrollHorizontally = (e: any) => { if(!e.deltaX && this.container.scrollWidth > this.container.clientWidth) { this.container.scrollLeft += e.deltaY / 4; diff --git a/src/components/sidebarLeft/index.ts b/src/components/sidebarLeft/index.ts index 9b37fd76..247a3aa2 100644 --- a/src/components/sidebarLeft/index.ts +++ b/src/components/sidebarLeft/index.ts @@ -28,7 +28,7 @@ import AppAddMembersTab from "./tabs/addMembers"; import { i18n_, LangPackKey } from "../../lib/langPack"; import { ButtonMenuItemOptions } from "../buttonMenu"; import CheckboxField from "../checkboxField"; -import { isMobileSafari } from "../../helpers/userAgent"; +import { IS_MOBILE_SAFARI } from "../../environment/userAgent"; import appNavigationController from "../appNavigationController"; import findUpClassName from "../../helpers/dom/findUpClassName"; import findUpTag from "../../helpers/dom/findUpTag"; @@ -531,7 +531,7 @@ export class AppSidebarLeft extends SidebarSlider { this.newBtnMenu.classList.add('is-hidden'); this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true); - if(!isMobileSafari && !appNavigationController.findItemByType('global-search')) { + if(!IS_MOBILE_SAFARI && !appNavigationController.findItemByType('global-search')) { appNavigationController.pushItem({ onPop: () => { close(); diff --git a/src/components/sidebarLeft/tabs/contacts.ts b/src/components/sidebarLeft/tabs/contacts.ts index 169932aa..2edba4c2 100644 --- a/src/components/sidebarLeft/tabs/contacts.ts +++ b/src/components/sidebarLeft/tabs/contacts.ts @@ -8,7 +8,7 @@ import { SliderSuperTab } from "../../slider"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appUsersManager from "../../../lib/appManagers/appUsersManager"; import InputSearch from "../../inputSearch"; -import { isMobile } from "../../../helpers/userAgent"; +import { IS_MOBILE } from "../../../environment/userAgent"; import { canFocus } from "../../../helpers/dom/canFocus"; import windowSize from "../../../helpers/windowSize"; import ButtonCorner from "../../buttonCorner"; @@ -75,7 +75,7 @@ export default class AppContactsTab extends SliderSuperTab { } protected onOpenAfterTimeout() { - if(isMobile || !canFocus(true)) return; + if(IS_MOBILE || !canFocus(true)) return; this.inputSearch.input.focus(); } diff --git a/src/components/sidebarLeft/tabs/generalSettings.ts b/src/components/sidebarLeft/tabs/generalSettings.ts index 85d410a5..5a9389d7 100644 --- a/src/components/sidebarLeft/tabs/generalSettings.ts +++ b/src/components/sidebarLeft/tabs/generalSettings.ts @@ -12,7 +12,7 @@ import CheckboxField from "../../checkboxField"; import RadioField from "../../radioField"; import appStateManager from "../../../lib/appManagers/appStateManager"; import rootScope from "../../../lib/rootScope"; -import { isApple } from "../../../helpers/userAgent"; +import { IS_APPLE } from "../../../environment/userAgent"; import Row from "../../row"; import AppBackgroundTab from "./background"; import { LangPackKey, _i18n } from "../../../lib/langPack"; @@ -120,7 +120,7 @@ export default class AppGeneralSettingsTab extends SliderSuperTab { }), subtitleLangKey: 'General.SendShortcut.NewLine.Enter' }); - _i18n(ctrlEnterRow.radioField.main, 'General.SendShortcut.CtrlEnter', [isApple ? '⌘' : 'Ctrl']); + _i18n(ctrlEnterRow.radioField.main, 'General.SendShortcut.CtrlEnter', [IS_APPLE ? '⌘' : 'Ctrl']); form.append(enterRow.container, ctrlEnterRow.container); container.append(form); diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts index 516aca7d..2d7957b9 100644 --- a/src/components/sidebarRight/tabs/sharedMedia.ts +++ b/src/components/sidebarRight/tabs/sharedMedia.ts @@ -39,8 +39,8 @@ import AppAddMembersTab from "../../sidebarLeft/tabs/addMembers"; import PopupPickUser from "../../popups/pickUser"; import PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from "../../popups/peer"; import Scrollable from "../../scrollable"; -import { isTouchSupported } from "../../../helpers/touchSupport"; -import { isFirefox } from "../../../helpers/userAgent"; +import { IS_TOUCH_SUPPORTED } from "../../../environment/touchSupport"; +import { IS_FIREFOX } from "../../../environment/userAgent"; import appDownloadManager from "../../../lib/appManagers/appDownloadManager"; import ButtonCorner from "../../buttonCorner"; import { cancelEvent } from "../../../helpers/dom/cancelEvent"; @@ -58,7 +58,7 @@ let setText = (text: string, row: Row) => { //}); }; -const PARALLAX_SUPPORTED = !isFirefox && false; +const PARALLAX_SUPPORTED = !IS_FIREFOX && false; export function filterChatPhotosMessages(value: { count: number; @@ -199,7 +199,7 @@ class PeerProfileAvatars { const cancelNextClick = () => { cancel = true; - document.body.addEventListener(isTouchSupported ? 'touchend' : 'click', (e) => { + document.body.addEventListener(IS_TOUCH_SUPPORTED ? 'touchend' : 'click', (e) => { cancel = false; }, {once: true}); }; diff --git a/src/components/swipeHandler.ts b/src/components/swipeHandler.ts index b38823f6..e6144073 100644 --- a/src/components/swipeHandler.ts +++ b/src/components/swipeHandler.ts @@ -6,7 +6,7 @@ import { cancelEvent } from "../helpers/dom/cancelEvent"; import { safeAssign } from "../helpers/object"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import rootScope from "../lib/rootScope"; const getEvent = (e: TouchEvent | MouseEvent) => { @@ -48,7 +48,7 @@ export default class SwipeHandler { } public setListeners() { - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.element.addEventListener('mousedown', this.handleStart, false); attachGlobalListenerTo.addEventListener('mouseup', this.reset); } else { @@ -58,7 +58,7 @@ export default class SwipeHandler { } public removeListeners() { - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.element.removeEventListener('mousedown', this.handleStart, false); attachGlobalListenerTo.removeEventListener('mouseup', this.reset); } else { @@ -72,7 +72,7 @@ export default class SwipeHandler { cancelEvent(e); } */ - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true}); } else { attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove); @@ -96,7 +96,7 @@ export default class SwipeHandler { this.xDown = e.clientX; this.yDown = e.clientY; - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { attachGlobalListenerTo.addEventListener('touchmove', this.handleMove, {passive: false, capture: true}); } else { attachGlobalListenerTo.addEventListener('mousemove', this.handleMove, false); @@ -127,7 +127,7 @@ export default class SwipeHandler { this.hadMove = true; - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.element.style.setProperty('cursor', this.cursor, 'important'); } diff --git a/src/components/telInputField.ts b/src/components/telInputField.ts index 87787467..b3d61318 100644 --- a/src/components/telInputField.ts +++ b/src/components/telInputField.ts @@ -6,7 +6,7 @@ import placeCaretAtEnd from "../helpers/dom/placeCaretAtEnd"; import { formatPhoneNumber } from "../helpers/formatPhoneNumber"; -import { isApple, isAndroid, isAppleMobile } from "../helpers/userAgent"; +import { IS_APPLE, IS_ANDROID, IS_APPLE_MOBILE } from "../environment/userAgent"; import { HelpCountry, HelpCountryCode } from "../layer"; import InputField, { InputFieldOptions } from "./inputField"; @@ -36,9 +36,9 @@ export default class TelInputField extends InputField { const pixelRatio = window.devicePixelRatio; if(pixelRatio > 1) { let letterSpacing: number; - if(isApple) { + if(IS_APPLE) { letterSpacing = pixelRatio * -.16; - } else if(isAndroid) { + } else if(IS_ANDROID) { letterSpacing = 0; } @@ -58,7 +58,7 @@ export default class TelInputField extends InputField { const value = this.value; const diff = Math.abs(value.length - this.lastValue.length); - if(diff > 1 && !this.pasted && isAppleMobile) { + if(diff > 1 && !this.pasted && IS_APPLE_MOBILE) { this.setValueSilently(this.lastValue + value); } diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index c0ba847c..6127fa34 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -11,7 +11,7 @@ import { deferredPromise } from '../helpers/cancellablePromise'; import { formatDateAccordingToToday, months } from '../helpers/date'; import mediaSizes, { ScreenSize } from '../helpers/mediaSizes'; import { formatBytes } from '../helpers/number'; -import { isSafari } from '../helpers/userAgent'; +import { IS_SAFARI } from '../environment/userAgent'; import { PhotoSize, StickerSet } from '../layer'; import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager"; import appMessagesManager from '../lib/appManagers/appMessagesManager'; @@ -44,6 +44,8 @@ import isInDOM from '../helpers/dom/isInDOM'; import lottieLoader from '../lib/lottieLoader'; import { clearBadCharsAndTrim } from '../helpers/cleanSearchText'; import blur from '../helpers/blur'; +import IS_WEBP_SUPPORTED from '../environment/webpSupport'; +import MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport'; const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB @@ -382,7 +384,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai loadPromise = Promise.reject(); } else if(!cacheContext.downloaded) { // * check for uploading video preloader.attach(container, false, null); - video.addEventListener(isSafari ? 'timeupdate' : 'canplay', () => { + video.addEventListener(IS_SAFARI ? 'timeupdate' : 'canplay', () => { preloader.detach(); }, {once: true}); } @@ -640,10 +642,12 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS } else if(doc.type === 'pdf') { download = appDocsManager.downloadDoc(doc, queueId); download.then(() => { - const cacheContext = appDownloadManager.getCacheContext(doc); - window.open(cacheContext.url); + setTimeout(() => { // wait for preloader animation end + const url = appDownloadManager.getCacheContext(doc).url; + window.open(url); + }, rootScope.settings.animationsEnabled ? 250 : 0); }); - } else if(doc.type === 'photo' || doc.type === 'video' || doc.mime_type.indexOf('video/') === 0) { + } else if(MEDIA_MIME_TYPES_SUPPORTED.has(doc.mime_type)) { download = appDocsManager.downloadDoc(doc, queueId); } else { download = appDocsManager.saveDocFile(doc, queueId); @@ -1149,7 +1153,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o if(thumb && thumb._ !== 'photoPathSize' && toneIndex <= 0) { thumbImage = new Image(); - if((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || cacheContext.url)/* && false */) { + if((IS_WEBP_SUPPORTED || doc.pFlags.stickerThumbConverted || cacheContext.url)/* && false */) { renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender); haveThumbCached = true; } else { diff --git a/src/environment/ctx.ts b/src/environment/ctx.ts new file mode 100644 index 00000000..a3496e50 --- /dev/null +++ b/src/environment/ctx.ts @@ -0,0 +1,3 @@ +const ctx = typeof(window) !== 'undefined' ? window : self; + +export default ctx; \ No newline at end of file diff --git a/src/helpers/emojiSupport.ts b/src/environment/emojiSupport.ts similarity index 100% rename from src/helpers/emojiSupport.ts rename to src/environment/emojiSupport.ts diff --git a/src/environment/mediaMimeTypesSupport.ts b/src/environment/mediaMimeTypesSupport.ts new file mode 100644 index 00000000..3125e725 --- /dev/null +++ b/src/environment/mediaMimeTypesSupport.ts @@ -0,0 +1,21 @@ +import IS_MOV_SUPPORTED from "./movSupport"; +import IS_WEBP_SUPPORTED from "./webpSupport"; + +const MEDIA_MIME_TYPES_SUPPORTED = new Set([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/bmp', + 'video/mp4', + 'video/webm' +]); + +if(IS_MOV_SUPPORTED) { + MEDIA_MIME_TYPES_SUPPORTED.add('video/quicktime'); +} + +if(IS_WEBP_SUPPORTED) { + MEDIA_MIME_TYPES_SUPPORTED.add('image/webp'); +} + +export default MEDIA_MIME_TYPES_SUPPORTED; diff --git a/src/environment/movSupport.ts b/src/environment/movSupport.ts new file mode 100644 index 00000000..68f336da --- /dev/null +++ b/src/environment/movSupport.ts @@ -0,0 +1,6 @@ +import { IS_APPLE_MOBILE, IS_SAFARI } from "./userAgent"; + +// mov is not supported in Chrome on macOS +const IS_MOV_SUPPORTED = !!document.createElement('video').canPlayType('video/quicktime') || IS_SAFARI || IS_APPLE_MOBILE; + +export default IS_MOV_SUPPORTED; diff --git a/src/helpers/touchSupport.ts b/src/environment/touchSupport.ts similarity index 53% rename from src/helpers/touchSupport.ts rename to src/environment/touchSupport.ts index d4ff1a7f..d74a06c1 100644 --- a/src/helpers/touchSupport.ts +++ b/src/environment/touchSupport.ts @@ -5,4 +5,4 @@ */ // @ts-ignore -export const isTouchSupported = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)/* || true */; \ No newline at end of file +export const IS_TOUCH_SUPPORTED = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)/* || true */; \ No newline at end of file diff --git a/src/environment/userAgent.ts b/src/environment/userAgent.ts new file mode 100644 index 00000000..ddc2cc38 --- /dev/null +++ b/src/environment/userAgent.ts @@ -0,0 +1,24 @@ +/* + * https://github.com/morethanwords/tweb + * Copyright (C) 2019-2021 Eduard Kuzmenko + * https://github.com/morethanwords/tweb/blob/master/LICENSE + */ + +import ctx from './ctx'; + +export const USER_AGENT = navigator ? navigator.userAgent : null; +export const IS_APPLE = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1; +export const IS_ANDROID = navigator.userAgent.toLowerCase().indexOf('android') !== -1; +export const IS_CHROMIUM = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); + +// https://stackoverflow.com/a/58065241 +export const IS_APPLE_MOBILE = (/iPad|iPhone|iPod/.test(navigator.platform) || + (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && + !(ctx as any).MSStream; + +export const IS_SAFARI = !!('safari' in ctx) || !!(USER_AGENT && (/\b(iPad|iPhone|iPod)\b/.test(USER_AGENT) || (!!USER_AGENT.match('Safari') && !USER_AGENT.match('Chrome'))))/* || true */; +export const IS_FIREFOX = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + +export const IS_MOBILE_SAFARI = IS_SAFARI && IS_APPLE_MOBILE; + +export const IS_MOBILE = /* screen.width && screen.width < 480 || */navigator.maxTouchPoints > 0 && navigator.userAgent.search(/iOS|iPhone OS|Android|BlackBerry|BB10|Series ?[64]0|J2ME|MIDP|opera mini|opera mobi|mobi.+Gecko|Windows Phone/i) != -1; diff --git a/src/environment/webpSupport.ts b/src/environment/webpSupport.ts new file mode 100644 index 00000000..497e4ba0 --- /dev/null +++ b/src/environment/webpSupport.ts @@ -0,0 +1,3 @@ +const IS_WEBP_SUPPORTED = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp'); + +export default IS_WEBP_SUPPORTED; \ No newline at end of file diff --git a/src/helpers/dom/canFocus.ts b/src/helpers/dom/canFocus.ts index 4fcd77b0..c795ccf1 100644 --- a/src/helpers/dom/canFocus.ts +++ b/src/helpers/dom/canFocus.ts @@ -4,8 +4,8 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import { isMobileSafari } from "../userAgent"; +import { IS_MOBILE_SAFARI } from "../../environment/userAgent"; export function canFocus(isFirstInput: boolean) { - return !isMobileSafari || !isFirstInput; + return !IS_MOBILE_SAFARI || !isFirstInput; } diff --git a/src/helpers/dom/clickEvent.ts b/src/helpers/dom/clickEvent.ts index 03bbe063..d60dbab0 100644 --- a/src/helpers/dom/clickEvent.ts +++ b/src/helpers/dom/clickEvent.ts @@ -5,10 +5,10 @@ */ import type ListenerSetter from "../listenerSetter"; -import { isTouchSupported } from "../touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import simulateEvent from "./dispatchEvent"; -export const CLICK_EVENT_NAME: 'mousedown' /* | 'touchend' */ | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any; +export const CLICK_EVENT_NAME: 'mousedown' /* | 'touchend' */ | 'click' = (IS_TOUCH_SUPPORTED ? 'mousedown' : 'click') as any; export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>; export function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* TouchEvent | */MouseEvent) => void, options: AttachClickOptions = {}) { const add = options.listenerSetter ? options.listenerSetter.add(elem) : elem.addEventListener.bind(elem); diff --git a/src/helpers/dom/fixSafariStickyInputFocusing.ts b/src/helpers/dom/fixSafariStickyInputFocusing.ts index 12a2cafd..a21c8b88 100644 --- a/src/helpers/dom/fixSafariStickyInputFocusing.ts +++ b/src/helpers/dom/fixSafariStickyInputFocusing.ts @@ -4,12 +4,12 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import { isTouchSupported } from "../touchSupport"; -import { isMobile, isSafari } from "../userAgent"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; +import { IS_MOBILE, IS_SAFARI } from "../../environment/userAgent"; import findUpClassName from "./findUpClassName"; import fixSafariStickyInput from "./fixSafariStickyInput"; -export const IS_STICKY_INPUT_BUGGED = isSafari && isMobile && isTouchSupported; +export const IS_STICKY_INPUT_BUGGED = IS_SAFARI && IS_MOBILE && IS_TOUCH_SUPPORTED; if(IS_STICKY_INPUT_BUGGED) { let key: 'clientY' | 'pageY' = 'clientY'; diff --git a/src/helpers/dom/handleScrollSideEvent.ts b/src/helpers/dom/handleScrollSideEvent.ts index f77dc5d0..8f16d42f 100644 --- a/src/helpers/dom/handleScrollSideEvent.ts +++ b/src/helpers/dom/handleScrollSideEvent.ts @@ -5,10 +5,10 @@ */ import type ListenerSetter from "../listenerSetter"; -import { isTouchSupported } from "../touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; export default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) { - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { let lastY: number; const options = {passive: true}; listenerSetter.add(elem)('touchstart', (e) => { diff --git a/src/helpers/dom/isSendShortcutPressed.ts b/src/helpers/dom/isSendShortcutPressed.ts index 9cb103c9..c66a418d 100644 --- a/src/helpers/dom/isSendShortcutPressed.ts +++ b/src/helpers/dom/isSendShortcutPressed.ts @@ -5,10 +5,10 @@ */ import rootScope from "../../lib/rootScope"; -import { isMobile, isApple } from "../userAgent"; +import { IS_MOBILE, IS_APPLE } from "../../environment/userAgent"; export default function isSendShortcutPressed(e: KeyboardEvent) { - if(e.key === 'Enter' && !isMobile && !e.isComposing) { + if(e.key === 'Enter' && !IS_MOBILE && !e.isComposing) { /* if(e.ctrlKey || e.metaKey) { this.messageInput.innerHTML += '
'; placeCaretAtEnd(this.message) @@ -22,8 +22,8 @@ export default function isSendShortcutPressed(e: KeyboardEvent) { return true; } else { - const secondaryKey = isApple ? e.metaKey : e.ctrlKey; - if(e.shiftKey || (isApple ? e.ctrlKey : e.metaKey)) { + const secondaryKey = IS_APPLE ? e.metaKey : e.ctrlKey; + if(e.shiftKey || (IS_APPLE ? e.ctrlKey : e.metaKey)) { return; } diff --git a/src/helpers/dom/placeCaretAtEnd.ts b/src/helpers/dom/placeCaretAtEnd.ts index d8542453..78f58825 100644 --- a/src/helpers/dom/placeCaretAtEnd.ts +++ b/src/helpers/dom/placeCaretAtEnd.ts @@ -9,10 +9,10 @@ * https://github.com/zhukov/webogram/blob/master/LICENSE */ -import { isTouchSupported } from "../touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; export default function placeCaretAtEnd(el: HTMLElement, ignoreTouchCheck = false) { - if(isTouchSupported && (!ignoreTouchCheck || document.activeElement !== el)) { + if(IS_TOUCH_SUPPORTED && (!ignoreTouchCheck || document.activeElement !== el)) { return; } diff --git a/src/helpers/dropdownHover.ts b/src/helpers/dropdownHover.ts index 72423be2..c80672a7 100644 --- a/src/helpers/dropdownHover.ts +++ b/src/helpers/dropdownHover.ts @@ -9,7 +9,7 @@ import findUpAsChild from "./dom/findUpAsChild"; import EventListenerBase from "./eventListenerBase"; import ListenerSetter from "./listenerSetter"; import { safeAssign } from "./object"; -import { isTouchSupported } from "./touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; const KEEP_OPEN = false; const TOGGLE_TIMEOUT = 200; @@ -35,7 +35,7 @@ export default class DropdownHover extends EventListenerBase<{ public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) { let firstTime = true; - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { attachClickEvent(button, () => { if(firstTime) { firstTime = false; @@ -76,7 +76,7 @@ export default class DropdownHover extends EventListenerBase<{ }; protected init() { - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.element.onmouseout = this.onMouseOut; this.element.onmouseover = (e) => { if(this.forceClose) { @@ -117,7 +117,7 @@ export default class DropdownHover extends EventListenerBase<{ this.displayTimeout = window.setTimeout(() => { this.forceClose = false; this.dispatchEvent('opened'); - }, isTouchSupported ? 0 : ANIMATION_DURATION); + }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION); // ! can't use together with resizeObserver /* if(isTouchSupported) { @@ -139,7 +139,7 @@ export default class DropdownHover extends EventListenerBase<{ this.element.style.display = 'none'; this.forceClose = false; this.dispatchEvent('closed'); - }, isTouchSupported ? 0 : ANIMATION_DURATION); + }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION); /* if(isTouchSupported) { const scrollHeight = this.container.scrollHeight; diff --git a/src/helpers/files.ts b/src/helpers/files.ts index 2f40926b..387c4fe6 100644 --- a/src/helpers/files.ts +++ b/src/helpers/files.ts @@ -6,7 +6,7 @@ import { makeMediaSize, MediaSize } from "./mediaSizes"; import { pause } from "./schedulers/pause"; -import { isAppleMobile } from "./userAgent"; +import { IS_APPLE_MOBILE } from "../environment/userAgent"; export function scaleMediaElement(options: { media: CanvasImageSource, @@ -76,7 +76,7 @@ export function onVideoLoad(video: HTMLVideoElement) { return; } - video.addEventListener(isAppleMobile ? 'loadeddata' : 'canplay', () => resolve(), {once: true}); + video.addEventListener(IS_APPLE_MOBILE ? 'loadeddata' : 'canplay', () => resolve(), {once: true}); }); } diff --git a/src/helpers/userAgent.ts b/src/helpers/userAgent.ts deleted file mode 100644 index 9a239545..00000000 --- a/src/helpers/userAgent.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * https://github.com/morethanwords/tweb - * Copyright (C) 2019-2021 Eduard Kuzmenko - * https://github.com/morethanwords/tweb/blob/master/LICENSE - */ - -export const userAgent = navigator ? navigator.userAgent : null; -export const isApple = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) !== -1; -export const isAndroid = navigator.userAgent.toLowerCase().indexOf('android') !== -1; -export const isChromium = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); - -export const ctx = typeof(window) !== 'undefined' ? window : self; - -// https://stackoverflow.com/a/58065241 -export const isAppleMobile = (/iPad|iPhone|iPod/.test(navigator.platform) || - (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && - !(ctx as any).MSStream; - -export const isSafari = !!('safari' in ctx) || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))))/* || true */; -export const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; - -export const isMobileSafari = isSafari && isAppleMobile; - -export const isMobile = /* screen.width && screen.width < 480 || */navigator.maxTouchPoints > 0 && navigator.userAgent.search(/iOS|iPhone OS|Android|BlackBerry|BB10|Series ?[64]0|J2ME|MIDP|opera mini|opera mobi|mobi.+Gecko|Windows Phone/i) != -1; diff --git a/src/index.ts b/src/index.ts index 0fbe0a6b..bf76910d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,8 +9,8 @@ import blurActiveElement from './helpers/dom/blurActiveElement'; import { cancelEvent } from './helpers/dom/cancelEvent'; import { IS_STICKY_INPUT_BUGGED } from './helpers/dom/fixSafariStickyInputFocusing'; import loadFonts from './helpers/dom/loadFonts'; -import IS_EMOJI_SUPPORTED from './helpers/emojiSupport'; -import { isMobileSafari } from './helpers/userAgent'; +import IS_EMOJI_SUPPORTED from './environment/emojiSupport'; +import { IS_MOBILE_SAFARI } from './environment/userAgent'; import './materialize.scss'; import './scss/style.scss'; import './scss/tgico.scss'; @@ -67,7 +67,7 @@ console.timeEnd('get storage1'); */ const vh = (setViewportVH && !rootScope.default.isOverlayActive ? w.height || w.innerHeight : window.innerHeight) * 0.01; if(lastVH === vh) { return; - } else if(touchSupport.isTouchSupported && lastVH < vh && (vh - lastVH) > 1) { + } else if(touchSupport.IS_TOUCH_SUPPORTED && lastVH < vh && (vh - lastVH) > 1) { blurActiveElement(); // (Android) fix blurring inputs when keyboard is being closed (e.g. closing keyboard by back arrow and touching a bubble) } @@ -101,8 +101,8 @@ console.timeEnd('get storage1'); */ const [_, touchSupport, userAgent, rootScope, appStateManager, I18n] = await Promise.all([ import('./lib/polyfill'), - import('./helpers/touchSupport'), - import('./helpers/userAgent'), + import('./environment/touchSupport'), + import('./environment/userAgent'), import('./lib/rootScope'), import('./lib/appManagers/appStateManager'), import('./lib/langPack'), @@ -146,7 +146,7 @@ console.timeEnd('get storage1'); */ }); } - if(userAgent.isFirefox && !IS_EMOJI_SUPPORTED) { + if(userAgent.IS_FIREFOX && !IS_EMOJI_SUPPORTED) { document.addEventListener('dragstart', (e) => { const target = e.target as HTMLElement; if(target.tagName === 'IMG' && target.classList.contains('emoji')) { @@ -164,23 +164,23 @@ console.timeEnd('get storage1'); */ } }); - if(userAgent.isFirefox) { + if(userAgent.IS_FIREFOX) { document.documentElement.classList.add('is-firefox'); } - if(userAgent.isApple) { - if(userAgent.isSafari) { + if(userAgent.IS_APPLE) { + if(userAgent.IS_SAFARI) { document.documentElement.classList.add('is-safari'); } document.documentElement.classList.add('emoji-supported'); - if(userAgent.isAppleMobile) { + if(userAgent.IS_APPLE_MOBILE) { document.documentElement.classList.add('is-ios'); } else { document.documentElement.classList.add('is-mac'); } - } else if(userAgent.isAndroid) { + } else if(userAgent.IS_ANDROID) { document.documentElement.classList.add('is-android'); /* document.addEventListener('focusin', (e) => { @@ -193,7 +193,7 @@ console.timeEnd('get storage1'); */ }, {passive: true}); */ } - if(!touchSupport.isTouchSupported) { + if(!touchSupport.IS_TOUCH_SUPPORTED) { document.documentElement.classList.add('no-touch'); } else { document.documentElement.classList.add('is-touch'); @@ -257,7 +257,7 @@ console.timeEnd('get storage1'); */ let scrollable: HTMLElement; if(el) { scrollable = el.querySelector('.scrollable') as HTMLElement; - if((!touchSupport.isTouchSupported || isMobileSafari)) { + if((!touchSupport.IS_TOUCH_SUPPORTED || IS_MOBILE_SAFARI)) { scrollable.classList.add('no-scrollbar'); } diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index f96198c9..944f2d81 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -15,7 +15,7 @@ import { ripple } from "../../components/ripple"; //import Scrollable from "../../components/scrollable"; import Scrollable, { ScrollableX, SliceSides } from "../../components/scrollable"; import { formatDateAccordingToTodayNew } from "../../helpers/date"; -import { isSafari } from "../../helpers/userAgent"; +import { IS_SAFARI } from "../../environment/userAgent"; import { logger, LogTypes } from "../logger"; import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; @@ -45,7 +45,7 @@ import appChatsManager from "./appChatsManager"; import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl"; import { fastRaf, fastRafConventional, fastRafPromise } from "../../helpers/schedulers"; import SortedUserList from "../../components/sortedUserList"; -import { isTouchSupported } from "../../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport"; import handleTabSwipe from "../../helpers/dom/handleTabSwipe"; import windowSize from "../../helpers/windowSize"; import isInDOM from "../../helpers/dom/isInDOM"; @@ -202,7 +202,7 @@ export class AppDialogsManager { }); } */ - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { handleTabSwipe(this.folders.container, (next) => { const prevId = selectTab.prevId(); selectTab(next ? prevId + 1 : prevId - 1); @@ -1100,7 +1100,7 @@ export class AppDialogsManager { const saveLength = 10; - const sliceFromStart = isSafari ? [] : children.slice(0, Math.max(0, firstIndex - saveLength)); + const sliceFromStart = IS_SAFARI ? [] : children.slice(0, Math.max(0, firstIndex - saveLength)); const sliceFromEnd = children.slice(lastIndex + saveLength); /* if(sliceFromStart.length !== sliceFromEnd.length) { diff --git a/src/lib/appManagers/appDocsManager.ts b/src/lib/appManagers/appDocsManager.ts index 55fd5ac2..4c90eb9e 100644 --- a/src/lib/appManagers/appDocsManager.ts +++ b/src/lib/appManagers/appDocsManager.ts @@ -15,7 +15,6 @@ import { Document, InputFileLocation, InputMedia, PhotoSize } from '../../layer' import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase'; import opusDecodeController from '../opusDecodeController'; import { RichTextProcessor } from '../richtextprocessor'; -import webpWorkerController from '../webp/webpWorkerController'; import appDownloadManager, { DownloadBlob } from './appDownloadManager'; import appPhotosManager from './appPhotosManager'; import blur from '../../helpers/blur'; @@ -23,11 +22,16 @@ import apiManager from '../mtproto/mtprotoworker'; import { MOUNT_CLASS_TO } from '../../config/debug'; import { getFullDate } from '../../helpers/date'; import rootScope from '../rootScope'; +import IS_WEBP_SUPPORTED from '../../environment/webpSupport'; export type MyDocument = Document.document; // TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается +const EXTENSION_MIME_TYPE_MAP: {[key: string]: string} = { + mov: 'video/quicktime' +}; + export class AppDocsManager { private docs: {[docId: string]: MyDocument} = {}; private savingLottiePreview: {[docId: string]: true} = {}; @@ -135,7 +139,7 @@ export class AppDocsManager { } // * there can be no thumbs, then it is a document - if(/* apiDoc.thumbs && */doc.mime_type === 'image/webp' && (doc.thumbs || webpWorkerController.isWebpSupported())) { + if(/* apiDoc.thumbs && */doc.mime_type === 'image/webp' && (doc.thumbs || IS_WEBP_SUPPORTED)) { doc.type = 'sticker'; doc.sticker = 1; } @@ -158,28 +162,32 @@ export class AppDocsManager { }); if(!doc.mime_type) { - switch(doc.type) { - case 'gif': - case 'video': - case 'round': - doc.mime_type = 'video/mp4'; - break; - case 'sticker': - doc.mime_type = 'image/webp'; - break; - case 'audio': - doc.mime_type = 'audio/mpeg'; - break; - case 'voice': - doc.mime_type = 'audio/ogg'; - break; - default: - doc.mime_type = 'application/octet-stream'; - break; + const ext = (doc.file_name || '').split('.').pop(); + const mappedMimeType = ext && EXTENSION_MIME_TYPE_MAP[ext.toLowerCase()]; + if(mappedMimeType) { + doc.mime_type = mappedMimeType; + } else { + switch(doc.type) { + case 'gif': + case 'video': + case 'round': + doc.mime_type = 'video/mp4'; + break; + case 'sticker': + doc.mime_type = 'image/webp'; + break; + case 'audio': + doc.mime_type = 'audio/mpeg'; + break; + case 'voice': + doc.mime_type = 'audio/ogg'; + break; + default: + doc.mime_type = 'application/octet-stream'; + break; + } } - } - - if(doc.mime_type === 'application/pdf') { + } else if(doc.mime_type === 'application/pdf') { doc.type = 'pdf'; } diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index b10615be..f8769509 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -26,7 +26,7 @@ import appStickersManager from './appStickersManager'; import appWebPagesManager from './appWebPagesManager'; import PopupNewMedia from '../../components/popups/newMedia'; import MarkupTooltip from '../../components/chat/markupTooltip'; -import { isTouchSupported } from '../../helpers/touchSupport'; +import { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport'; import appPollsManager from './appPollsManager'; import SetTransition from '../../components/singleTransition'; import ChatDragAndDrop from '../../components/chat/dragAndDrop'; @@ -67,13 +67,14 @@ import { pause } from '../../helpers/schedulers/pause'; import appMessagesIdsManager from './appMessagesIdsManager'; import { InternalLink, InternalLinkTypeMap, INTERNAL_LINK_TYPE } from './internalLink'; import RichTextProcessor from '../richtextprocessor'; +import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport'; //console.log('appImManager included33!'); appSidebarLeft; // just to include export const CHAT_ANIMATION_GROUP = 'chat'; -const FOCUS_EVENT_NAME = isTouchSupported ? 'touchstart' : 'mousemove'; +const FOCUS_EVENT_NAME = IS_TOUCH_SUPPORTED ? 'touchstart' : 'mousemove'; export type ChatSavedPosition = { mids: number[], @@ -495,7 +496,7 @@ export class AppImManager { e.target !== chat.input.messageInput && target.tagName !== 'INPUT' && !target.hasAttribute('contenteditable') && - !isTouchSupported && + !IS_TOUCH_SUPPORTED && (!mediaSizes.isMobile || this.tabId === 1) && !this.chat.selection.isSelecting && !this.chat.input.recording) { @@ -891,7 +892,7 @@ export class AppImManager { appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]); }); - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.attachDragAndDropListeners(); } @@ -917,10 +918,10 @@ export class AppImManager { } if(mount && !drops.length) { - const types: string[] = await getFilesFromEvent(e, true) + const types: string[] = await getFilesFromEvent(e, true); const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari - const foundMedia = types.filter(t => ['image', 'video'].includes(t.split('/')[0])).length; + const foundMedia = types.filter(t => MEDIA_MIME_TYPES_SUPPORTED.has(t)).length; const foundDocuments = types.length - foundMedia; this.log('drag files', types); @@ -1029,12 +1030,12 @@ export class AppImManager { getFilesFromEvent(e).then((files: File[]) => { if(files.length) { - if(attachType === 'media' && files.find(file => !['image', 'video'].includes(file.type.split('/')[0]))) { + if(/* attachType === 'media' && */files.find(file => !MEDIA_MIME_TYPES_SUPPORTED.has(file.type))) { attachType = 'document'; } const chatInput = this.chat.input; - chatInput.willAttachType = attachType || (files[0].type.indexOf('image/') === 0 ? 'media' : "document"); + chatInput.willAttachType = attachType || (MEDIA_MIME_TYPES_SUPPORTED.has(files[0].type) ? 'media' : "document"); new PopupNewMedia(this.chat, files, chatInput.willAttachType); } }); diff --git a/src/lib/appManagers/appNotificationsManager.ts b/src/lib/appManagers/appNotificationsManager.ts index d3b0dc1d..0f68402f 100644 --- a/src/lib/appManagers/appNotificationsManager.ts +++ b/src/lib/appManagers/appNotificationsManager.ts @@ -15,7 +15,7 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePr import { tsNow } from "../../helpers/date"; import { deepEqual } from "../../helpers/object"; import { convertInputKeyToKey } from "../../helpers/string"; -import { isMobile } from "../../helpers/userAgent"; +import { IS_MOBILE } from "../../environment/userAgent"; import { InputNotifyPeer, InputPeerNotifySettings, NotifyPeer, PeerNotifySettings, Update } from "../../layer"; import I18n from "../langPack"; import apiManager from "../mtproto/mtprotoworker"; @@ -209,7 +209,7 @@ export class AppNotificationsManager { } private toggleToggler(enable = rootScope.idle.isIDLE) { - if(isMobile) return; + if(IS_MOBILE) return; const resetTitle = () => { this.titleChanged = false; @@ -616,7 +616,7 @@ export class AppNotificationsManager { } this.notificationsShown[key] = notification; - if(!isMobile) { + if(!IS_MOBILE) { setTimeout(() => { this.hide(key); }, 8000); diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index 6594d933..971e9336 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -14,7 +14,7 @@ import { bytesFromHex } from "../../helpers/bytes"; import { CancellablePromise } from "../../helpers/cancellablePromise"; import { getFileNameByLocation } from "../../helpers/fileName"; import { safeReplaceArrayInObject, isObject } from "../../helpers/object"; -import { isSafari } from "../../helpers/userAgent"; +import { IS_SAFARI } from "../../environment/userAgent"; import { InputFileLocation, InputMedia, InputPhoto, Photo, PhotoSize, PhotosPhotos } from "../../layer"; import apiManager from "../mtproto/mtprotoworker"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; @@ -165,7 +165,7 @@ export class AppPhotosManager { let mimeType: string; if(isSticker) { - mimeType = isSafari ? 'image/png' : 'image/webp'; + mimeType = IS_SAFARI ? 'image/png' : 'image/webp'; } else { mimeType = 'image/jpeg'; } diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index 2368ec83..3a87f0b8 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -19,7 +19,7 @@ import App from '../../config/app'; import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug'; import AppStorage from '../storage'; import { Chat } from '../../layer'; -import { isMobile } from '../../helpers/userAgent'; +import { IS_MOBILE } from '../../environment/userAgent'; import DATABASE_STATE from '../../config/databases/state'; import sessionStorage from '../sessionStorage'; import { nextRandomUint } from '../../helpers/random'; @@ -112,7 +112,7 @@ export const STATE_INIT: State = { recentSearch: [], version: STATE_VERSION, authState: { - _: isMobile ? 'authStateSignIn' : 'authStateSignQr' + _: IS_MOBILE ? 'authStateSignIn' : 'authStateSignQr' }, hiddenPinnedMessages: {}, settings: { diff --git a/src/lib/lottieLoader.ts b/src/lib/lottieLoader.ts index 3369758d..ff4659fc 100644 --- a/src/lib/lottieLoader.ts +++ b/src/lib/lottieLoader.ts @@ -11,7 +11,7 @@ import EventListenerBase from "../helpers/eventListenerBase"; import mediaSizes from "../helpers/mediaSizes"; import { clamp } from '../helpers/number'; import { pause } from '../helpers/schedulers/pause'; -import { isAndroid, isApple, isAppleMobile, isSafari } from "../helpers/userAgent"; +import { IS_ANDROID, IS_APPLE, IS_APPLE_MOBILE, IS_SAFARI } from "../environment/userAgent"; import { logger, LogTypes } from "./logger"; import apiManager from "./mtproto/mtprotoworker"; @@ -107,7 +107,7 @@ export class RLottiePlayer extends EventListenerBase<{ // * Skip ratio (30fps) let skipRatio: number; if(options.skipRatio !== undefined) skipRatio = options.skipRatio; - else if((isAndroid || isAppleMobile || (isApple && !isSafari)) && this.width < 100 && this.height < 100) { + else if((IS_ANDROID || IS_APPLE_MOBILE || (IS_APPLE && !IS_SAFARI)) && this.width < 100 && this.height < 100) { skipRatio = 0.5; } @@ -125,7 +125,7 @@ export class RLottiePlayer extends EventListenerBase<{ this.height = Math.round(this.height * pixelRatio); } else if(pixelRatio > 1) { if(this.width > 100 && this.height > 100) { - if(isApple || !mediaSizes.isMobile) { + if(IS_APPLE || !mediaSizes.isMobile) { /* this.width = Math.round(this.width * (pixelRatio - 1)); this.height = Math.round(this.height * (pixelRatio - 1)); */ this.width = Math.round(this.width * pixelRatio); @@ -146,7 +146,7 @@ export class RLottiePlayer extends EventListenerBase<{ // * Cache frames params if(!options.noCache/* && false */) { // проверка на размер уже после скейлинга, сделано для попапа и сайдбара, где стикеры 80х80 и 68х68, туда нужно 75% - if(isApple && this.width > 100 && this.height > 100) { + if(IS_APPLE && this.width > 100 && this.height > 100) { this.cachingDelta = 2; //2 // 50% } else if(this.width < 100 && this.height < 100) { this.cachingDelta = Infinity; // 100% @@ -303,7 +303,7 @@ export class RLottiePlayer extends EventListenerBase<{ public requestFrame(frameNo: number) { if(this.frames[frameNo]) { this.renderFrame(this.frames[frameNo], frameNo); - } else if(isSafari) { + } else if(IS_SAFARI) { this.sendQuery('renderFrame', frameNo); } else { if(!this.clamped.length) { // fix detached @@ -480,7 +480,7 @@ class QueryableWorker extends EventListenerBase { } public sendQuery(queryMethod: string, ...args: any[]) { - if(isSafari) { + if(IS_SAFARI) { this.worker.postMessage({ 'queryMethod': queryMethod, 'queryMethodArguments': args diff --git a/src/lib/mediaPlayer.ts b/src/lib/mediaPlayer.ts index 3bc060d5..4d12d5c2 100644 --- a/src/lib/mediaPlayer.ts +++ b/src/lib/mediaPlayer.ts @@ -5,8 +5,8 @@ */ import appMediaPlaybackController from "../components/appMediaPlaybackController"; -import { isAppleMobile } from "../helpers/userAgent"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_APPLE_MOBILE } from "../environment/userAgent"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import RangeSelector from "../components/rangeSelector"; import { onVideoLoad } from "../helpers/files"; import { cancelEvent } from "../helpers/dom/cancelEvent"; @@ -314,12 +314,12 @@ export default class VideoPlayer extends EventListenerBase<{ }); this.listenerSetter.add(video)('click', () => { - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.togglePlay(); } }); - if(isTouchSupported) { + if(IS_TOUCH_SUPPORTED) { this.listenerSetter.add(player)('click', () => { this.toggleControls(); }); @@ -390,7 +390,7 @@ export default class VideoPlayer extends EventListenerBase<{ }); */ this.listenerSetter.add(video)('dblclick', () => { - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { this.toggleFullScreen(fullScreenButton); } }); @@ -537,7 +537,7 @@ export default class VideoPlayer extends EventListenerBase<{ const player = this.wrapper; // * https://caniuse.com/#feat=fullscreen - if(isAppleMobile) { + if(IS_APPLE_MOBILE) { const video = this.video as any; video.webkitEnterFullscreen(); video.enterFullscreen(); diff --git a/src/lib/mtproto/apiFileManager.ts b/src/lib/mtproto/apiFileManager.ts index 1af81b7a..cea29ca6 100644 --- a/src/lib/mtproto/apiFileManager.ts +++ b/src/lib/mtproto/apiFileManager.ts @@ -27,7 +27,7 @@ import apiManager from "./apiManager"; import { isWebpSupported } from "./mtproto.worker"; import { bytesToHex } from "../../helpers/bytes"; import assumeType from "../../helpers/assumeType"; -import { ctx } from "../../helpers/userAgent"; +import ctx from "../../environment/ctx"; type Delayed = { offset: number, diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index e5c9fb75..9ea03785 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -23,11 +23,12 @@ import type { MethodDeclMap } from '../../layer'; import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise'; import { bytesFromHex, bytesToHex } from '../../helpers/bytes'; //import { clamp } from '../../helpers/number'; -import { ctx, isSafari } from '../../helpers/userAgent'; +import { IS_SAFARI } from '../../environment/userAgent'; import App from '../../config/app'; import { MOUNT_CLASS_TO } from '../../config/debug'; import IDBStorage from '../idb'; import CryptoWorker from "../crypto/cryptoworker"; +import ctx from '../../environment/ctx'; /// #if !MTPROTO_WORKER import rootScope from '../rootScope'; @@ -203,7 +204,7 @@ export class ApiManager { /// #if MTPROTO_HTTP_UPLOAD // @ts-ignore - const transportType: TransportType = connectionType === 'upload' && isSafari ? 'https' : 'websocket'; + const transportType: TransportType = connectionType === 'upload' && IS_SAFARI ? 'https' : 'websocket'; //const transportType: TransportType = connectionType !== 'client' ? 'https' : 'websocket'; /// #else // @ts-ignore diff --git a/src/lib/mtproto/dcConfigurator.ts b/src/lib/mtproto/dcConfigurator.ts index 6968a206..8da77c88 100644 --- a/src/lib/mtproto/dcConfigurator.ts +++ b/src/lib/mtproto/dcConfigurator.ts @@ -19,7 +19,7 @@ import HTTP from './transports/http'; /// #if !MTPROTO_HTTP import Socket from './transports/websocket'; import TcpObfuscated from './transports/tcpObfuscated'; -import { isSafari } from '../../helpers/userAgent'; +import { IS_SAFARI } from '../../environment/userAgent'; import { isWebWorker } from '../../helpers/context'; import SocketProxied from './transports/socketProxied'; import App from '../../config/app'; @@ -64,7 +64,7 @@ export class DcConfigurator { const retryTimeout = connectionType === 'client' ? 10000 : 10000; - const oooohLetMeLive: MTConnectionConstructable = (isSafari && isWebWorker && typeof(SocketProxied) !== 'undefined') /* || true */ ? SocketProxied : Socket; + const oooohLetMeLive: MTConnectionConstructable = (IS_SAFARI && isWebWorker && typeof(SocketProxied) !== 'undefined') /* || true */ ? SocketProxied : Socket; return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout); }; diff --git a/src/lib/mtproto/mtproto.worker.ts b/src/lib/mtproto/mtproto.worker.ts index edf94f7f..d354fac1 100644 --- a/src/lib/mtproto/mtproto.worker.ts +++ b/src/lib/mtproto/mtproto.worker.ts @@ -15,12 +15,12 @@ import apiManager from "./apiManager"; import cryptoWorker from "../crypto/cryptoworker"; import networkerFactory from "./networkerFactory"; import apiFileManager from './apiFileManager'; -import { ctx } from '../../helpers/userAgent'; import { notifyAll } from '../../helpers/context'; import CacheStorageController from '../cacheStorage'; import sessionStorage from '../sessionStorage'; import { socketsProxied } from './transports/socketProxied'; import { bytesToHex } from '../../helpers/bytes'; +import ctx from '../../environment/ctx'; let webpSupported = false; export const isWebpSupported = () => { diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index e3ff3701..6993c19c 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -30,6 +30,7 @@ import { SocketProxyTask } from './transports/socketProxied'; import telegramMeWebManager from './telegramMeWebManager'; import { CacheStorageDbName } from '../cacheStorage'; import { pause } from '../../helpers/schedulers/pause'; +import IS_WEBP_SUPPORTED from '../../environment/webpSupport'; type Task = { taskId: number, @@ -318,7 +319,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods { this.postMessagesWaiting.forEach(args => this.postMessage(...args)); this.postMessagesWaiting.length = 0; - const isWebpSupported = webpWorkerController.isWebpSupported(); + const isWebpSupported = IS_WEBP_SUPPORTED; this.log('WebP supported:', isWebpSupported); this.postMessage({type: 'webpSupport', payload: isWebpSupported}); this.postMessage({type: 'userAgent', payload: navigator.userAgent}); diff --git a/src/lib/mtproto/webPushApiManager.ts b/src/lib/mtproto/webPushApiManager.ts index 505391b2..3d0dcb41 100644 --- a/src/lib/mtproto/webPushApiManager.ts +++ b/src/lib/mtproto/webPushApiManager.ts @@ -17,7 +17,7 @@ import rootScope from "../rootScope"; import { ServiceWorkerNotificationsClearTask, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "../serviceWorker/index.service"; import apiManager from "./mtprotoworker"; import I18n, { LangPackKey } from "../langPack"; -import { isMobile } from "../../helpers/userAgent"; +import { IS_MOBILE } from "../../environment/userAgent"; import appRuntimeManager from "../appManagers/appRuntimeManager"; export type PushSubscriptionNotifyType = 'init' | 'subscribe' | 'unsubscribe'; @@ -163,8 +163,8 @@ export class WebPushApiManager { const lang: ServiceWorkerPingTask['payload']['lang'] = {} as any; const ACTIONS_LANG_MAP: Record = { - push_action_mute1d: isMobile ? 'PushNotification.Action.Mute1d.Mobile' : 'PushNotification.Action.Mute1d', - push_action_settings: isMobile ? 'PushNotification.Action.Settings.Mobile' : 'PushNotification.Action.Settings', + push_action_mute1d: IS_MOBILE ? 'PushNotification.Action.Mute1d.Mobile' : 'PushNotification.Action.Mute1d', + push_action_settings: IS_MOBILE ? 'PushNotification.Action.Settings.Mobile' : 'PushNotification.Action.Settings', push_message_nopreview: 'PushNotification.Message.NoPreview' }; diff --git a/src/lib/opusDecodeController.ts b/src/lib/opusDecodeController.ts index 4d4639b2..2dccc158 100644 --- a/src/lib/opusDecodeController.ts +++ b/src/lib/opusDecodeController.ts @@ -5,7 +5,7 @@ */ import { MOUNT_CLASS_TO } from "../config/debug"; -import { isSafari } from "../helpers/userAgent"; +import { IS_SAFARI } from "../environment/userAgent"; import { logger, LogTypes } from "./logger"; type Result = { @@ -72,7 +72,7 @@ export class OpusDecodeController { this.wavWorker.postMessage({ command: 'encode', buffers: e.data - }, isSafari ? undefined : data.map((typedArray: Uint8Array) => typedArray.buffer)); + }, IS_SAFARI ? undefined : data.map((typedArray: Uint8Array) => typedArray.buffer)); } }); } @@ -136,7 +136,7 @@ export class OpusDecodeController { command: 'decode', pages: task.pages, waveform: task.withWaveform - }, isSafari ? undefined : [task.pages.buffer]); + }, IS_SAFARI ? undefined : [task.pages.buffer]); //}, 1e3); task.timeout = window.setTimeout(() => { diff --git a/src/lib/richtextprocessor.ts b/src/lib/richtextprocessor.ts index 35b1a1ac..fa2e5746 100644 --- a/src/lib/richtextprocessor.ts +++ b/src/lib/richtextprocessor.ts @@ -15,9 +15,9 @@ import emojiRegExp from '../vendor/emoji/regex'; import { encodeEmoji, toCodePoints } from '../vendor/emoji'; import { MessageEntity } from '../layer'; import { encodeEntities } from '../helpers/string'; -import { isSafari } from '../helpers/userAgent'; +import { IS_SAFARI } from '../environment/userAgent'; import { MOUNT_CLASS_TO } from '../config/debug'; -import IS_EMOJI_SUPPORTED from '../helpers/emojiSupport'; +import IS_EMOJI_SUPPORTED from '../environment/emojiSupport'; const EmojiHelper = { emojiMap: (code: string) => { return code; }, @@ -115,8 +115,6 @@ for(let i in markdownEntities) { } namespace RichTextProcessor { - export const emojiSupported = IS_EMOJI_SUPPORTED; - export function getEmojiSpritesheetCoords(emojiCode: string) { let unified = encodeEmoji(emojiCode).replace(/-?fe0f/g, ''); @@ -406,7 +404,7 @@ namespace RichTextProcessor { currentEntities.push(...filtered); currentEntities.sort((a, b) => a.offset - b.offset); - if(!emojiSupported) { // fix splitted emoji. messageEntityTextUrl can split the emoji if starts before its end (e.g. on fe0f) + if(!IS_EMOJI_SUPPORTED) { // fix splitted emoji. messageEntityTextUrl can split the emoji if starts before its end (e.g. on fe0f) for(let i = 0; i < currentEntities.length; ++i) { const entity = currentEntities[i]; if(entity._ === 'messageEntityEmoji') { @@ -507,7 +505,7 @@ namespace RichTextProcessor { case 'messageEntityStrike': { if(options.wrappingDraft) { - const styleName = isSafari ? 'text-decoration' : 'text-decoration-line'; + const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line'; insertPart(entity, ``, ''); } else { insertPart(entity, '', ''); @@ -518,7 +516,7 @@ namespace RichTextProcessor { case 'messageEntityUnderline': { if(options.wrappingDraft) { - const styleName = isSafari ? 'text-decoration' : 'text-decoration-line'; + const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line'; insertPart(entity, ``, ''); } else { insertPart(entity, '', ''); @@ -571,9 +569,9 @@ namespace RichTextProcessor { } case 'messageEntityEmoji': { - //if(!(options.wrappingDraft && emojiSupported)) { // * fix safari emoji - if(!emojiSupported) { // no wrapping needed - // if(emojiSupported) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера + //if(!(options.wrappingDraft && IS_EMOJI_SUPPORTED)) { // * fix safari emoji + if(!IS_EMOJI_SUPPORTED) { // no wrapping needed + // if(IS_EMOJI_SUPPORTED) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера // insertPart(entity, '', ''); // } else { insertPart(entity, ``, ``); @@ -581,10 +579,10 @@ namespace RichTextProcessor { //} else if(options.mustWrapEmoji) { } else if(!options.wrappingDraft) { insertPart(entity, '', ''); - } else if(!isSafari) { + } else if(!IS_SAFARI) { insertPart(entity, '', ''); } - /* if(!emojiSupported) { + /* if(!IS_EMOJI_SUPPORTED) { insertPart(entity, ``, ``); } */ @@ -723,7 +721,7 @@ namespace RichTextProcessor { } export function fixEmoji(text: string, entities?: MessageEntity[]) { - /* if(!emojiSupported) { + /* if(!IS_EMOJI_SUPPORTED) { return text; } */ // '$`\ufe0f' @@ -795,7 +793,7 @@ namespace RichTextProcessor { } export function wrapPlainText(text: string) { - if(emojiSupported) { + if(IS_EMOJI_SUPPORTED) { return text; } diff --git a/src/lib/serviceWorker/push.ts b/src/lib/serviceWorker/push.ts index bd77201c..4165ef94 100644 --- a/src/lib/serviceWorker/push.ts +++ b/src/lib/serviceWorker/push.ts @@ -11,7 +11,7 @@ import { Database } from "../../config/databases"; import DATABASE_STATE from "../../config/databases/state"; -import { isFirefox } from "../../helpers/userAgent"; +import { IS_FIREFOX } from "../../environment/userAgent"; import IDBStorage from "../idb"; import { log, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "./index.service"; @@ -256,7 +256,7 @@ export function closeAllNotifications() { } function userInvisibleIsSupported() { - return isFirefox; + return IS_FIREFOX; } function fireNotification(obj: PushNotificationObject, settings: PushStorage['push_settings'], lang: PushStorage['push_lang']) { diff --git a/src/lib/webp/webpWorkerController.ts b/src/lib/webp/webpWorkerController.ts index f1b4dd91..50c87aea 100644 --- a/src/lib/webp/webpWorkerController.ts +++ b/src/lib/webp/webpWorkerController.ts @@ -20,9 +20,8 @@ export type WebpConvertTask = { export class WebpWorkerController { private worker: Worker; private convertPromises: {[fileName: string]: CancellablePromise} = {}; - private isWebpSupportedCache: boolean; - init() { + private init() { this.worker = new WebpWorker(); this.worker.addEventListener('message', (e) => { const payload = (e.data as WebpConvertTask).payload; @@ -39,7 +38,7 @@ export class WebpWorkerController { }); } - postMessage(data: WebpConvertTask) { + public postMessage(data: WebpConvertTask) { if(this.init) { this.init(); this.init = null; @@ -48,15 +47,7 @@ export class WebpWorkerController { this.worker.postMessage(data); } - isWebpSupported() { - if(this.isWebpSupportedCache === undefined) { - this.isWebpSupportedCache = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp'); - } - - return this.isWebpSupportedCache; - } - - convert(fileName: string, bytes: Uint8Array) { + public convert(fileName: string, bytes: Uint8Array) { fileName = 'main-' + fileName; if(this.convertPromises.hasOwnProperty(fileName)) { diff --git a/src/pages/pageSignIn.ts b/src/pages/pageSignIn.ts index ef2bffff..8a831f03 100644 --- a/src/pages/pageSignIn.ts +++ b/src/pages/pageSignIn.ts @@ -13,9 +13,9 @@ import Page from "./page"; import InputField from "../components/inputField"; import CheckboxField from "../components/checkboxField"; import Button from "../components/button"; -import { isAndroid, isApple, isAppleMobile } from "../helpers/userAgent"; +import { IS_ANDROID, IS_APPLE, IS_APPLE_MOBILE } from "../environment/userAgent"; import fastSmoothScroll from "../helpers/fastSmoothScroll"; -import { isTouchSupported } from "../helpers/touchSupport"; +import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import App from "../config/app"; import I18n, { _i18n, i18n } from "../lib/langPack"; import lottieLoader from "../lib/lottieLoader"; @@ -41,6 +41,7 @@ import simulateEvent from "../helpers/dom/dispatchEvent"; import stateStorage from "../lib/stateStorage"; import rootScope from "../lib/rootScope"; import TelInputField from "../components/telInputField"; +import IS_EMOJI_SUPPORTED from "../environment/emojiSupport"; //import _countries from '../countries_pretty.json'; let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement; @@ -117,7 +118,7 @@ let onFirstMount = () => { const li = document.createElement('li'); let wrapped = RichTextProcessor.wrapEmojiText(emoji); - if(RichTextProcessor.emojiSupported) { + if(IS_EMOJI_SUPPORTED) { const spanEmoji = document.createElement('span'); spanEmoji.innerHTML = wrapped; li.append(spanEmoji); @@ -477,7 +478,7 @@ let onFirstMount = () => { })//.catch(tryAgain); }; - if(!isTouchSupported) { + if(!IS_TOUCH_SUPPORTED) { setTimeout(() => { telEl.focus(); }, 0); diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 9b79cb38..05dda5b1 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -2294,7 +2294,10 @@ $bubble-margin: .25rem; .c-ripple__circle { background-color: var(--message-out-primary-color); - opacity: .08; + + &:not(.hiding) { + opacity: .08; + } } }