Browse Source

Show .mov videos as document if it's not supported

master
morethanwords 3 years ago
parent
commit
ce715fa09f
  1. 4
      src/components/animationIntersector.ts
  2. 10
      src/components/appMediaPlaybackController.ts
  3. 17
      src/components/appMediaViewer.ts
  4. 4
      src/components/appNavigationController.ts
  5. 6
      src/components/appSearchSuper..ts
  6. 4
      src/components/audio.ts
  7. 4
      src/components/chat/autocompleteHelper.ts
  8. 22
      src/components/chat/bubbles.ts
  9. 8
      src/components/chat/contextMenu.ts
  10. 33
      src/components/chat/input.ts
  11. 14
      src/components/chat/markupTooltip.ts
  12. 4
      src/components/chat/replyKeyboard.ts
  13. 10
      src/components/chat/selection.ts
  14. 6
      src/components/chat/topbar.ts
  15. 4
      src/components/emoticonsDropdown/index.ts
  16. 9
      src/components/emoticonsDropdown/tabs/emoji.ts
  17. 16
      src/components/misc.ts
  18. 4
      src/components/poll.ts
  19. 13
      src/components/popups/newMedia.ts
  20. 4
      src/components/popups/pickUser.ts
  21. 6
      src/components/ripple.ts
  22. 4
      src/components/scrollable.ts
  23. 4
      src/components/sidebarLeft/index.ts
  24. 4
      src/components/sidebarLeft/tabs/contacts.ts
  25. 4
      src/components/sidebarLeft/tabs/generalSettings.ts
  26. 8
      src/components/sidebarRight/tabs/sharedMedia.ts
  27. 12
      src/components/swipeHandler.ts
  28. 8
      src/components/telInputField.ts
  29. 16
      src/components/wrappers.ts
  30. 3
      src/environment/ctx.ts
  31. 0
      src/environment/emojiSupport.ts
  32. 21
      src/environment/mediaMimeTypesSupport.ts
  33. 6
      src/environment/movSupport.ts
  34. 2
      src/environment/touchSupport.ts
  35. 24
      src/environment/userAgent.ts
  36. 3
      src/environment/webpSupport.ts
  37. 4
      src/helpers/dom/canFocus.ts
  38. 4
      src/helpers/dom/clickEvent.ts
  39. 6
      src/helpers/dom/fixSafariStickyInputFocusing.ts
  40. 4
      src/helpers/dom/handleScrollSideEvent.ts
  41. 8
      src/helpers/dom/isSendShortcutPressed.ts
  42. 4
      src/helpers/dom/placeCaretAtEnd.ts
  43. 10
      src/helpers/dropdownHover.ts
  44. 4
      src/helpers/files.ts
  45. 24
      src/helpers/userAgent.ts
  46. 26
      src/index.ts
  47. 8
      src/lib/appManagers/appDialogsManager.ts
  48. 54
      src/lib/appManagers/appDocsManager.ts
  49. 17
      src/lib/appManagers/appImManager.ts
  50. 6
      src/lib/appManagers/appNotificationsManager.ts
  51. 4
      src/lib/appManagers/appPhotosManager.ts
  52. 4
      src/lib/appManagers/appStateManager.ts
  53. 12
      src/lib/lottieLoader.ts
  54. 12
      src/lib/mediaPlayer.ts
  55. 2
      src/lib/mtproto/apiFileManager.ts
  56. 5
      src/lib/mtproto/apiManager.ts
  57. 4
      src/lib/mtproto/dcConfigurator.ts
  58. 2
      src/lib/mtproto/mtproto.worker.ts
  59. 3
      src/lib/mtproto/mtprotoworker.ts
  60. 6
      src/lib/mtproto/webPushApiManager.ts
  61. 6
      src/lib/opusDecodeController.ts
  62. 26
      src/lib/richtextprocessor.ts
  63. 4
      src/lib/serviceWorker/push.ts
  64. 15
      src/lib/webp/webpWorkerController.ts
  65. 9
      src/pages/pageSignIn.ts
  66. 5
      src/scss/partials/_chatBubble.scss

4
src/components/animationIntersector.ts

@ -6,7 +6,7 @@
import { RLottiePlayer } from "../lib/lottieLoader"; import { RLottiePlayer } from "../lib/lottieLoader";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import { isSafari } from "../helpers/userAgent"; import { IS_SAFARI } from "../environment/userAgent";
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
import isInDOM from "../helpers/dom/isInDOM"; import isInDOM from "../helpers/dom/isInDOM";
@ -93,7 +93,7 @@ export class AnimationIntersector {
const {el, animation} = player; const {el, animation} = player;
animation.remove(); animation.remove();
if(animation instanceof HTMLVideoElement && isSafari) { if(animation instanceof HTMLVideoElement && IS_SAFARI) {
setTimeout(() => { // TODO: очистка по очереди, а не все вместе с этим таймаутом setTimeout(() => { // TODO: очистка по очереди, а не все вместе с этим таймаутом
animation.src = ''; animation.src = '';
animation.load(); animation.load();

10
src/components/appMediaPlaybackController.ts

@ -8,7 +8,7 @@ import rootScope from "../lib/rootScope";
import appMessagesManager from "../lib/appManagers/appMessagesManager"; import appMessagesManager from "../lib/appManagers/appMessagesManager";
import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager"; import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager";
import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise"; 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 { MOUNT_CLASS_TO } from "../config/debug";
import appDownloadManager from "../lib/appManagers/appDownloadManager"; import appDownloadManager from "../lib/appManagers/appDownloadManager";
import simulateEvent from "../helpers/dom/dispatchEvent"; import simulateEvent from "../helpers/dom/dispatchEvent";
@ -16,7 +16,7 @@ import type { SearchSuperContext } from "./appSearchSuper.";
import { copy, deepEqual } from "../helpers/object"; import { copy, deepEqual } from "../helpers/object";
import { DocumentAttribute, Message, MessageMedia, PhotoSize } from "../layer"; import { DocumentAttribute, Message, MessageMedia, PhotoSize } from "../layer";
import appPhotosManager from "../lib/appManagers/appPhotosManager"; 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 appAvatarsManager from "../lib/appManagers/appAvatarsManager";
import appPeersManager from "../lib/appManagers/appPeersManager"; import appPeersManager from "../lib/appManagers/appPeersManager";
import I18n from "../lib/langPack"; import I18n from "../lib/langPack";
@ -34,7 +34,7 @@ type HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;
const SHOULD_USE_SAFARI_FIX = (() => { const SHOULD_USE_SAFARI_FIX = (() => {
try { try {
return isSafari && +navigator.userAgent.match(/ Version\/(\d+)/)[1] < 14; return IS_SAFARI && +navigator.userAgent.match(/ Version\/(\d+)/)[1] < 14;
} catch(err) { } catch(err) {
return false; return false;
} }
@ -296,8 +296,8 @@ class AppMediaPlaybackController {
} }
if(!artwork.length) { if(!artwork.length) {
if(isApple) { if(IS_APPLE) {
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
artwork.push({ artwork.push({
src: `assets/img/apple-touch-icon-precomposed.png`, src: `assets/img/apple-touch-icon-precomposed.png`,
sizes: '180x180', sizes: '180x180',

17
src/components/appMediaViewer.ts

@ -6,8 +6,8 @@
import { deferredPromise } from "../helpers/cancellablePromise"; import { deferredPromise } from "../helpers/cancellablePromise";
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import { isMobileSafari, isSafari } from "../helpers/userAgent"; import { IS_MOBILE_SAFARI, IS_SAFARI } from "../environment/userAgent";
import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager"; import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
import appImManager from "../lib/appManagers/appImManager"; import appImManager from "../lib/appManagers/appImManager";
import appMessagesManager from "../lib/appManagers/appMessagesManager"; import appMessagesManager from "../lib/appManagers/appMessagesManager";
@ -52,6 +52,7 @@ import PopupDeleteMessages from "./popups/deleteMessages";
import RangeSelector from "./rangeSelector"; import RangeSelector from "./rangeSelector";
import windowSize from "../helpers/windowSize"; import windowSize from "../helpers/windowSize";
import ListLoader, { ListLoaderOptions } from "../helpers/listLoader"; import ListLoader, { ListLoaderOptions } from "../helpers/listLoader";
import MEDIA_MIME_TYPES_SUPPORTED from "../environment/mediaMimeTypesSupport";
const ZOOM_STEP = 0.5; const ZOOM_STEP = 0.5;
const ZOOM_INITIAL_VALUE = 1; const ZOOM_INITIAL_VALUE = 1;
@ -355,7 +356,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
else this.onPrevClick(item); else this.onPrevClick(item);
}; };
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
const swipeHandler = new SwipeHandler({ const swipeHandler = new SwipeHandler({
element: this.wholeDiv, element: this.wholeDiv,
onSwipe: (xDiff, yDiff) => { onSwipe: (xDiff, yDiff) => {
@ -530,7 +531,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
if(target.tagName === 'A') return; if(target.tagName === 'A') return;
cancelEvent(e); cancelEvent(e);
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
if(this.highlightSwitchersTimeout) { if(this.highlightSwitchersTimeout) {
clearTimeout(this.highlightSwitchersTimeout); clearTimeout(this.highlightSwitchersTimeout);
} else { } else {
@ -1295,7 +1296,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
} else { } else {
window.addEventListener('keydown', this.onKeyDown); window.addEventListener('keydown', this.onKeyDown);
window.addEventListener('keyup', this.onKeyUp); window.addEventListener('keyup', this.onKeyUp);
if(!isTouchSupported) window.addEventListener('wheel', this.onWheel, {passive: false, capture: true}); if(!IS_TOUCH_SUPPORTED) window.addEventListener('wheel', this.onWheel, {passive: false, capture: true});
const mainColumns = this.pageEl.querySelector('#main-columns'); const mainColumns = this.pageEl.querySelector('#main-columns');
this.pageEl.insertBefore(this.wholeDiv, mainColumns); this.pageEl.insertBefore(this.wholeDiv, mainColumns);
void this.wholeDiv.offsetLeft; // reflow void this.wholeDiv.offsetLeft; // reflow
@ -1303,7 +1304,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
rootScope.isOverlayActive = true; rootScope.isOverlayActive = true;
animationIntersector.checkAnimations(true); animationIntersector.checkAnimations(true);
if(!isMobileSafari) { if(!IS_MOBILE_SAFARI) {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: 'media', type: 'media',
onPop: (canAnimate) => { onPop: (canAnimate) => {
@ -1401,7 +1402,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
} }
}, {once: true}); }, {once: true});
if(isSafari) { if(IS_SAFARI) {
// test stream // test stream
// video.controls = true; // video.controls = true;
video.autoplay = true; video.autoplay = true;
@ -1851,7 +1852,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
} }
public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) { public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) {
return media._ === 'photo' || (['photo', 'video', 'gif'].includes(media.type) || media.mime_type.indexOf('video/') === 0); return media._ === 'photo' || MEDIA_MIME_TYPES_SUPPORTED.has(media.mime_type);
} }
} }

4
src/components/appNavigationController.ts

@ -5,7 +5,7 @@
*/ */
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
import { isMobileSafari } from "../helpers/userAgent"; import { IS_MOBILE_SAFARI } from "../environment/userAgent";
import { logger } from "../lib/logger"; import { logger } from "../lib/logger";
import { doubleRaf } from "../helpers/schedulers"; import { doubleRaf } from "../helpers/schedulers";
import blurActiveElement from "../helpers/dom/blurActiveElement"; import blurActiveElement from "../helpers/dom/blurActiveElement";
@ -67,7 +67,7 @@ export class AppNavigationController {
} }
}, {capture: true, passive: false}); }, {capture: true, passive: false});
if(isMobileSafari) { if(IS_MOBILE_SAFARI) {
const options = {passive: true}; const options = {passive: true};
window.addEventListener('touchstart', (e) => { window.addEventListener('touchstart', (e) => {
if(e.touches.length > 1) return; if(e.touches.length > 1) return;

6
src/components/appSearchSuper..ts

@ -38,7 +38,7 @@ import mediaSizes from "../helpers/mediaSizes";
import appImManager from "../lib/appManagers/appImManager"; import appImManager from "../lib/appManagers/appImManager";
import positionElementByIndex from "../helpers/dom/positionElementByIndex"; import positionElementByIndex from "../helpers/dom/positionElementByIndex";
import cleanSearchText from "../helpers/cleanSearchText"; import cleanSearchText from "../helpers/cleanSearchText";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import handleTabSwipe from "../helpers/dom/handleTabSwipe"; import handleTabSwipe from "../helpers/dom/handleTabSwipe";
import windowSize from "../helpers/windowSize"; import windowSize from "../helpers/windowSize";
import { formatPhoneNumber } from "../helpers/formatPhoneNumber"; import { formatPhoneNumber } from "../helpers/formatPhoneNumber";
@ -133,7 +133,7 @@ class SearchContextMenu {
}); });
}; };
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
} else { } else {
attachContextMenuListener(attachTo, onContextMenu as any); attachContextMenuListener(attachTo, onContextMenu as any);
@ -326,7 +326,7 @@ export default class AppSearchSuper {
this.tabsContainer = document.createElement('div'); this.tabsContainer = document.createElement('div');
this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container'); this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container');
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
handleTabSwipe(this.tabsContainer, (next) => { handleTabSwipe(this.tabsContainer, (next) => {
const prevId = this.selectTab.prevId(); const prevId = this.selectTab.prevId();
this.selectTab(next ? prevId + 1 : prevId - 1); this.selectTab(next ? prevId + 1 : prevId - 1);

4
src/components/audio.ts

@ -12,7 +12,7 @@ import { MediaProgressLine } from "../lib/mediaPlayer";
import appMediaPlaybackController, { MediaItem } from "./appMediaPlaybackController"; import appMediaPlaybackController, { MediaItem } from "./appMediaPlaybackController";
import { DocumentAttribute } from "../layer"; import { DocumentAttribute } from "../layer";
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { isSafari } from "../helpers/userAgent"; import { IS_SAFARI } from "../environment/userAgent";
import appMessagesManager from "../lib/appManagers/appMessagesManager"; import appMessagesManager from "../lib/appManagers/appMessagesManager";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import './middleEllipsis'; import './middleEllipsis';
@ -558,7 +558,7 @@ export default class AudioElement extends HTMLElement {
appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid); appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid);
appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio
if(isSafari) { if(IS_SAFARI) {
this.audio.autoplay = true; this.audio.autoplay = true;
} }

4
src/components/chat/autocompleteHelper.ts

@ -7,7 +7,7 @@
import attachListNavigation from "../../helpers/dom/attachListNavigation"; import attachListNavigation from "../../helpers/dom/attachListNavigation";
import EventListenerBase from "../../helpers/eventListenerBase"; import EventListenerBase from "../../helpers/eventListenerBase";
import { safeAssign } from "../../helpers/object"; import { safeAssign } from "../../helpers/object";
import { isMobile } from "../../helpers/userAgent"; import { IS_MOBILE } from "../../environment/userAgent";
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
import appNavigationController, { NavigationItem } from "../appNavigationController"; import appNavigationController, { NavigationItem } from "../appNavigationController";
import SetTransition from "../singleTransition"; import SetTransition from "../singleTransition";
@ -68,7 +68,7 @@ export default class AutocompleteHelper extends EventListenerBase<{
this.detach = detach; this.detach = detach;
this.resetTarget = resetTarget; this.resetTarget = resetTarget;
if(!isMobile && !this.navigationItem) { if(!IS_MOBILE && !this.navigationItem) {
this.navigationItem = { this.navigationItem = {
type: 'autocomplete-helper', type: 'autocomplete-helper',
onPop: () => { onPop: () => {

22
src/components/chat/bubbles.ts

@ -18,7 +18,7 @@ import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIds
import type Chat from "./chat"; import type Chat from "./chat";
import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager"; import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
import { getObjectKeysAndSort } from "../../helpers/object"; import { getObjectKeysAndSort } from "../../helpers/object";
import { isTouchSupported } from "../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import { logger } from "../../lib/logger"; import { logger } from "../../lib/logger";
import rootScope, { BroadcastEvents } from "../../lib/rootScope"; import rootScope, { BroadcastEvents } from "../../lib/rootScope";
import AppMediaViewer from "../appMediaViewer"; import AppMediaViewer from "../appMediaViewer";
@ -32,7 +32,7 @@ import StickyIntersector from "../stickyIntersector";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
import RichTextProcessor from "../../lib/richtextprocessor"; import RichTextProcessor from "../../lib/richtextprocessor";
import mediaSizes from "../../helpers/mediaSizes"; 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 I18n, { i18n, langPack } from "../../lib/langPack";
import AvatarElement from "../avatar"; import AvatarElement from "../avatar";
import { ripple } from "../ripple"; import { ripple } from "../ripple";
@ -452,7 +452,7 @@ export default class ChatBubbles {
}); });
} }
if(!isMobile) { if(!IS_MOBILE) {
this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => { this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {
if(this.chat.selection.isSelecting || if(this.chat.selection.isSelecting ||
!this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId)) { !this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId)) {
@ -864,7 +864,7 @@ export default class ChatBubbles {
return; return;
} }
if(!isTouchSupported && findUpClassName(target, 'time')) { if(!IS_TOUCH_SUPPORTED && findUpClassName(target, 'time')) {
this.chat.selection.toggleByElement(bubble); this.chat.selection.toggleByElement(bubble);
return; return;
} }
@ -878,7 +878,7 @@ export default class ChatBubbles {
cancelEvent(e); cancelEvent(e);
//console.log('bubble click', 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; this.chat.selection.selectedText = undefined;
return; return;
} }
@ -1264,7 +1264,7 @@ export default class ChatBubbles {
if(this.isHeavyAnimationInProgress && this.scrolledDown) return; if(this.isHeavyAnimationInProgress && this.scrolledDown) return;
//lottieLoader.checkAnimations(false, 'chat'); //lottieLoader.checkAnimations(false, 'chat');
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
if(this.isScrollingTimeout) { if(this.isScrollingTimeout) {
clearTimeout(this.isScrollingTimeout); clearTimeout(this.isScrollingTimeout);
} else if(!this.chatInner.classList.contains('is-scrolling')) { } else if(!this.chatInner.classList.contains('is-scrolling')) {
@ -1313,7 +1313,7 @@ export default class ChatBubbles {
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false); this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
//this.scrollable.attachSentinels(undefined, 300); //this.scrollable.attachSentinels(undefined, 300);
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
this.scrollable.container.addEventListener('touchmove', () => { this.scrollable.container.addEventListener('touchmove', () => {
if(this.isScrollingTimeout) { if(this.isScrollingTimeout) {
clearTimeout(this.isScrollingTimeout); clearTimeout(this.isScrollingTimeout);
@ -2530,7 +2530,7 @@ export default class ChatBubbles {
break; 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'); if(withTail) bubble.classList.add('with-media-tail');
wrapPhoto({ wrapPhoto({
photo, photo,
@ -2759,7 +2759,7 @@ export default class ChatBubbles {
noAutoDownload: this.chat.noAutoDownloadMedia, noAutoDownload: this.chat.noAutoDownloadMedia,
}); });
} else { } 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'); if(withTail) bubble.classList.add('with-media-tail');
wrapVideo({ wrapVideo({
doc, doc,
@ -3198,7 +3198,7 @@ export default class ChatBubbles {
//this.scrollable.scrollTop = this.scrollable.scrollHeight; //this.scrollable.scrollTop = this.scrollable.scrollHeight;
//isTouchSupported && isApple && (this.scrollable.container.style.overflow = ''); //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); reflowScrollableElement(this.scrollable.container);
} }
@ -3376,7 +3376,7 @@ export default class ChatBubbles {
// ! в хроме, каким-то образом из-за zoom-fade класса начинает прыгать скролл при подгрузке сообщений вверх, // ! в хроме, каким-то образом из-за zoom-fade класса начинает прыгать скролл при подгрузке сообщений вверх,
// ! т.е. скролл не ставится, так же, как в сафари при translateZ на блок выше scrollable // ! т.е. скролл не ставится, так же, как в сафари при translateZ на блок выше scrollable
if(!isSafari) { if(!IS_SAFARI) {
this.needReflowScroll = true; this.needReflowScroll = true;
} }
}); });

8
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 { AppDocsManager, MyDocument } from "../../lib/appManagers/appDocsManager";
import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager"; import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager";
import type Chat from "./chat"; import type Chat from "./chat";
import { isTouchSupported } from "../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc";
import PopupDeleteMessages from "../popups/deleteMessages"; import PopupDeleteMessages from "../popups/deleteMessages";
@ -117,7 +117,7 @@ export default class ChatContextMenu {
if(chat.selection.isSelecting && !button.withSelection) { if(chat.selection.isSelecting && !button.withSelection) {
good = false; good = false;
} else { } else {
good = contentWrapper || isTouchSupported || true ? good = contentWrapper || IS_TOUCH_SUPPORTED || true ?
button.verify() : button.verify() :
button.notDirect && button.verify() && button.notDirect(); 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) => { attachClickEvent(attachTo, (e) => {
if(chat.selection.isSelecting) { if(chat.selection.isSelecting) {
return; return;
@ -284,7 +284,7 @@ export default class ChatContextMenu {
const doc: MyDocument = this.message.media?.document; const doc: MyDocument = this.message.media?.document;
if(!doc) return false; 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); const isGoodType = !doc.type || !(['gif', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);
if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio'); if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio');
return isGoodType && hasTarget; return isGoodType && hasTarget;

33
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 { AppMessagesIdsManager } from '../../lib/appManagers/appMessagesIdsManager';
import type Chat from './chat'; import type Chat from './chat';
import Recorder from '../../../public/recorder.min'; 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 apiManager from "../../lib/mtproto/mtprotoworker";
//import Recorder from '../opus-recorder/dist/recorder.min'; //import Recorder from '../opus-recorder/dist/recorder.min';
import opusDecodeController from "../../lib/opusDecodeController"; import opusDecodeController from "../../lib/opusDecodeController";
@ -44,7 +44,7 @@ import rootScope from '../../lib/rootScope';
import PopupPinMessage from '../popups/unpinMessage'; import PopupPinMessage from '../popups/unpinMessage';
import { tsNow } from '../../helpers/date'; import { tsNow } from '../../helpers/date';
import appNavigationController, { NavigationItem } from '../appNavigationController'; 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 I18n, { i18n, join, LangPackKey } from '../../lib/langPack';
import { generateTail } from './bubbles'; import { generateTail } from './bubbles';
import findUpClassName from '../../helpers/dom/findUpClassName'; 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 fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing';
import { copy } from '../../helpers/object'; import { copy } from '../../helpers/object';
import PopupPeer from '../popups/peer'; import PopupPeer from '../popups/peer';
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
const RECORD_MIN_TIME = 500; const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.'; 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); this.appImManager.openScheduled(this.chat.peerId);
}, {listenerSetter: this.listenerSetter}); }, {listenerSetter: this.listenerSetter});
this.listenerSetter.add(rootScope)('scheduled_new', (e) => { this.listenerSetter.add(rootScope)('scheduled_new', ({peerId}) => {
const peerId = e.peerId;
if(this.chat.peerId !== peerId) { if(this.chat.peerId !== peerId) {
return; return;
} }
@ -341,9 +340,7 @@ export default class ChatInput {
this.btnScheduled.classList.remove('hide'); this.btnScheduled.classList.remove('hide');
}); });
this.listenerSetter.add(rootScope)('scheduled_delete', (e) => { this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId}) => {
const peerId = e.peerId;
if(this.chat.peerId !== peerId) { if(this.chat.peerId !== peerId) {
return; return;
} }
@ -370,7 +367,8 @@ export default class ChatInput {
text: 'Chat.Input.Attach.PhotoOrVideo', text: 'Chat.Input.Attach.PhotoOrVideo',
onClick: () => { onClick: () => {
this.fileInput.value = ''; 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.willAttachType = 'media';
this.fileInput.click(); this.fileInput.click();
}, },
@ -391,7 +389,7 @@ export default class ChatInput {
onClick: () => { onClick: () => {
new PopupCreatePoll(this.chat).show(); 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); 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) => { this.listenerSetter.add(rootScope)('draft_updated', ({peerId, threadId, draft, force}) => {
const {peerId, threadId, draft, force} = e;
if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return; if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return;
this.setDraft(draft, true, force); this.setDraft(draft, true, force);
}); });
@ -671,12 +668,12 @@ export default class ChatInput {
}; };
private onEmoticonsOpen = () => { private onEmoticonsOpen = () => {
const toggleClass = isTouchSupported ? 'flip-icon' : 'active'; const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';
this.btnToggleEmoticons.classList.toggle(toggleClass, true); this.btnToggleEmoticons.classList.toggle(toggleClass, true);
}; };
private onEmoticonsClose = () => { private onEmoticonsClose = () => {
const toggleClass = isTouchSupported ? 'flip-icon' : 'active'; const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';
this.btnToggleEmoticons.classList.toggle(toggleClass, false); this.btnToggleEmoticons.classList.toggle(toggleClass, false);
}; };
@ -929,7 +926,7 @@ export default class ChatInput {
} }
}); });
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
attachClickEvent(this.messageInput, (e) => { attachClickEvent(this.messageInput, (e) => {
this.appImManager.selectTab(1); // * set chat tab for album orientation this.appImManager.selectTab(1); // * set chat tab for album orientation
//this.saveScroll(); //this.saveScroll();
@ -1619,7 +1616,7 @@ export default class ChatInput {
}; };
public clearInput(canSetDraft = true, fireEvent = true, clearValue = '') { 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'); const i = document.createElement('input');
document.body.append(i); document.body.append(i);
fixSafariStickyInput(i); fixSafariStickyInput(i);
@ -1630,7 +1627,7 @@ export default class ChatInput {
this.messageInputField.setValueSilently(clearValue); this.messageInputField.setValueSilently(clearValue);
} }
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
//this.messageInput.innerText = ''; //this.messageInput.innerText = '';
} else { } else {
//this.attachMessageInputField(); //this.attachMessageInputField();
@ -1978,7 +1975,7 @@ export default class ChatInput {
scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200); scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200);
} */ } */
if(!isMobile) { if(!IS_MOBILE) {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: 'input-helper', type: 'input-helper',
onPop: () => { onPop: () => {

14
src/components/chat/markupTooltip.ts

@ -8,8 +8,8 @@ import type { AppImManager } from "../../lib/appManagers/appImManager";
import RichTextProcessor from "../../lib/richtextprocessor"; import RichTextProcessor from "../../lib/richtextprocessor";
import ButtonIcon from "../buttonIcon"; import ButtonIcon from "../buttonIcon";
import { clamp } from "../../helpers/number"; import { clamp } from "../../helpers/number";
import { isTouchSupported } from "../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import { isApple, isMobile } from "../../helpers/userAgent"; import { IS_APPLE, IS_MOBILE } from "../../environment/userAgent";
import appNavigationController from "../appNavigationController"; import appNavigationController from "../appNavigationController";
import { _i18n } from "../../lib/langPack"; import { _i18n } from "../../lib/langPack";
import { cancelEvent } from "../../helpers/dom/cancelEvent"; import { cancelEvent } from "../../helpers/dom/cancelEvent";
@ -313,7 +313,7 @@ export default class MarkupTooltip {
this.container.classList.add('is-visible'); this.container.classList.add('is-visible');
if(!isMobile) { if(!IS_MOBILE) {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: 'markup', type: 'markup',
onPop: () => { onPop: () => {
@ -337,7 +337,7 @@ export default class MarkupTooltip {
//this.log('onMouseUpSingle'); //this.log('onMouseUpSingle');
this.waitingForMouseUp = false; this.waitingForMouseUp = false;
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
cancelEvent(e); cancelEvent(e);
if(this.mouseUpCounter++ === 0) { if(this.mouseUpCounter++ === 0) {
this.resetSelection(this.savedRange); this.resetSelection(this.savedRange);
@ -362,7 +362,7 @@ export default class MarkupTooltip {
} }
public cancelClosening() { public cancelClosening() {
if(isTouchSupported && !isApple) { if(IS_TOUCH_SUPPORTED && !IS_APPLE) {
document.removeEventListener('mouseup', this.onMouseUpSingle); document.removeEventListener('mouseup', this.onMouseUpSingle);
document.addEventListener('mouseup', (e) => { document.addEventListener('mouseup', (e) => {
cancelEvent(e); cancelEvent(e);
@ -394,8 +394,8 @@ export default class MarkupTooltip {
return; return;
} }
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
if(isApple) { if(IS_APPLE) {
this.show(); this.show();
this.setTooltipPosition(); // * because can skip this in .show(); this.setTooltipPosition(); // * because can skip this in .show();
} else { } else {

4
src/components/chat/replyKeyboard.ts

@ -13,7 +13,7 @@ import rootScope from "../../lib/rootScope";
import { safeAssign } from "../../helpers/object"; import { safeAssign } from "../../helpers/object";
import ListenerSetter, { Listener } from "../../helpers/listenerSetter"; import ListenerSetter, { Listener } from "../../helpers/listenerSetter";
import findUpClassName from "../../helpers/dom/findUpClassName"; 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 findUpAsChild from "../../helpers/dom/findUpAsChild";
import { cancelEvent } from "../../helpers/dom/cancelEvent"; import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck"; import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
@ -64,7 +64,7 @@ export default class ReplyKeyboard extends DropdownHover {
this.listenerSetter.add(this)('open', () => { this.listenerSetter.add(this)('open', () => {
this.render(); 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.touchListener = this.listenerSetter.add(document.body)('touchstart', this.onBodyTouchStart, {passive: false, capture: true}) as any as Listener;
this.listenerSetter.add(this)('close', () => { this.listenerSetter.add(this)('close', () => {
this.listenerSetter.remove(this.touchListener); this.listenerSetter.remove(this.touchListener);

10
src/components/chat/selection.ts

@ -8,7 +8,7 @@ import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManage
import type ChatBubbles from "./bubbles"; import type ChatBubbles from "./bubbles";
import type ChatInput from "./input"; import type ChatInput from "./input";
import type Chat from "./chat"; import type Chat from "./chat";
import { isTouchSupported } from "../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import Button from "../button"; import Button from "../button";
import ButtonIcon from "../buttonIcon"; import ButtonIcon from "../buttonIcon";
import CheckboxField from "../checkboxField"; import CheckboxField from "../checkboxField";
@ -19,7 +19,7 @@ import SetTransition from "../singleTransition";
import ListenerSetter from "../../helpers/listenerSetter"; import ListenerSetter from "../../helpers/listenerSetter";
import PopupSendNow from "../popups/sendNow"; import PopupSendNow from "../popups/sendNow";
import appNavigationController, { NavigationItem } from "../appNavigationController"; 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 I18n, { i18n, _i18n } from "../../lib/langPack";
import findUpClassName from "../../helpers/dom/findUpClassName"; import findUpClassName from "../../helpers/dom/findUpClassName";
import blurActiveElement from "../../helpers/dom/blurActiveElement"; import blurActiveElement from "../../helpers/dom/blurActiveElement";
@ -85,7 +85,7 @@ class AppSelection {
this.navigationType = 'multiselect-' + randomLong() as any; this.navigationType = 'multiselect-' + randomLong() as any;
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
this.listenerSetter.add(this.listenElement)('touchend', () => { this.listenerSetter.add(this.listenElement)('touchend', () => {
if(!this.isSelecting) return; if(!this.isSelecting) return;
this.selectedText = getSelectedText(); this.selectedText = getSelectedText();
@ -367,7 +367,7 @@ class AppSelection {
} }
} */ } */
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.listenElement.classList.toggle('no-select', this.isSelecting); this.listenElement.classList.toggle('no-select', this.isSelecting);
if(wasSelecting) { if(wasSelecting) {
@ -390,7 +390,7 @@ class AppSelection {
const forwards = !!size || forceSelection; const forwards = !!size || forceSelection;
this.onToggleSelection && this.onToggleSelection(forwards); this.onToggleSelection && this.onToggleSelection(forwards);
if(!isMobileSafari) { if(!IS_MOBILE_SAFARI) {
if(forwards) { if(forwards) {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: this.navigationType, type: this.navigationType,

6
src/components/chat/topbar.ts

@ -14,7 +14,7 @@ import type { AppUsersManager } from "../../lib/appManagers/appUsersManager";
import type Chat from "./chat"; import type Chat from "./chat";
import { RIGHT_COLUMN_ACTIVE_CLASSNAME } from "../sidebarRight"; import { RIGHT_COLUMN_ACTIVE_CLASSNAME } from "../sidebarRight";
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes"; import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
import { isSafari } from "../../helpers/userAgent"; import { IS_SAFARI } from "../../environment/userAgent";
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
import AvatarElement from "../avatar"; import AvatarElement from "../avatar";
import Button from "../button"; import Button from "../button";
@ -685,7 +685,7 @@ export default class ChatTopbar {
//return; //return;
if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF); if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF);
if(isSafari && resize) { if(IS_SAFARI && resize) {
this.chatUtils.classList.add('hide'); this.chatUtils.classList.add('hide');
} }
@ -695,7 +695,7 @@ export default class ChatTopbar {
//mutationRAF = window.requestAnimationFrame(() => { //mutationRAF = window.requestAnimationFrame(() => {
//setTimeout(() => { //setTimeout(() => {
if(isSafari && resize) { if(IS_SAFARI && resize) {
this.chatUtils.classList.remove('hide'); this.chatUtils.classList.remove('hide');
} }
/* this.chatInfo.style.removeProperty('--utils-width'); /* this.chatInfo.style.removeProperty('--utils-width');

4
src/components/emoticonsDropdown/index.ts

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * 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 appImManager from "../../lib/appManagers/appImManager";
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
@ -61,7 +61,7 @@ export class EmoticonsDropdown extends DropdownHover {
}); });
this.addEventListener('open', async() => { this.addEventListener('open', async() => {
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
//appImManager.chat.input.saveScroll(); //appImManager.chat.input.saveScroll();
if(blurActiveElement()) { if(blurActiveElement()) {
await pause(100); await pause(100);

9
src/components/emoticonsDropdown/tabs/emoji.ts

@ -9,7 +9,7 @@ import { cancelEvent } from "../../../helpers/dom/cancelEvent";
import findUpClassName from "../../../helpers/dom/findUpClassName"; import findUpClassName from "../../../helpers/dom/findUpClassName";
import { fastRaf } from "../../../helpers/schedulers"; import { fastRaf } from "../../../helpers/schedulers";
import { pause } from "../../../helpers/schedulers/pause"; 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 appEmojiManager from "../../../lib/appManagers/appEmojiManager";
import appImManager from "../../../lib/appManagers/appImManager"; import appImManager from "../../../lib/appManagers/appImManager";
import Config from "../../../lib/config"; import Config from "../../../lib/config";
@ -20,6 +20,7 @@ import { emojiFromCodePoints } from "../../../vendor/emoji";
import { putPreloader } from "../../misc"; import { putPreloader } from "../../misc";
import Scrollable from "../../scrollable"; import Scrollable from "../../scrollable";
import StickyIntersector from "../../stickyIntersector"; import StickyIntersector from "../../stickyIntersector";
import IS_EMOJI_SUPPORTED from "../../../environment/emojiSupport";
const loadedURLs: Set<string> = new Set(); const loadedURLs: Set<string> = new Set();
export function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) { 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'); spanEmoji.classList.add('super-emoji');
let kek: string; let kek: string;
if(unify && !RichTextProcessor.emojiSupported) { if(unify && !IS_EMOJI_SUPPORTED) {
kek = RichTextProcessor.wrapSingleEmoji(emoji); kek = RichTextProcessor.wrapSingleEmoji(emoji);
} else { } else {
emoji = RichTextProcessor.fixEmoji(emoji); emoji = RichTextProcessor.fixEmoji(emoji);
@ -53,7 +54,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal
spanEmoji.append(first); spanEmoji.append(first);
} }
if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) { if(spanEmoji.firstElementChild && !IS_EMOJI_SUPPORTED) {
const image = spanEmoji.firstElementChild as HTMLImageElement; const image = spanEmoji.firstElementChild as HTMLImageElement;
const url = image.src; const url = image.src;
@ -295,7 +296,7 @@ export default class EmojiTab implements EmoticonsTab {
const html = RichTextProcessor.wrapEmojiText(emoji, true); const html = RichTextProcessor.wrapEmojiText(emoji, true);
let inserted = false; let inserted = false;
if(window.getSelection) { if(window.getSelection) {
const savedRange = isTouchSupported ? undefined : emoticonsDropdown.getSavedRange(); const savedRange = IS_TOUCH_SUPPORTED ? undefined : emoticonsDropdown.getSavedRange();
let sel = window.getSelection(); let sel = window.getSelection();
if(savedRange) { if(savedRange) {
sel.removeAllRanges(); sel.removeAllRanges();

16
src/components/misc.ts

@ -9,8 +9,8 @@ import { cancelEvent } from "../helpers/dom/cancelEvent";
import { CLICK_EVENT_NAME } from "../helpers/dom/clickEvent"; import { CLICK_EVENT_NAME } from "../helpers/dom/clickEvent";
import ListenerSetter from "../helpers/listenerSetter"; import ListenerSetter from "../helpers/listenerSetter";
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import { isApple, isMobileSafari } from "../helpers/userAgent"; import { IS_APPLE, IS_MOBILE_SAFARI } from "../environment/userAgent";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import appNavigationController from "./appNavigationController"; import appNavigationController from "./appNavigationController";
@ -101,7 +101,7 @@ export const closeBtnMenu = () => {
openedMenuOnClose = null; openedMenuOnClose = null;
} }
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
window.removeEventListener('mousemove', onMouseMove); window.removeEventListener('mousemove', onMouseMove);
//window.removeEventListener('keydown', onKeyDown, {capture: true}); //window.removeEventListener('keydown', onKeyDown, {capture: true});
window.removeEventListener('contextmenu', onClick); window.removeEventListener('contextmenu', onClick);
@ -109,7 +109,7 @@ export const closeBtnMenu = () => {
document.removeEventListener(CLICK_EVENT_NAME, onClick); document.removeEventListener(CLICK_EVENT_NAME, onClick);
if(!isMobileSafari) { if(!IS_MOBILE_SAFARI) {
appNavigationController.removeByType('menu'); appNavigationController.removeByType('menu');
} }
}; };
@ -131,7 +131,7 @@ let openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null, menuOv
export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) { export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
closeBtnMenu(); closeBtnMenu();
if(!isMobileSafari) { if(!IS_MOBILE_SAFARI) {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: 'menu', type: 'menu',
onPop: (canAnimate) => { onPop: (canAnimate) => {
@ -161,7 +161,7 @@ export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
openedMenuOnClose = onClose; openedMenuOnClose = onClose;
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
window.addEventListener('mousemove', onMouseMove); window.addEventListener('mousemove', onMouseMove);
//window.addEventListener('keydown', onKeyDown, {capture: true}); //window.addEventListener('keydown', onKeyDown, {capture: true});
window.addEventListener('contextmenu', onClick, {once: 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 add = listenerSetter ? listenerSetter.add(element) : element.addEventListener.bind(element);
const remove = listenerSetter ? listenerSetter.removeManual.bind(listenerSetter, element) : element.removeEventListener.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; let timeout: number;
const options: EventListenerOptions = {capture: true}; const options: EventListenerOptions = {capture: true};
@ -343,7 +343,7 @@ export function attachContextMenuListener(element: HTMLElement, callback: (e: To
}, {passive: false, capture: true}); }, {passive: false, capture: true});
} */ } */
} else { } else {
add('contextmenu', isTouchSupported ? (e: any) => { add('contextmenu', IS_TOUCH_SUPPORTED ? (e: any) => {
callback(e); callback(e);
if(openedMenu) { if(openedMenu) {

4
src/components/poll.ts

@ -5,7 +5,7 @@
*/ */
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import appImManager from "../lib/appManagers/appImManager"; import appImManager from "../lib/appManagers/appImManager";
import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsManager"; import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsManager";
import serverTimeManager from "../lib/mtproto/serverTimeManager"; import serverTimeManager from "../lib/mtproto/serverTimeManager";
@ -161,7 +161,7 @@ const setQuizHint = (solution: string, solution_entities: any[], onHide: () => v
prevQuizHintOnHide = onHide; prevQuizHintOnHide = onHide;
prevQuizHintTimeout = window.setTimeout(() => { prevQuizHintTimeout = window.setTimeout(() => {
hideQuizHint(element, onHide, prevQuizHintTimeout); hideQuizHint(element, onHide, prevQuizHintTimeout);
}, isTouchSupported ? 5000 : 7000); }, IS_TOUCH_SUPPORTED ? 5000 : 7000);
}; };
export default class PollElement extends HTMLElement { export default class PollElement extends HTMLElement {

13
src/components/popups/newMedia.ts

@ -22,6 +22,7 @@ import rootScope from "../../lib/rootScope";
import RichTextProcessor from "../../lib/richtextprocessor"; import RichTextProcessor from "../../lib/richtextprocessor";
import { MediaSize } from "../../helpers/mediaSizes"; import { MediaSize } from "../../helpers/mediaSizes";
import { attachClickEvent } from "../../helpers/dom/clickEvent"; import { attachClickEvent } from "../../helpers/dom/clickEvent";
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
type SendFileParams = Partial<{ type SendFileParams = Partial<{
file: File, file: File,
@ -368,13 +369,11 @@ export default class PopupNewMedia extends PopupElement {
willAttach.type = 'document'; willAttach.type = 'document';
} */ } */
files = files.filter(file => { if(willAttach.type === 'media') {
if(willAttach.type === 'media') { files = files.filter(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type));
return ['image/', 'video/'].find(s => file.type.indexOf(s) === 0); } else {
} else { files = files.slice();
return true; }
}
});
Promise.all(files.map(this.attachFile)).then(results => { Promise.all(files.map(this.attachFile)).then(results => {
this.container.classList.remove('is-media', 'is-document', 'is-album'); this.container.classList.remove('is-media', 'is-document', 'is-album');

4
src/components/popups/pickUser.ts

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * 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 AppSelectPeers from "../appSelectPeers";
import PopupElement from "."; import PopupElement from ".";
import { LangPackKey, _i18n } from "../../lib/langPack"; import { LangPackKey, _i18n } from "../../lib/langPack";
@ -50,7 +50,7 @@ export default class PopupPickUser extends PopupElement {
this.show(); this.show();
this.selector.checkForTriggers(); // ! due to zero height before mounting this.selector.checkForTriggers(); // ! due to zero height before mounting
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.selector.input.focus(); this.selector.input.focus();
} }
}, },

6
src/components/ripple.ts

@ -6,7 +6,7 @@
import findUpClassName from "../helpers/dom/findUpClassName"; import findUpClassName from "../helpers/dom/findUpClassName";
import sequentialDom from "../helpers/sequentialDom"; import sequentialDom from "../helpers/sequentialDom";
import {isTouchSupported} from "../helpers/touchSupport"; import {IS_TOUCH_SUPPORTED} from "../environment/touchSupport";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
let rippleClickId = 0; let rippleClickId = 0;
@ -63,7 +63,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
setTimeout(cb, duration / 2); setTimeout(cb, duration / 2);
} }
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
window.removeEventListener('contextmenu', handler); window.removeEventListener('contextmenu', handler);
} }
@ -136,7 +136,7 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
// TODO: rename this variable // TODO: rename this variable
let touchStartFired = false; let touchStartFired = false;
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
let touchEnd = () => { let touchEnd = () => {
handler && handler(); handler && handler();
}; };

4
src/components/scrollable.ts

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * 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 { logger, LogTypes } from "../lib/logger";
import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll"; import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll";
import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck"; import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck";
@ -248,7 +248,7 @@ export class ScrollableX extends ScrollableBase {
this.container.classList.add('scrollable-x'); this.container.classList.add('scrollable-x');
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
const scrollHorizontally = (e: any) => { const scrollHorizontally = (e: any) => {
if(!e.deltaX && this.container.scrollWidth > this.container.clientWidth) { if(!e.deltaX && this.container.scrollWidth > this.container.clientWidth) {
this.container.scrollLeft += e.deltaY / 4; this.container.scrollLeft += e.deltaY / 4;

4
src/components/sidebarLeft/index.ts

@ -28,7 +28,7 @@ import AppAddMembersTab from "./tabs/addMembers";
import { i18n_, LangPackKey } from "../../lib/langPack"; import { i18n_, LangPackKey } from "../../lib/langPack";
import { ButtonMenuItemOptions } from "../buttonMenu"; import { ButtonMenuItemOptions } from "../buttonMenu";
import CheckboxField from "../checkboxField"; import CheckboxField from "../checkboxField";
import { isMobileSafari } from "../../helpers/userAgent"; import { IS_MOBILE_SAFARI } from "../../environment/userAgent";
import appNavigationController from "../appNavigationController"; import appNavigationController from "../appNavigationController";
import findUpClassName from "../../helpers/dom/findUpClassName"; import findUpClassName from "../../helpers/dom/findUpClassName";
import findUpTag from "../../helpers/dom/findUpTag"; import findUpTag from "../../helpers/dom/findUpTag";
@ -531,7 +531,7 @@ export class AppSidebarLeft extends SidebarSlider {
this.newBtnMenu.classList.add('is-hidden'); this.newBtnMenu.classList.add('is-hidden');
this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true); 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({ appNavigationController.pushItem({
onPop: () => { onPop: () => {
close(); close();

4
src/components/sidebarLeft/tabs/contacts.ts

@ -8,7 +8,7 @@ import { SliderSuperTab } from "../../slider";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager"; import appUsersManager from "../../../lib/appManagers/appUsersManager";
import InputSearch from "../../inputSearch"; import InputSearch from "../../inputSearch";
import { isMobile } from "../../../helpers/userAgent"; import { IS_MOBILE } from "../../../environment/userAgent";
import { canFocus } from "../../../helpers/dom/canFocus"; import { canFocus } from "../../../helpers/dom/canFocus";
import windowSize from "../../../helpers/windowSize"; import windowSize from "../../../helpers/windowSize";
import ButtonCorner from "../../buttonCorner"; import ButtonCorner from "../../buttonCorner";
@ -75,7 +75,7 @@ export default class AppContactsTab extends SliderSuperTab {
} }
protected onOpenAfterTimeout() { protected onOpenAfterTimeout() {
if(isMobile || !canFocus(true)) return; if(IS_MOBILE || !canFocus(true)) return;
this.inputSearch.input.focus(); this.inputSearch.input.focus();
} }

4
src/components/sidebarLeft/tabs/generalSettings.ts

@ -12,7 +12,7 @@ import CheckboxField from "../../checkboxField";
import RadioField from "../../radioField"; import RadioField from "../../radioField";
import appStateManager from "../../../lib/appManagers/appStateManager"; import appStateManager from "../../../lib/appManagers/appStateManager";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import { isApple } from "../../../helpers/userAgent"; import { IS_APPLE } from "../../../environment/userAgent";
import Row from "../../row"; import Row from "../../row";
import AppBackgroundTab from "./background"; import AppBackgroundTab from "./background";
import { LangPackKey, _i18n } from "../../../lib/langPack"; import { LangPackKey, _i18n } from "../../../lib/langPack";
@ -120,7 +120,7 @@ export default class AppGeneralSettingsTab extends SliderSuperTab {
}), }),
subtitleLangKey: 'General.SendShortcut.NewLine.Enter' 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); form.append(enterRow.container, ctrlEnterRow.container);
container.append(form); container.append(form);

8
src/components/sidebarRight/tabs/sharedMedia.ts

@ -39,8 +39,8 @@ import AppAddMembersTab from "../../sidebarLeft/tabs/addMembers";
import PopupPickUser from "../../popups/pickUser"; import PopupPickUser from "../../popups/pickUser";
import PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from "../../popups/peer"; import PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from "../../popups/peer";
import Scrollable from "../../scrollable"; import Scrollable from "../../scrollable";
import { isTouchSupported } from "../../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../../environment/touchSupport";
import { isFirefox } from "../../../helpers/userAgent"; import { IS_FIREFOX } from "../../../environment/userAgent";
import appDownloadManager from "../../../lib/appManagers/appDownloadManager"; import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
import ButtonCorner from "../../buttonCorner"; import ButtonCorner from "../../buttonCorner";
import { cancelEvent } from "../../../helpers/dom/cancelEvent"; 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: { export function filterChatPhotosMessages(value: {
count: number; count: number;
@ -199,7 +199,7 @@ class PeerProfileAvatars {
const cancelNextClick = () => { const cancelNextClick = () => {
cancel = true; cancel = true;
document.body.addEventListener(isTouchSupported ? 'touchend' : 'click', (e) => { document.body.addEventListener(IS_TOUCH_SUPPORTED ? 'touchend' : 'click', (e) => {
cancel = false; cancel = false;
}, {once: true}); }, {once: true});
}; };

12
src/components/swipeHandler.ts

@ -6,7 +6,7 @@
import { cancelEvent } from "../helpers/dom/cancelEvent"; import { cancelEvent } from "../helpers/dom/cancelEvent";
import { safeAssign } from "../helpers/object"; import { safeAssign } from "../helpers/object";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
const getEvent = (e: TouchEvent | MouseEvent) => { const getEvent = (e: TouchEvent | MouseEvent) => {
@ -48,7 +48,7 @@ export default class SwipeHandler {
} }
public setListeners() { public setListeners() {
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.element.addEventListener('mousedown', this.handleStart, false); this.element.addEventListener('mousedown', this.handleStart, false);
attachGlobalListenerTo.addEventListener('mouseup', this.reset); attachGlobalListenerTo.addEventListener('mouseup', this.reset);
} else { } else {
@ -58,7 +58,7 @@ export default class SwipeHandler {
} }
public removeListeners() { public removeListeners() {
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.element.removeEventListener('mousedown', this.handleStart, false); this.element.removeEventListener('mousedown', this.handleStart, false);
attachGlobalListenerTo.removeEventListener('mouseup', this.reset); attachGlobalListenerTo.removeEventListener('mouseup', this.reset);
} else { } else {
@ -72,7 +72,7 @@ export default class SwipeHandler {
cancelEvent(e); cancelEvent(e);
} */ } */
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true}); attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true});
} else { } else {
attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove); attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove);
@ -96,7 +96,7 @@ export default class SwipeHandler {
this.xDown = e.clientX; this.xDown = e.clientX;
this.yDown = e.clientY; this.yDown = e.clientY;
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
attachGlobalListenerTo.addEventListener('touchmove', this.handleMove, {passive: false, capture: true}); attachGlobalListenerTo.addEventListener('touchmove', this.handleMove, {passive: false, capture: true});
} else { } else {
attachGlobalListenerTo.addEventListener('mousemove', this.handleMove, false); attachGlobalListenerTo.addEventListener('mousemove', this.handleMove, false);
@ -127,7 +127,7 @@ export default class SwipeHandler {
this.hadMove = true; this.hadMove = true;
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.element.style.setProperty('cursor', this.cursor, 'important'); this.element.style.setProperty('cursor', this.cursor, 'important');
} }

8
src/components/telInputField.ts

@ -6,7 +6,7 @@
import placeCaretAtEnd from "../helpers/dom/placeCaretAtEnd"; import placeCaretAtEnd from "../helpers/dom/placeCaretAtEnd";
import { formatPhoneNumber } from "../helpers/formatPhoneNumber"; 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 { HelpCountry, HelpCountryCode } from "../layer";
import InputField, { InputFieldOptions } from "./inputField"; import InputField, { InputFieldOptions } from "./inputField";
@ -36,9 +36,9 @@ export default class TelInputField extends InputField {
const pixelRatio = window.devicePixelRatio; const pixelRatio = window.devicePixelRatio;
if(pixelRatio > 1) { if(pixelRatio > 1) {
let letterSpacing: number; let letterSpacing: number;
if(isApple) { if(IS_APPLE) {
letterSpacing = pixelRatio * -.16; letterSpacing = pixelRatio * -.16;
} else if(isAndroid) { } else if(IS_ANDROID) {
letterSpacing = 0; letterSpacing = 0;
} }
@ -58,7 +58,7 @@ export default class TelInputField extends InputField {
const value = this.value; const value = this.value;
const diff = Math.abs(value.length - this.lastValue.length); 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); this.setValueSilently(this.lastValue + value);
} }

16
src/components/wrappers.ts

@ -11,7 +11,7 @@ import { deferredPromise } from '../helpers/cancellablePromise';
import { formatDateAccordingToToday, months } from '../helpers/date'; import { formatDateAccordingToToday, months } from '../helpers/date';
import mediaSizes, { ScreenSize } from '../helpers/mediaSizes'; import mediaSizes, { ScreenSize } from '../helpers/mediaSizes';
import { formatBytes } from '../helpers/number'; import { formatBytes } from '../helpers/number';
import { isSafari } from '../helpers/userAgent'; import { IS_SAFARI } from '../environment/userAgent';
import { PhotoSize, StickerSet } from '../layer'; import { PhotoSize, StickerSet } from '../layer';
import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager"; import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
import appMessagesManager from '../lib/appManagers/appMessagesManager'; import appMessagesManager from '../lib/appManagers/appMessagesManager';
@ -44,6 +44,8 @@ import isInDOM from '../helpers/dom/isInDOM';
import lottieLoader from '../lib/lottieLoader'; import lottieLoader from '../lib/lottieLoader';
import { clearBadCharsAndTrim } from '../helpers/cleanSearchText'; import { clearBadCharsAndTrim } from '../helpers/cleanSearchText';
import blur from '../helpers/blur'; 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 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(); loadPromise = Promise.reject();
} else if(!cacheContext.downloaded) { // * check for uploading video } else if(!cacheContext.downloaded) { // * check for uploading video
preloader.attach(container, false, null); preloader.attach(container, false, null);
video.addEventListener(isSafari ? 'timeupdate' : 'canplay', () => { video.addEventListener(IS_SAFARI ? 'timeupdate' : 'canplay', () => {
preloader.detach(); preloader.detach();
}, {once: true}); }, {once: true});
} }
@ -640,10 +642,12 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
} else if(doc.type === 'pdf') { } else if(doc.type === 'pdf') {
download = appDocsManager.downloadDoc(doc, queueId); download = appDocsManager.downloadDoc(doc, queueId);
download.then(() => { download.then(() => {
const cacheContext = appDownloadManager.getCacheContext(doc); setTimeout(() => { // wait for preloader animation end
window.open(cacheContext.url); 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); download = appDocsManager.downloadDoc(doc, queueId);
} else { } else {
download = appDocsManager.saveDocFile(doc, queueId); 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) { if(thumb && thumb._ !== 'photoPathSize' && toneIndex <= 0) {
thumbImage = new Image(); 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); renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender);
haveThumbCached = true; haveThumbCached = true;
} else { } else {

3
src/environment/ctx.ts

@ -0,0 +1,3 @@
const ctx = typeof(window) !== 'undefined' ? window : self;
export default ctx;

0
src/helpers/emojiSupport.ts → src/environment/emojiSupport.ts

21
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;

6
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;

2
src/helpers/touchSupport.ts → src/environment/touchSupport.ts

@ -5,4 +5,4 @@
*/ */
// @ts-ignore // @ts-ignore
export const isTouchSupported = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)/* || true */; export const IS_TOUCH_SUPPORTED = ('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)/* || true */;

24
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;

3
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;

4
src/helpers/dom/canFocus.ts

@ -4,8 +4,8 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
import { isMobileSafari } from "../userAgent"; import { IS_MOBILE_SAFARI } from "../../environment/userAgent";
export function canFocus(isFirstInput: boolean) { export function canFocus(isFirstInput: boolean) {
return !isMobileSafari || !isFirstInput; return !IS_MOBILE_SAFARI || !isFirstInput;
} }

4
src/helpers/dom/clickEvent.ts

@ -5,10 +5,10 @@
*/ */
import type ListenerSetter from "../listenerSetter"; import type ListenerSetter from "../listenerSetter";
import { isTouchSupported } from "../touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import simulateEvent from "./dispatchEvent"; 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 type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>;
export function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* TouchEvent | */MouseEvent) => void, options: AttachClickOptions = {}) { 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); const add = options.listenerSetter ? options.listenerSetter.add(elem) : elem.addEventListener.bind(elem);

6
src/helpers/dom/fixSafariStickyInputFocusing.ts

@ -4,12 +4,12 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
import { isTouchSupported } from "../touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import { isMobile, isSafari } from "../userAgent"; import { IS_MOBILE, IS_SAFARI } from "../../environment/userAgent";
import findUpClassName from "./findUpClassName"; import findUpClassName from "./findUpClassName";
import fixSafariStickyInput from "./fixSafariStickyInput"; 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) { if(IS_STICKY_INPUT_BUGGED) {
let key: 'clientY' | 'pageY' = 'clientY'; let key: 'clientY' | 'pageY' = 'clientY';

4
src/helpers/dom/handleScrollSideEvent.ts

@ -5,10 +5,10 @@
*/ */
import type ListenerSetter from "../listenerSetter"; 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) { export default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) {
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
let lastY: number; let lastY: number;
const options = {passive: true}; const options = {passive: true};
listenerSetter.add(elem)('touchstart', (e) => { listenerSetter.add(elem)('touchstart', (e) => {

8
src/helpers/dom/isSendShortcutPressed.ts

@ -5,10 +5,10 @@
*/ */
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
import { isMobile, isApple } from "../userAgent"; import { IS_MOBILE, IS_APPLE } from "../../environment/userAgent";
export default function isSendShortcutPressed(e: KeyboardEvent) { 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) { /* if(e.ctrlKey || e.metaKey) {
this.messageInput.innerHTML += '<br>'; this.messageInput.innerHTML += '<br>';
placeCaretAtEnd(this.message) placeCaretAtEnd(this.message)
@ -22,8 +22,8 @@ export default function isSendShortcutPressed(e: KeyboardEvent) {
return true; return true;
} else { } else {
const secondaryKey = isApple ? e.metaKey : e.ctrlKey; const secondaryKey = IS_APPLE ? e.metaKey : e.ctrlKey;
if(e.shiftKey || (isApple ? e.ctrlKey : e.metaKey)) { if(e.shiftKey || (IS_APPLE ? e.ctrlKey : e.metaKey)) {
return; return;
} }

4
src/helpers/dom/placeCaretAtEnd.ts

@ -9,10 +9,10 @@
* https://github.com/zhukov/webogram/blob/master/LICENSE * 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) { export default function placeCaretAtEnd(el: HTMLElement, ignoreTouchCheck = false) {
if(isTouchSupported && (!ignoreTouchCheck || document.activeElement !== el)) { if(IS_TOUCH_SUPPORTED && (!ignoreTouchCheck || document.activeElement !== el)) {
return; return;
} }

10
src/helpers/dropdownHover.ts

@ -9,7 +9,7 @@ import findUpAsChild from "./dom/findUpAsChild";
import EventListenerBase from "./eventListenerBase"; import EventListenerBase from "./eventListenerBase";
import ListenerSetter from "./listenerSetter"; import ListenerSetter from "./listenerSetter";
import { safeAssign } from "./object"; import { safeAssign } from "./object";
import { isTouchSupported } from "./touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
const KEEP_OPEN = false; const KEEP_OPEN = false;
const TOGGLE_TIMEOUT = 200; const TOGGLE_TIMEOUT = 200;
@ -35,7 +35,7 @@ export default class DropdownHover extends EventListenerBase<{
public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) { public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {
let firstTime = true; let firstTime = true;
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
attachClickEvent(button, () => { attachClickEvent(button, () => {
if(firstTime) { if(firstTime) {
firstTime = false; firstTime = false;
@ -76,7 +76,7 @@ export default class DropdownHover extends EventListenerBase<{
}; };
protected init() { protected init() {
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.element.onmouseout = this.onMouseOut; this.element.onmouseout = this.onMouseOut;
this.element.onmouseover = (e) => { this.element.onmouseover = (e) => {
if(this.forceClose) { if(this.forceClose) {
@ -117,7 +117,7 @@ export default class DropdownHover extends EventListenerBase<{
this.displayTimeout = window.setTimeout(() => { this.displayTimeout = window.setTimeout(() => {
this.forceClose = false; this.forceClose = false;
this.dispatchEvent('opened'); this.dispatchEvent('opened');
}, isTouchSupported ? 0 : ANIMATION_DURATION); }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);
// ! can't use together with resizeObserver // ! can't use together with resizeObserver
/* if(isTouchSupported) { /* if(isTouchSupported) {
@ -139,7 +139,7 @@ export default class DropdownHover extends EventListenerBase<{
this.element.style.display = 'none'; this.element.style.display = 'none';
this.forceClose = false; this.forceClose = false;
this.dispatchEvent('closed'); this.dispatchEvent('closed');
}, isTouchSupported ? 0 : ANIMATION_DURATION); }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);
/* if(isTouchSupported) { /* if(isTouchSupported) {
const scrollHeight = this.container.scrollHeight; const scrollHeight = this.container.scrollHeight;

4
src/helpers/files.ts

@ -6,7 +6,7 @@
import { makeMediaSize, MediaSize } from "./mediaSizes"; import { makeMediaSize, MediaSize } from "./mediaSizes";
import { pause } from "./schedulers/pause"; import { pause } from "./schedulers/pause";
import { isAppleMobile } from "./userAgent"; import { IS_APPLE_MOBILE } from "../environment/userAgent";
export function scaleMediaElement(options: { export function scaleMediaElement(options: {
media: CanvasImageSource, media: CanvasImageSource,
@ -76,7 +76,7 @@ export function onVideoLoad(video: HTMLVideoElement) {
return; return;
} }
video.addEventListener(isAppleMobile ? 'loadeddata' : 'canplay', () => resolve(), {once: true}); video.addEventListener(IS_APPLE_MOBILE ? 'loadeddata' : 'canplay', () => resolve(), {once: true});
}); });
} }

24
src/helpers/userAgent.ts

@ -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;

26
src/index.ts

@ -9,8 +9,8 @@ import blurActiveElement from './helpers/dom/blurActiveElement';
import { cancelEvent } from './helpers/dom/cancelEvent'; import { cancelEvent } from './helpers/dom/cancelEvent';
import { IS_STICKY_INPUT_BUGGED } from './helpers/dom/fixSafariStickyInputFocusing'; import { IS_STICKY_INPUT_BUGGED } from './helpers/dom/fixSafariStickyInputFocusing';
import loadFonts from './helpers/dom/loadFonts'; import loadFonts from './helpers/dom/loadFonts';
import IS_EMOJI_SUPPORTED from './helpers/emojiSupport'; import IS_EMOJI_SUPPORTED from './environment/emojiSupport';
import { isMobileSafari } from './helpers/userAgent'; import { IS_MOBILE_SAFARI } from './environment/userAgent';
import './materialize.scss'; import './materialize.scss';
import './scss/style.scss'; import './scss/style.scss';
import './scss/tgico.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; const vh = (setViewportVH && !rootScope.default.isOverlayActive ? w.height || w.innerHeight : window.innerHeight) * 0.01;
if(lastVH === vh) { if(lastVH === vh) {
return; 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) 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([ const [_, touchSupport, userAgent, rootScope, appStateManager, I18n] = await Promise.all([
import('./lib/polyfill'), import('./lib/polyfill'),
import('./helpers/touchSupport'), import('./environment/touchSupport'),
import('./helpers/userAgent'), import('./environment/userAgent'),
import('./lib/rootScope'), import('./lib/rootScope'),
import('./lib/appManagers/appStateManager'), import('./lib/appManagers/appStateManager'),
import('./lib/langPack'), 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) => { document.addEventListener('dragstart', (e) => {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
if(target.tagName === 'IMG' && target.classList.contains('emoji')) { 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'); document.documentElement.classList.add('is-firefox');
} }
if(userAgent.isApple) { if(userAgent.IS_APPLE) {
if(userAgent.isSafari) { if(userAgent.IS_SAFARI) {
document.documentElement.classList.add('is-safari'); document.documentElement.classList.add('is-safari');
} }
document.documentElement.classList.add('emoji-supported'); document.documentElement.classList.add('emoji-supported');
if(userAgent.isAppleMobile) { if(userAgent.IS_APPLE_MOBILE) {
document.documentElement.classList.add('is-ios'); document.documentElement.classList.add('is-ios');
} else { } else {
document.documentElement.classList.add('is-mac'); document.documentElement.classList.add('is-mac');
} }
} else if(userAgent.isAndroid) { } else if(userAgent.IS_ANDROID) {
document.documentElement.classList.add('is-android'); document.documentElement.classList.add('is-android');
/* document.addEventListener('focusin', (e) => { /* document.addEventListener('focusin', (e) => {
@ -193,7 +193,7 @@ console.timeEnd('get storage1'); */
}, {passive: true}); */ }, {passive: true}); */
} }
if(!touchSupport.isTouchSupported) { if(!touchSupport.IS_TOUCH_SUPPORTED) {
document.documentElement.classList.add('no-touch'); document.documentElement.classList.add('no-touch');
} else { } else {
document.documentElement.classList.add('is-touch'); document.documentElement.classList.add('is-touch');
@ -257,7 +257,7 @@ console.timeEnd('get storage1'); */
let scrollable: HTMLElement; let scrollable: HTMLElement;
if(el) { if(el) {
scrollable = el.querySelector('.scrollable') as HTMLElement; scrollable = el.querySelector('.scrollable') as HTMLElement;
if((!touchSupport.isTouchSupported || isMobileSafari)) { if((!touchSupport.IS_TOUCH_SUPPORTED || IS_MOBILE_SAFARI)) {
scrollable.classList.add('no-scrollbar'); scrollable.classList.add('no-scrollbar');
} }

8
src/lib/appManagers/appDialogsManager.ts

@ -15,7 +15,7 @@ import { ripple } from "../../components/ripple";
//import Scrollable from "../../components/scrollable"; //import Scrollable from "../../components/scrollable";
import Scrollable, { ScrollableX, SliceSides } from "../../components/scrollable"; import Scrollable, { ScrollableX, SliceSides } from "../../components/scrollable";
import { formatDateAccordingToTodayNew } from "../../helpers/date"; import { formatDateAccordingToTodayNew } from "../../helpers/date";
import { isSafari } from "../../helpers/userAgent"; import { IS_SAFARI } from "../../environment/userAgent";
import { logger, LogTypes } from "../logger"; import { logger, LogTypes } from "../logger";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope"; import rootScope from "../rootScope";
@ -45,7 +45,7 @@ import appChatsManager from "./appChatsManager";
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl"; import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
import { fastRaf, fastRafConventional, fastRafPromise } from "../../helpers/schedulers"; import { fastRaf, fastRafConventional, fastRafPromise } from "../../helpers/schedulers";
import SortedUserList from "../../components/sortedUserList"; import SortedUserList from "../../components/sortedUserList";
import { isTouchSupported } from "../../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
import handleTabSwipe from "../../helpers/dom/handleTabSwipe"; import handleTabSwipe from "../../helpers/dom/handleTabSwipe";
import windowSize from "../../helpers/windowSize"; import windowSize from "../../helpers/windowSize";
import isInDOM from "../../helpers/dom/isInDOM"; import isInDOM from "../../helpers/dom/isInDOM";
@ -202,7 +202,7 @@ export class AppDialogsManager {
}); });
} */ } */
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
handleTabSwipe(this.folders.container, (next) => { handleTabSwipe(this.folders.container, (next) => {
const prevId = selectTab.prevId(); const prevId = selectTab.prevId();
selectTab(next ? prevId + 1 : prevId - 1); selectTab(next ? prevId + 1 : prevId - 1);
@ -1100,7 +1100,7 @@ export class AppDialogsManager {
const saveLength = 10; 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); const sliceFromEnd = children.slice(lastIndex + saveLength);
/* if(sliceFromStart.length !== sliceFromEnd.length) { /* if(sliceFromStart.length !== sliceFromEnd.length) {

54
src/lib/appManagers/appDocsManager.ts

@ -15,7 +15,6 @@ import { Document, InputFileLocation, InputMedia, PhotoSize } from '../../layer'
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase'; import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import opusDecodeController from '../opusDecodeController'; import opusDecodeController from '../opusDecodeController';
import { RichTextProcessor } from '../richtextprocessor'; import { RichTextProcessor } from '../richtextprocessor';
import webpWorkerController from '../webp/webpWorkerController';
import appDownloadManager, { DownloadBlob } from './appDownloadManager'; import appDownloadManager, { DownloadBlob } from './appDownloadManager';
import appPhotosManager from './appPhotosManager'; import appPhotosManager from './appPhotosManager';
import blur from '../../helpers/blur'; import blur from '../../helpers/blur';
@ -23,11 +22,16 @@ import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from '../../config/debug'; import { MOUNT_CLASS_TO } from '../../config/debug';
import { getFullDate } from '../../helpers/date'; import { getFullDate } from '../../helpers/date';
import rootScope from '../rootScope'; import rootScope from '../rootScope';
import IS_WEBP_SUPPORTED from '../../environment/webpSupport';
export type MyDocument = Document.document; export type MyDocument = Document.document;
// TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается // TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается
const EXTENSION_MIME_TYPE_MAP: {[key: string]: string} = {
mov: 'video/quicktime'
};
export class AppDocsManager { export class AppDocsManager {
private docs: {[docId: string]: MyDocument} = {}; private docs: {[docId: string]: MyDocument} = {};
private savingLottiePreview: {[docId: string]: true} = {}; private savingLottiePreview: {[docId: string]: true} = {};
@ -135,7 +139,7 @@ export class AppDocsManager {
} }
// * there can be no thumbs, then it is a document // * 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.type = 'sticker';
doc.sticker = 1; doc.sticker = 1;
} }
@ -158,28 +162,32 @@ export class AppDocsManager {
}); });
if(!doc.mime_type) { if(!doc.mime_type) {
switch(doc.type) { const ext = (doc.file_name || '').split('.').pop();
case 'gif': const mappedMimeType = ext && EXTENSION_MIME_TYPE_MAP[ext.toLowerCase()];
case 'video': if(mappedMimeType) {
case 'round': doc.mime_type = mappedMimeType;
doc.mime_type = 'video/mp4'; } else {
break; switch(doc.type) {
case 'sticker': case 'gif':
doc.mime_type = 'image/webp'; case 'video':
break; case 'round':
case 'audio': doc.mime_type = 'video/mp4';
doc.mime_type = 'audio/mpeg'; break;
break; case 'sticker':
case 'voice': doc.mime_type = 'image/webp';
doc.mime_type = 'audio/ogg'; break;
break; case 'audio':
default: doc.mime_type = 'audio/mpeg';
doc.mime_type = 'application/octet-stream'; break;
break; case 'voice':
doc.mime_type = 'audio/ogg';
break;
default:
doc.mime_type = 'application/octet-stream';
break;
}
} }
} } else if(doc.mime_type === 'application/pdf') {
if(doc.mime_type === 'application/pdf') {
doc.type = 'pdf'; doc.type = 'pdf';
} }

17
src/lib/appManagers/appImManager.ts

@ -26,7 +26,7 @@ import appStickersManager from './appStickersManager';
import appWebPagesManager from './appWebPagesManager'; import appWebPagesManager from './appWebPagesManager';
import PopupNewMedia from '../../components/popups/newMedia'; import PopupNewMedia from '../../components/popups/newMedia';
import MarkupTooltip from '../../components/chat/markupTooltip'; import MarkupTooltip from '../../components/chat/markupTooltip';
import { isTouchSupported } from '../../helpers/touchSupport'; import { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport';
import appPollsManager from './appPollsManager'; import appPollsManager from './appPollsManager';
import SetTransition from '../../components/singleTransition'; import SetTransition from '../../components/singleTransition';
import ChatDragAndDrop from '../../components/chat/dragAndDrop'; import ChatDragAndDrop from '../../components/chat/dragAndDrop';
@ -67,13 +67,14 @@ import { pause } from '../../helpers/schedulers/pause';
import appMessagesIdsManager from './appMessagesIdsManager'; import appMessagesIdsManager from './appMessagesIdsManager';
import { InternalLink, InternalLinkTypeMap, INTERNAL_LINK_TYPE } from './internalLink'; import { InternalLink, InternalLinkTypeMap, INTERNAL_LINK_TYPE } from './internalLink';
import RichTextProcessor from '../richtextprocessor'; import RichTextProcessor from '../richtextprocessor';
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
//console.log('appImManager included33!'); //console.log('appImManager included33!');
appSidebarLeft; // just to include appSidebarLeft; // just to include
export const CHAT_ANIMATION_GROUP = 'chat'; 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 = { export type ChatSavedPosition = {
mids: number[], mids: number[],
@ -495,7 +496,7 @@ export class AppImManager {
e.target !== chat.input.messageInput && e.target !== chat.input.messageInput &&
target.tagName !== 'INPUT' && target.tagName !== 'INPUT' &&
!target.hasAttribute('contenteditable') && !target.hasAttribute('contenteditable') &&
!isTouchSupported && !IS_TOUCH_SUPPORTED &&
(!mediaSizes.isMobile || this.tabId === 1) && (!mediaSizes.isMobile || this.tabId === 1) &&
!this.chat.selection.isSelecting && !this.chat.selection.isSelecting &&
!this.chat.input.recording) { !this.chat.input.recording) {
@ -891,7 +892,7 @@ export class AppImManager {
appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]); appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]);
}); });
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.attachDragAndDropListeners(); this.attachDragAndDropListeners();
} }
@ -917,10 +918,10 @@ export class AppImManager {
} }
if(mount && !drops.length) { 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 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; const foundDocuments = types.length - foundMedia;
this.log('drag files', types); this.log('drag files', types);
@ -1029,12 +1030,12 @@ export class AppImManager {
getFilesFromEvent(e).then((files: File[]) => { getFilesFromEvent(e).then((files: File[]) => {
if(files.length) { 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'; attachType = 'document';
} }
const chatInput = this.chat.input; 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); new PopupNewMedia(this.chat, files, chatInput.willAttachType);
} }
}); });

6
src/lib/appManagers/appNotificationsManager.ts

@ -15,7 +15,7 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePr
import { tsNow } from "../../helpers/date"; import { tsNow } from "../../helpers/date";
import { deepEqual } from "../../helpers/object"; import { deepEqual } from "../../helpers/object";
import { convertInputKeyToKey } from "../../helpers/string"; 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 { InputNotifyPeer, InputPeerNotifySettings, NotifyPeer, PeerNotifySettings, Update } from "../../layer";
import I18n from "../langPack"; import I18n from "../langPack";
import apiManager from "../mtproto/mtprotoworker"; import apiManager from "../mtproto/mtprotoworker";
@ -209,7 +209,7 @@ export class AppNotificationsManager {
} }
private toggleToggler(enable = rootScope.idle.isIDLE) { private toggleToggler(enable = rootScope.idle.isIDLE) {
if(isMobile) return; if(IS_MOBILE) return;
const resetTitle = () => { const resetTitle = () => {
this.titleChanged = false; this.titleChanged = false;
@ -616,7 +616,7 @@ export class AppNotificationsManager {
} }
this.notificationsShown[key] = notification; this.notificationsShown[key] = notification;
if(!isMobile) { if(!IS_MOBILE) {
setTimeout(() => { setTimeout(() => {
this.hide(key); this.hide(key);
}, 8000); }, 8000);

4
src/lib/appManagers/appPhotosManager.ts

@ -14,7 +14,7 @@ import { bytesFromHex } from "../../helpers/bytes";
import { CancellablePromise } from "../../helpers/cancellablePromise"; import { CancellablePromise } from "../../helpers/cancellablePromise";
import { getFileNameByLocation } from "../../helpers/fileName"; import { getFileNameByLocation } from "../../helpers/fileName";
import { safeReplaceArrayInObject, isObject } from "../../helpers/object"; 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 { InputFileLocation, InputMedia, InputPhoto, Photo, PhotoSize, PhotosPhotos } from "../../layer";
import apiManager from "../mtproto/mtprotoworker"; import apiManager from "../mtproto/mtprotoworker";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
@ -165,7 +165,7 @@ export class AppPhotosManager {
let mimeType: string; let mimeType: string;
if(isSticker) { if(isSticker) {
mimeType = isSafari ? 'image/png' : 'image/webp'; mimeType = IS_SAFARI ? 'image/png' : 'image/webp';
} else { } else {
mimeType = 'image/jpeg'; mimeType = 'image/jpeg';
} }

4
src/lib/appManagers/appStateManager.ts

@ -19,7 +19,7 @@ import App from '../../config/app';
import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug'; import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';
import AppStorage from '../storage'; import AppStorage from '../storage';
import { Chat } from '../../layer'; import { Chat } from '../../layer';
import { isMobile } from '../../helpers/userAgent'; import { IS_MOBILE } from '../../environment/userAgent';
import DATABASE_STATE from '../../config/databases/state'; import DATABASE_STATE from '../../config/databases/state';
import sessionStorage from '../sessionStorage'; import sessionStorage from '../sessionStorage';
import { nextRandomUint } from '../../helpers/random'; import { nextRandomUint } from '../../helpers/random';
@ -112,7 +112,7 @@ export const STATE_INIT: State = {
recentSearch: [], recentSearch: [],
version: STATE_VERSION, version: STATE_VERSION,
authState: { authState: {
_: isMobile ? 'authStateSignIn' : 'authStateSignQr' _: IS_MOBILE ? 'authStateSignIn' : 'authStateSignQr'
}, },
hiddenPinnedMessages: {}, hiddenPinnedMessages: {},
settings: { settings: {

12
src/lib/lottieLoader.ts

@ -11,7 +11,7 @@ import EventListenerBase from "../helpers/eventListenerBase";
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { clamp } from '../helpers/number'; import { clamp } from '../helpers/number';
import { pause } from '../helpers/schedulers/pause'; 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 { logger, LogTypes } from "./logger";
import apiManager from "./mtproto/mtprotoworker"; import apiManager from "./mtproto/mtprotoworker";
@ -107,7 +107,7 @@ export class RLottiePlayer extends EventListenerBase<{
// * Skip ratio (30fps) // * Skip ratio (30fps)
let skipRatio: number; let skipRatio: number;
if(options.skipRatio !== undefined) skipRatio = options.skipRatio; 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; skipRatio = 0.5;
} }
@ -125,7 +125,7 @@ export class RLottiePlayer extends EventListenerBase<{
this.height = Math.round(this.height * pixelRatio); this.height = Math.round(this.height * pixelRatio);
} else if(pixelRatio > 1) { } else if(pixelRatio > 1) {
if(this.width > 100 && this.height > 100) { 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.width = Math.round(this.width * (pixelRatio - 1));
this.height = Math.round(this.height * (pixelRatio - 1)); */ this.height = Math.round(this.height * (pixelRatio - 1)); */
this.width = Math.round(this.width * pixelRatio); this.width = Math.round(this.width * pixelRatio);
@ -146,7 +146,7 @@ export class RLottiePlayer extends EventListenerBase<{
// * Cache frames params // * Cache frames params
if(!options.noCache/* && false */) { if(!options.noCache/* && false */) {
// проверка на размер уже после скейлинга, сделано для попапа и сайдбара, где стикеры 80х80 и 68х68, туда нужно 75% // проверка на размер уже после скейлинга, сделано для попапа и сайдбара, где стикеры 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% this.cachingDelta = 2; //2 // 50%
} else if(this.width < 100 && this.height < 100) { } else if(this.width < 100 && this.height < 100) {
this.cachingDelta = Infinity; // 100% this.cachingDelta = Infinity; // 100%
@ -303,7 +303,7 @@ export class RLottiePlayer extends EventListenerBase<{
public requestFrame(frameNo: number) { public requestFrame(frameNo: number) {
if(this.frames[frameNo]) { if(this.frames[frameNo]) {
this.renderFrame(this.frames[frameNo], frameNo); this.renderFrame(this.frames[frameNo], frameNo);
} else if(isSafari) { } else if(IS_SAFARI) {
this.sendQuery('renderFrame', frameNo); this.sendQuery('renderFrame', frameNo);
} else { } else {
if(!this.clamped.length) { // fix detached if(!this.clamped.length) { // fix detached
@ -480,7 +480,7 @@ class QueryableWorker extends EventListenerBase<any> {
} }
public sendQuery(queryMethod: string, ...args: any[]) { public sendQuery(queryMethod: string, ...args: any[]) {
if(isSafari) { if(IS_SAFARI) {
this.worker.postMessage({ this.worker.postMessage({
'queryMethod': queryMethod, 'queryMethod': queryMethod,
'queryMethodArguments': args 'queryMethodArguments': args

12
src/lib/mediaPlayer.ts

@ -5,8 +5,8 @@
*/ */
import appMediaPlaybackController from "../components/appMediaPlaybackController"; import appMediaPlaybackController from "../components/appMediaPlaybackController";
import { isAppleMobile } from "../helpers/userAgent"; import { IS_APPLE_MOBILE } from "../environment/userAgent";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import RangeSelector from "../components/rangeSelector"; import RangeSelector from "../components/rangeSelector";
import { onVideoLoad } from "../helpers/files"; import { onVideoLoad } from "../helpers/files";
import { cancelEvent } from "../helpers/dom/cancelEvent"; import { cancelEvent } from "../helpers/dom/cancelEvent";
@ -314,12 +314,12 @@ export default class VideoPlayer extends EventListenerBase<{
}); });
this.listenerSetter.add(video)('click', () => { this.listenerSetter.add(video)('click', () => {
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.togglePlay(); this.togglePlay();
} }
}); });
if(isTouchSupported) { if(IS_TOUCH_SUPPORTED) {
this.listenerSetter.add(player)('click', () => { this.listenerSetter.add(player)('click', () => {
this.toggleControls(); this.toggleControls();
}); });
@ -390,7 +390,7 @@ export default class VideoPlayer extends EventListenerBase<{
}); */ }); */
this.listenerSetter.add(video)('dblclick', () => { this.listenerSetter.add(video)('dblclick', () => {
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
this.toggleFullScreen(fullScreenButton); this.toggleFullScreen(fullScreenButton);
} }
}); });
@ -537,7 +537,7 @@ export default class VideoPlayer extends EventListenerBase<{
const player = this.wrapper; const player = this.wrapper;
// * https://caniuse.com/#feat=fullscreen // * https://caniuse.com/#feat=fullscreen
if(isAppleMobile) { if(IS_APPLE_MOBILE) {
const video = this.video as any; const video = this.video as any;
video.webkitEnterFullscreen(); video.webkitEnterFullscreen();
video.enterFullscreen(); video.enterFullscreen();

2
src/lib/mtproto/apiFileManager.ts

@ -27,7 +27,7 @@ import apiManager from "./apiManager";
import { isWebpSupported } from "./mtproto.worker"; import { isWebpSupported } from "./mtproto.worker";
import { bytesToHex } from "../../helpers/bytes"; import { bytesToHex } from "../../helpers/bytes";
import assumeType from "../../helpers/assumeType"; import assumeType from "../../helpers/assumeType";
import { ctx } from "../../helpers/userAgent"; import ctx from "../../environment/ctx";
type Delayed = { type Delayed = {
offset: number, offset: number,

5
src/lib/mtproto/apiManager.ts

@ -23,11 +23,12 @@ import type { MethodDeclMap } from '../../layer';
import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise'; import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';
import { bytesFromHex, bytesToHex } from '../../helpers/bytes'; import { bytesFromHex, bytesToHex } from '../../helpers/bytes';
//import { clamp } from '../../helpers/number'; //import { clamp } from '../../helpers/number';
import { ctx, isSafari } from '../../helpers/userAgent'; import { IS_SAFARI } from '../../environment/userAgent';
import App from '../../config/app'; import App from '../../config/app';
import { MOUNT_CLASS_TO } from '../../config/debug'; import { MOUNT_CLASS_TO } from '../../config/debug';
import IDBStorage from '../idb'; import IDBStorage from '../idb';
import CryptoWorker from "../crypto/cryptoworker"; import CryptoWorker from "../crypto/cryptoworker";
import ctx from '../../environment/ctx';
/// #if !MTPROTO_WORKER /// #if !MTPROTO_WORKER
import rootScope from '../rootScope'; import rootScope from '../rootScope';
@ -203,7 +204,7 @@ export class ApiManager {
/// #if MTPROTO_HTTP_UPLOAD /// #if MTPROTO_HTTP_UPLOAD
// @ts-ignore // @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'; //const transportType: TransportType = connectionType !== 'client' ? 'https' : 'websocket';
/// #else /// #else
// @ts-ignore // @ts-ignore

4
src/lib/mtproto/dcConfigurator.ts

@ -19,7 +19,7 @@ import HTTP from './transports/http';
/// #if !MTPROTO_HTTP /// #if !MTPROTO_HTTP
import Socket from './transports/websocket'; import Socket from './transports/websocket';
import TcpObfuscated from './transports/tcpObfuscated'; import TcpObfuscated from './transports/tcpObfuscated';
import { isSafari } from '../../helpers/userAgent'; import { IS_SAFARI } from '../../environment/userAgent';
import { isWebWorker } from '../../helpers/context'; import { isWebWorker } from '../../helpers/context';
import SocketProxied from './transports/socketProxied'; import SocketProxied from './transports/socketProxied';
import App from '../../config/app'; import App from '../../config/app';
@ -64,7 +64,7 @@ export class DcConfigurator {
const retryTimeout = connectionType === 'client' ? 10000 : 10000; 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); return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout);
}; };

2
src/lib/mtproto/mtproto.worker.ts

@ -15,12 +15,12 @@ import apiManager from "./apiManager";
import cryptoWorker from "../crypto/cryptoworker"; import cryptoWorker from "../crypto/cryptoworker";
import networkerFactory from "./networkerFactory"; import networkerFactory from "./networkerFactory";
import apiFileManager from './apiFileManager'; import apiFileManager from './apiFileManager';
import { ctx } from '../../helpers/userAgent';
import { notifyAll } from '../../helpers/context'; import { notifyAll } from '../../helpers/context';
import CacheStorageController from '../cacheStorage'; import CacheStorageController from '../cacheStorage';
import sessionStorage from '../sessionStorage'; import sessionStorage from '../sessionStorage';
import { socketsProxied } from './transports/socketProxied'; import { socketsProxied } from './transports/socketProxied';
import { bytesToHex } from '../../helpers/bytes'; import { bytesToHex } from '../../helpers/bytes';
import ctx from '../../environment/ctx';
let webpSupported = false; let webpSupported = false;
export const isWebpSupported = () => { export const isWebpSupported = () => {

3
src/lib/mtproto/mtprotoworker.ts

@ -30,6 +30,7 @@ import { SocketProxyTask } from './transports/socketProxied';
import telegramMeWebManager from './telegramMeWebManager'; import telegramMeWebManager from './telegramMeWebManager';
import { CacheStorageDbName } from '../cacheStorage'; import { CacheStorageDbName } from '../cacheStorage';
import { pause } from '../../helpers/schedulers/pause'; import { pause } from '../../helpers/schedulers/pause';
import IS_WEBP_SUPPORTED from '../../environment/webpSupport';
type Task = { type Task = {
taskId: number, taskId: number,
@ -318,7 +319,7 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
this.postMessagesWaiting.forEach(args => this.postMessage(...args)); this.postMessagesWaiting.forEach(args => this.postMessage(...args));
this.postMessagesWaiting.length = 0; this.postMessagesWaiting.length = 0;
const isWebpSupported = webpWorkerController.isWebpSupported(); const isWebpSupported = IS_WEBP_SUPPORTED;
this.log('WebP supported:', isWebpSupported); this.log('WebP supported:', isWebpSupported);
this.postMessage({type: 'webpSupport', payload: isWebpSupported}); this.postMessage({type: 'webpSupport', payload: isWebpSupported});
this.postMessage({type: 'userAgent', payload: navigator.userAgent}); this.postMessage({type: 'userAgent', payload: navigator.userAgent});

6
src/lib/mtproto/webPushApiManager.ts

@ -17,7 +17,7 @@ import rootScope from "../rootScope";
import { ServiceWorkerNotificationsClearTask, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "../serviceWorker/index.service"; import { ServiceWorkerNotificationsClearTask, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "../serviceWorker/index.service";
import apiManager from "./mtprotoworker"; import apiManager from "./mtprotoworker";
import I18n, { LangPackKey } from "../langPack"; import I18n, { LangPackKey } from "../langPack";
import { isMobile } from "../../helpers/userAgent"; import { IS_MOBILE } from "../../environment/userAgent";
import appRuntimeManager from "../appManagers/appRuntimeManager"; import appRuntimeManager from "../appManagers/appRuntimeManager";
export type PushSubscriptionNotifyType = 'init' | 'subscribe' | 'unsubscribe'; export type PushSubscriptionNotifyType = 'init' | 'subscribe' | 'unsubscribe';
@ -163,8 +163,8 @@ export class WebPushApiManager {
const lang: ServiceWorkerPingTask['payload']['lang'] = {} as any; const lang: ServiceWorkerPingTask['payload']['lang'] = {} as any;
const ACTIONS_LANG_MAP: Record<keyof ServiceWorkerPingTask['payload']['lang'], LangPackKey> = { const ACTIONS_LANG_MAP: Record<keyof ServiceWorkerPingTask['payload']['lang'], LangPackKey> = {
push_action_mute1d: isMobile ? 'PushNotification.Action.Mute1d.Mobile' : 'PushNotification.Action.Mute1d', push_action_mute1d: IS_MOBILE ? 'PushNotification.Action.Mute1d.Mobile' : 'PushNotification.Action.Mute1d',
push_action_settings: isMobile ? 'PushNotification.Action.Settings.Mobile' : 'PushNotification.Action.Settings', push_action_settings: IS_MOBILE ? 'PushNotification.Action.Settings.Mobile' : 'PushNotification.Action.Settings',
push_message_nopreview: 'PushNotification.Message.NoPreview' push_message_nopreview: 'PushNotification.Message.NoPreview'
}; };

6
src/lib/opusDecodeController.ts

@ -5,7 +5,7 @@
*/ */
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
import { isSafari } from "../helpers/userAgent"; import { IS_SAFARI } from "../environment/userAgent";
import { logger, LogTypes } from "./logger"; import { logger, LogTypes } from "./logger";
type Result = { type Result = {
@ -72,7 +72,7 @@ export class OpusDecodeController {
this.wavWorker.postMessage({ this.wavWorker.postMessage({
command: 'encode', command: 'encode',
buffers: e.data 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', command: 'decode',
pages: task.pages, pages: task.pages,
waveform: task.withWaveform waveform: task.withWaveform
}, isSafari ? undefined : [task.pages.buffer]); }, IS_SAFARI ? undefined : [task.pages.buffer]);
//}, 1e3); //}, 1e3);
task.timeout = window.setTimeout(() => { task.timeout = window.setTimeout(() => {

26
src/lib/richtextprocessor.ts

@ -15,9 +15,9 @@ import emojiRegExp from '../vendor/emoji/regex';
import { encodeEmoji, toCodePoints } from '../vendor/emoji'; import { encodeEmoji, toCodePoints } from '../vendor/emoji';
import { MessageEntity } from '../layer'; import { MessageEntity } from '../layer';
import { encodeEntities } from '../helpers/string'; import { encodeEntities } from '../helpers/string';
import { isSafari } from '../helpers/userAgent'; import { IS_SAFARI } from '../environment/userAgent';
import { MOUNT_CLASS_TO } from '../config/debug'; import { MOUNT_CLASS_TO } from '../config/debug';
import IS_EMOJI_SUPPORTED from '../helpers/emojiSupport'; import IS_EMOJI_SUPPORTED from '../environment/emojiSupport';
const EmojiHelper = { const EmojiHelper = {
emojiMap: (code: string) => { return code; }, emojiMap: (code: string) => { return code; },
@ -115,8 +115,6 @@ for(let i in markdownEntities) {
} }
namespace RichTextProcessor { namespace RichTextProcessor {
export const emojiSupported = IS_EMOJI_SUPPORTED;
export function getEmojiSpritesheetCoords(emojiCode: string) { export function getEmojiSpritesheetCoords(emojiCode: string) {
let unified = encodeEmoji(emojiCode).replace(/-?fe0f/g, ''); let unified = encodeEmoji(emojiCode).replace(/-?fe0f/g, '');
@ -406,7 +404,7 @@ namespace RichTextProcessor {
currentEntities.push(...filtered); currentEntities.push(...filtered);
currentEntities.sort((a, b) => a.offset - b.offset); 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) { for(let i = 0; i < currentEntities.length; ++i) {
const entity = currentEntities[i]; const entity = currentEntities[i];
if(entity._ === 'messageEntityEmoji') { if(entity._ === 'messageEntityEmoji') {
@ -507,7 +505,7 @@ namespace RichTextProcessor {
case 'messageEntityStrike': { case 'messageEntityStrike': {
if(options.wrappingDraft) { if(options.wrappingDraft) {
const styleName = isSafari ? 'text-decoration' : 'text-decoration-line'; const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
insertPart(entity, `<span style="${styleName}: line-through;">`, '</span>'); insertPart(entity, `<span style="${styleName}: line-through;">`, '</span>');
} else { } else {
insertPart(entity, '<del>', '</del>'); insertPart(entity, '<del>', '</del>');
@ -518,7 +516,7 @@ namespace RichTextProcessor {
case 'messageEntityUnderline': { case 'messageEntityUnderline': {
if(options.wrappingDraft) { if(options.wrappingDraft) {
const styleName = isSafari ? 'text-decoration' : 'text-decoration-line'; const styleName = IS_SAFARI ? 'text-decoration' : 'text-decoration-line';
insertPart(entity, `<span style="${styleName}: underline;">`, '</span>'); insertPart(entity, `<span style="${styleName}: underline;">`, '</span>');
} else { } else {
insertPart(entity, '<u>', '</u>'); insertPart(entity, '<u>', '</u>');
@ -571,9 +569,9 @@ namespace RichTextProcessor {
} }
case 'messageEntityEmoji': { case 'messageEntityEmoji': {
//if(!(options.wrappingDraft && emojiSupported)) { // * fix safari emoji //if(!(options.wrappingDraft && IS_EMOJI_SUPPORTED)) { // * fix safari emoji
if(!emojiSupported) { // no wrapping needed if(!IS_EMOJI_SUPPORTED) { // no wrapping needed
// if(emojiSupported) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера // if(IS_EMOJI_SUPPORTED) { // ! contenteditable="false" нужен для поля ввода, иначе там будет меняться шрифт в Safari, или же рендерить смайлик напрямую, без контейнера
// insertPart(entity, '<span class="emoji">', '</span>'); // insertPart(entity, '<span class="emoji">', '</span>');
// } else { // } else {
insertPart(entity, `<img src="assets/img/emoji/${entity.unicode}.png" alt="`, `" class="emoji">`); insertPart(entity, `<img src="assets/img/emoji/${entity.unicode}.png" alt="`, `" class="emoji">`);
@ -581,10 +579,10 @@ namespace RichTextProcessor {
//} else if(options.mustWrapEmoji) { //} else if(options.mustWrapEmoji) {
} else if(!options.wrappingDraft) { } else if(!options.wrappingDraft) {
insertPart(entity, '<span class="emoji">', '</span>'); insertPart(entity, '<span class="emoji">', '</span>');
} else if(!isSafari) { } else if(!IS_SAFARI) {
insertPart(entity, '<span class="emoji" contenteditable="false">', '</span>'); insertPart(entity, '<span class="emoji" contenteditable="false">', '</span>');
} }
/* if(!emojiSupported) { /* if(!IS_EMOJI_SUPPORTED) {
insertPart(entity, `<img src="assets/img/emoji/${entity.unicode}.png" alt="`, `" class="emoji">`); insertPart(entity, `<img src="assets/img/emoji/${entity.unicode}.png" alt="`, `" class="emoji">`);
} */ } */
@ -723,7 +721,7 @@ namespace RichTextProcessor {
} }
export function fixEmoji(text: string, entities?: MessageEntity[]) { export function fixEmoji(text: string, entities?: MessageEntity[]) {
/* if(!emojiSupported) { /* if(!IS_EMOJI_SUPPORTED) {
return text; return text;
} */ } */
// '$`\ufe0f' // '$`\ufe0f'
@ -795,7 +793,7 @@ namespace RichTextProcessor {
} }
export function wrapPlainText(text: string) { export function wrapPlainText(text: string) {
if(emojiSupported) { if(IS_EMOJI_SUPPORTED) {
return text; return text;
} }

4
src/lib/serviceWorker/push.ts

@ -11,7 +11,7 @@
import { Database } from "../../config/databases"; import { Database } from "../../config/databases";
import DATABASE_STATE from "../../config/databases/state"; import DATABASE_STATE from "../../config/databases/state";
import { isFirefox } from "../../helpers/userAgent"; import { IS_FIREFOX } from "../../environment/userAgent";
import IDBStorage from "../idb"; import IDBStorage from "../idb";
import { log, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "./index.service"; import { log, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "./index.service";
@ -256,7 +256,7 @@ export function closeAllNotifications() {
} }
function userInvisibleIsSupported() { function userInvisibleIsSupported() {
return isFirefox; return IS_FIREFOX;
} }
function fireNotification(obj: PushNotificationObject, settings: PushStorage['push_settings'], lang: PushStorage['push_lang']) { function fireNotification(obj: PushNotificationObject, settings: PushStorage['push_settings'], lang: PushStorage['push_lang']) {

15
src/lib/webp/webpWorkerController.ts

@ -20,9 +20,8 @@ export type WebpConvertTask = {
export class WebpWorkerController { export class WebpWorkerController {
private worker: Worker; private worker: Worker;
private convertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {}; private convertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
private isWebpSupportedCache: boolean;
init() { private init() {
this.worker = new WebpWorker(); this.worker = new WebpWorker();
this.worker.addEventListener('message', (e) => { this.worker.addEventListener('message', (e) => {
const payload = (e.data as WebpConvertTask).payload; const payload = (e.data as WebpConvertTask).payload;
@ -39,7 +38,7 @@ export class WebpWorkerController {
}); });
} }
postMessage(data: WebpConvertTask) { public postMessage(data: WebpConvertTask) {
if(this.init) { if(this.init) {
this.init(); this.init();
this.init = null; this.init = null;
@ -48,15 +47,7 @@ export class WebpWorkerController {
this.worker.postMessage(data); this.worker.postMessage(data);
} }
isWebpSupported() { public convert(fileName: string, bytes: Uint8Array) {
if(this.isWebpSupportedCache === undefined) {
this.isWebpSupportedCache = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp');
}
return this.isWebpSupportedCache;
}
convert(fileName: string, bytes: Uint8Array) {
fileName = 'main-' + fileName; fileName = 'main-' + fileName;
if(this.convertPromises.hasOwnProperty(fileName)) { if(this.convertPromises.hasOwnProperty(fileName)) {

9
src/pages/pageSignIn.ts

@ -13,9 +13,9 @@ import Page from "./page";
import InputField from "../components/inputField"; import InputField from "../components/inputField";
import CheckboxField from "../components/checkboxField"; import CheckboxField from "../components/checkboxField";
import Button from "../components/button"; 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 fastSmoothScroll from "../helpers/fastSmoothScroll";
import { isTouchSupported } from "../helpers/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import App from "../config/app"; import App from "../config/app";
import I18n, { _i18n, i18n } from "../lib/langPack"; import I18n, { _i18n, i18n } from "../lib/langPack";
import lottieLoader from "../lib/lottieLoader"; import lottieLoader from "../lib/lottieLoader";
@ -41,6 +41,7 @@ import simulateEvent from "../helpers/dom/dispatchEvent";
import stateStorage from "../lib/stateStorage"; import stateStorage from "../lib/stateStorage";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import TelInputField from "../components/telInputField"; import TelInputField from "../components/telInputField";
import IS_EMOJI_SUPPORTED from "../environment/emojiSupport";
//import _countries from '../countries_pretty.json'; //import _countries from '../countries_pretty.json';
let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement; let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement;
@ -117,7 +118,7 @@ let onFirstMount = () => {
const li = document.createElement('li'); const li = document.createElement('li');
let wrapped = RichTextProcessor.wrapEmojiText(emoji); let wrapped = RichTextProcessor.wrapEmojiText(emoji);
if(RichTextProcessor.emojiSupported) { if(IS_EMOJI_SUPPORTED) {
const spanEmoji = document.createElement('span'); const spanEmoji = document.createElement('span');
spanEmoji.innerHTML = wrapped; spanEmoji.innerHTML = wrapped;
li.append(spanEmoji); li.append(spanEmoji);
@ -477,7 +478,7 @@ let onFirstMount = () => {
})//.catch(tryAgain); })//.catch(tryAgain);
}; };
if(!isTouchSupported) { if(!IS_TOUCH_SUPPORTED) {
setTimeout(() => { setTimeout(() => {
telEl.focus(); telEl.focus();
}, 0); }, 0);

5
src/scss/partials/_chatBubble.scss

@ -2294,7 +2294,10 @@ $bubble-margin: .25rem;
.c-ripple__circle { .c-ripple__circle {
background-color: var(--message-out-primary-color); background-color: var(--message-out-primary-color);
opacity: .08;
&:not(.hiding) {
opacity: .08;
}
} }
} }

Loading…
Cancel
Save