mirror of
https://github.com/danog/telegram-tt.git
synced 2024-11-30 04:39:00 +01:00
[Dev] Fix eslint; Update dependencies (#1754)
This commit is contained in:
parent
0d4ab658fc
commit
07ffad4425
34
.eslintrc
34
.eslintrc
@ -2,6 +2,7 @@
|
||||
"extends": [
|
||||
"react-app",
|
||||
"plugin:teactn/recommended",
|
||||
"airbnb",
|
||||
"airbnb-typescript"
|
||||
],
|
||||
"plugins": [
|
||||
@ -34,11 +35,31 @@
|
||||
"no-else-return": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-void": "off",
|
||||
"no-continue": "off",
|
||||
"default-case": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-await-in-loop": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"function-paren-newline": ["error", "consistent"],
|
||||
"prefer-destructuring": "off",
|
||||
// Allow for...of. Edited from:
|
||||
// https://github.com/airbnb/javascript/blob/b4377fb03089dd7f08955242695860d47f9caab4/packages/eslint-config-airbnb-base/rules/style.js#L333
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
"selector": "ForInStatement",
|
||||
"message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array."
|
||||
},
|
||||
{
|
||||
"selector": "LabeledStatement",
|
||||
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand."
|
||||
},
|
||||
{
|
||||
"selector": "WithStatement",
|
||||
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
|
||||
}
|
||||
],
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/named": "off",
|
||||
@ -47,13 +68,22 @@
|
||||
"react/jsx-one-expression-per-line": "off",
|
||||
"react/button-has-type": "off",
|
||||
"react/require-default-props": "off",
|
||||
"react/function-component-definition": "off",
|
||||
// Teact feature
|
||||
"react/style-prop-object": "off",
|
||||
"react/jsx-no-bind": ["error", {
|
||||
"ignoreRefs": true,
|
||||
"allowArrowFunctions": true,
|
||||
"allowFunctions": true,
|
||||
"allowBind": false,
|
||||
"ignoreDOMComponents": true
|
||||
}],
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/no-static-element-interactions": "off",
|
||||
"jsx-a11y/label-has-associated-control": "off",
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
|
||||
"jsx-a11y/media-has-caption": "off",
|
||||
"no-async-without-await/no-async-without-await": 1,
|
||||
"@typescript-eslint/no-use-before-define": [
|
||||
"error",
|
||||
@ -64,6 +94,7 @@
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/member-delimiter-style": "error",
|
||||
"@typescript-eslint/default-param-last": "off",
|
||||
"@typescript-eslint/return-await": ["error", "in-try-catch"],
|
||||
"teactn/prefer-separate-component-file": "off"
|
||||
},
|
||||
"settings": {
|
||||
@ -71,8 +102,5 @@
|
||||
},
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"globals": {
|
||||
"APP_REVISION": "readonly"
|
||||
}
|
||||
}
|
||||
|
3443
package-lock.json
generated
3443
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@ -34,36 +34,34 @@
|
||||
"author": "Alexander Zinchuk (alexander@zinchuk.com)",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.0",
|
||||
"@babel/core": "^7.17.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
||||
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@peculiar/webcrypto": "^1.2.3",
|
||||
"@peculiar/webcrypto": "^1.3.2",
|
||||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@types/croppie": "^2.6.1",
|
||||
"@types/css-font-loading-module": "0.0.7",
|
||||
"@types/dom-mediacapture-record": "^1.0.11",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/resize-observer-browser": "^0.1.7",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/react": "^17.0.40",
|
||||
"@types/react-dom": "^17.0.13",
|
||||
"@types/wicg-mediasession": "^1.1.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
||||
"@typescript-eslint/parser": "^5.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
||||
"@typescript-eslint/parser": "^5.14.0",
|
||||
"@webpack-cli/serve": "^1.6.1",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"babel-loader": "^8.2.3",
|
||||
"browserlist": "^1.0.1",
|
||||
"buffer": "^6.0.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.6.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-config-airbnb-typescript": "^16.1.0",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^16.1.1",
|
||||
"eslint-config-react-app": "^7.0.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.2",
|
||||
"eslint-plugin-flowtype": "^8.0.3",
|
||||
@ -71,30 +69,30 @@
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-no-async-without-await": "^1.2.0",
|
||||
"eslint-plugin-no-null": "^1.0.2",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react": "^7.29.3",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-teactn": "git+https://github.com/korenskoy/eslint-plugin-teactn#c2c39dd005d58c07c24c4361de804dce1c6261b5",
|
||||
"git-revision-webpack-plugin": "^5.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"husky": "^7.0.4",
|
||||
"jest": "^27.5.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"lint-staged": "^12.3.3",
|
||||
"mini-css-extract-plugin": "^2.5.3",
|
||||
"lint-staged": "^12.3.5",
|
||||
"mini-css-extract-plugin": "^2.6.0",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"postcss-modules": "^4.3.0",
|
||||
"postcss-modules": "^4.3.1",
|
||||
"react": "^17.0.2",
|
||||
"replace-in-file": "^6.3.2",
|
||||
"sass": "^1.49.7",
|
||||
"sass-loader": "^12.4.0",
|
||||
"sass": "^1.49.9",
|
||||
"sass-loader": "^12.6.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"stylelint": "^14.3.0",
|
||||
"stylelint": "^14.5.3",
|
||||
"stylelint-config-recommended-scss": "^5.0.2",
|
||||
"stylelint-declaration-block-no-ignored-properties": "^2.5.0",
|
||||
"stylelint-group-selectors": "^1.0.8",
|
||||
"stylelint-high-performance-animation": "^1.6.0",
|
||||
"typescript": "^4.5.5",
|
||||
"webpack": "^5.68.0",
|
||||
"typescript": "^4.6.2",
|
||||
"webpack": "^5.70.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.4",
|
||||
|
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare const process: NodeJS.Process;
|
||||
|
||||
declare var APP_REVISION: string;
|
||||
declare const APP_REVISION: string;
|
||||
|
||||
declare namespace React {
|
||||
interface HTMLAttributes {
|
||||
|
@ -598,7 +598,9 @@ function buildGeo(media: GramJs.MessageMediaGeo): ApiLocation | undefined {
|
||||
}
|
||||
|
||||
function buildVenue(media: GramJs.MessageMediaVenue): ApiLocation | undefined {
|
||||
const { geo, title, provider, address, venueId, venueType } = media;
|
||||
const {
|
||||
geo, title, provider, address, venueId, venueType,
|
||||
} = media;
|
||||
const point = buildGeoPoint(geo);
|
||||
return point && {
|
||||
type: 'venue',
|
||||
@ -624,7 +626,9 @@ function buildGeoLive(media: GramJs.MessageMediaGeoLive): ApiLocation | undefine
|
||||
|
||||
function buildGeoPoint(geo: GramJs.TypeGeoPoint): ApiLocation['geo'] | undefined {
|
||||
if (geo instanceof GramJs.GeoPointEmpty) return undefined;
|
||||
const { long, lat, accuracyRadius, accessHash } = geo;
|
||||
const {
|
||||
long, lat, accuracyRadius, accessHash,
|
||||
} = geo;
|
||||
return {
|
||||
long,
|
||||
lat,
|
||||
|
@ -229,8 +229,19 @@ export function sendMessage(
|
||||
onProgress?: ApiOnProgress,
|
||||
) {
|
||||
const localMessage = buildLocalMessage(
|
||||
chat, text, entities, replyingTo, attachment, sticker, gif, poll, contact, groupedId, scheduledAt,
|
||||
sendAs, serverTimeOffset,
|
||||
chat,
|
||||
text,
|
||||
entities,
|
||||
replyingTo,
|
||||
attachment,
|
||||
sticker,
|
||||
gif,
|
||||
poll,
|
||||
contact,
|
||||
groupedId,
|
||||
scheduledAt,
|
||||
sendAs,
|
||||
serverTimeOffset,
|
||||
);
|
||||
onUpdate({
|
||||
'@type': localMessage.isScheduled ? 'newScheduledMessage' : 'newMessage',
|
||||
|
@ -776,7 +776,6 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_entities?.length) {
|
||||
_entities
|
||||
.filter((e) => e instanceof GramJs.User && !e.contact)
|
||||
|
@ -81,7 +81,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
|
||||
updateFilter(target.value);
|
||||
}, [filter, updateFilter, value]);
|
||||
|
||||
const CodeInput: FC<{ onTrigger: () => void; isOpen?: boolean }> = ({ onTrigger, isOpen }) => {
|
||||
const CodeInput: FC<{ onTrigger: () => void; isOpen?: boolean }> = useCallback(({ onTrigger, isOpen }) => {
|
||||
const handleTrigger = () => {
|
||||
if (isOpen) {
|
||||
return;
|
||||
@ -126,7 +126,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}, [filter, handleInput, handleInputKeyDown, id, isLoading, lang, value]);
|
||||
|
||||
return (
|
||||
<DropdownMenu
|
||||
|
@ -280,34 +280,32 @@ const Audio: FC<OwnProps> = ({
|
||||
|
||||
function renderWithTitle() {
|
||||
return (
|
||||
<>
|
||||
<div className={contentClassName}>
|
||||
<div className="content-row">
|
||||
<p className="title" dir="auto" title={renderFirstLine()}>{renderText(renderFirstLine())}</p>
|
||||
<div className={contentClassName}>
|
||||
<div className="content-row">
|
||||
<p className="title" dir="auto" title={renderFirstLine()}>{renderText(renderFirstLine())}</p>
|
||||
|
||||
<div className="message-date">
|
||||
{date && (
|
||||
<Link
|
||||
className="date"
|
||||
onClick={handleDateClick}
|
||||
>
|
||||
{formatPastTimeShort(lang, date * 1000)}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="message-date">
|
||||
{date && (
|
||||
<Link
|
||||
className="date"
|
||||
onClick={handleDateClick}
|
||||
>
|
||||
{formatPastTimeShort(lang, date * 1000)}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{withSeekline && (
|
||||
<div className="meta search-result" dir={isRtl ? 'rtl' : undefined}>
|
||||
<span className="duration with-seekline" dir="auto">
|
||||
{playProgress < 1 && `${formatMediaDuration(duration * playProgress, duration)}`}
|
||||
</span>
|
||||
{renderSeekline(playProgress, bufferedProgress, seekerRef)}
|
||||
</div>
|
||||
)}
|
||||
{!withSeekline && renderSecondLine()}
|
||||
</div>
|
||||
</>
|
||||
|
||||
{withSeekline && (
|
||||
<div className="meta search-result" dir={isRtl ? 'rtl' : undefined}>
|
||||
<span className="duration with-seekline" dir="auto">
|
||||
{playProgress < 1 && `${formatMediaDuration(duration * playProgress, duration)}`}
|
||||
</span>
|
||||
{renderSeekline(playProgress, bufferedProgress, seekerRef)}
|
||||
</div>
|
||||
)}
|
||||
{!withSeekline && renderSecondLine()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -356,8 +354,17 @@ const Audio: FC<OwnProps> = ({
|
||||
)}
|
||||
{origin === AudioOrigin.Search && renderWithTitle()}
|
||||
{origin !== AudioOrigin.Search && audio && renderAudio(
|
||||
lang, audio, duration, isPlaying, playProgress, bufferedProgress, seekerRef,
|
||||
(isDownloading || isUploading), date, transferProgress, onDateClick ? handleDateClick : undefined,
|
||||
lang,
|
||||
audio,
|
||||
duration,
|
||||
isPlaying,
|
||||
playProgress,
|
||||
bufferedProgress,
|
||||
seekerRef,
|
||||
(isDownloading || isUploading),
|
||||
date,
|
||||
transferProgress,
|
||||
onDateClick ? handleDateClick : undefined,
|
||||
)}
|
||||
{origin === AudioOrigin.SharedMedia && (voice || video) && renderWithTitle()}
|
||||
{origin === AudioOrigin.Inline && voice && (
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React, { FC, memo, useCallback, useRef } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
FC, memo, useCallback, useRef,
|
||||
} from '../../lib/teact/teact';
|
||||
|
||||
import { ApiMessage } from '../../api/types';
|
||||
|
||||
|
@ -45,7 +45,7 @@ export function renderMessageSummary(
|
||||
highlight?: string,
|
||||
truncateLength = TRUNCATED_SUMMARY_LENGTH,
|
||||
): TextPart[] {
|
||||
let { entities } = message.content.text || {};
|
||||
const { entities } = message.content.text || {};
|
||||
|
||||
const hasSpoilers = entities?.some((e) => e.type === ApiMessageEntityTypes.Spoiler);
|
||||
if (!hasSpoilers) {
|
||||
|
@ -104,7 +104,9 @@ const SettingsFoldersChatFilters: FC<OwnProps> = ({
|
||||
}, [mode, selectedChatIds, dispatch]);
|
||||
|
||||
useHistoryBack(
|
||||
isActive, onReset, onScreenSelect,
|
||||
isActive,
|
||||
onReset,
|
||||
onScreenSelect,
|
||||
mode === 'included' ? SettingsScreens.FoldersIncludedChats : SettingsScreens.FoldersExcludedChats,
|
||||
);
|
||||
|
||||
|
@ -163,17 +163,15 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<div className="MediaViewerActions">
|
||||
{!isAvatar && !isProtected && (
|
||||
<>
|
||||
<Button
|
||||
round
|
||||
size="smaller"
|
||||
color="translucent-white"
|
||||
ariaLabel={lang('Forward')}
|
||||
onClick={onForward}
|
||||
>
|
||||
<i className="icon-forward" />
|
||||
</Button>
|
||||
</>
|
||||
<Button
|
||||
round
|
||||
size="smaller"
|
||||
color="translucent-white"
|
||||
ariaLabel={lang('Forward')}
|
||||
onClick={onForward}
|
||||
>
|
||||
<i className="icon-forward" />
|
||||
</Button>
|
||||
)}
|
||||
{renderDownloadButton()}
|
||||
<Button
|
||||
|
@ -518,7 +518,8 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
<MediaViewerContent
|
||||
/* eslint-disable-next-line react/jsx-props-no-spreading */
|
||||
{...rest}
|
||||
messageId={previousMessageId} />
|
||||
messageId={previousMessageId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{activeMessageId && (
|
||||
@ -543,7 +544,8 @@ const MediaViewerSlides: FC<OwnProps> = ({
|
||||
<MediaViewerContent
|
||||
/* eslint-disable-next-line react/jsx-props-no-spreading */
|
||||
{...rest}
|
||||
messageId={nextMessageId}/>
|
||||
messageId={nextMessageId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -571,4 +573,5 @@ function checkIfControlTarget(e: TouchEvent | MouseEvent) {
|
||||
e.preventDefault();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
import React, {
|
||||
FC, memo, useCallback, useEffect, useRef, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
|
||||
import { ApiDimensions } from '../../api/types';
|
||||
|
||||
import useBuffering from '../../hooks/useBuffering';
|
||||
import useFullscreenStatus from '../../hooks/useFullscreen';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useVideoCleanup from '../../hooks/useVideoCleanup';
|
||||
import React, { FC, memo, useCallback, useEffect, useRef, useState } from '../../lib/teact/teact';
|
||||
|
||||
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/environment';
|
||||
import safePlay from '../../util/safePlay';
|
||||
|
||||
import Button from '../ui/Button';
|
||||
import ProgressSpinner from '../ui/ProgressSpinner';
|
||||
|
||||
|
@ -55,12 +55,11 @@ const VideoPlayerControls: FC<IProps> = ({
|
||||
const isSeekingRef = useRef<boolean>(false);
|
||||
const isSeeking = isSeekingRef.current;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let timeout: number | undefined;
|
||||
if (!isVisible || !isPlayed || isSeeking) {
|
||||
if (timeout) window.clearTimeout(timeout);
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
timeout = window.setTimeout(() => {
|
||||
setVisibility(false);
|
||||
@ -113,7 +112,6 @@ const VideoPlayerControls: FC<IProps> = ({
|
||||
});
|
||||
}, [isVisible, handleStartSeek, handleSeek, handleStopSeek]);
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName('VideoPlayerControls', isForceMobileVersion && 'mobile', isVisible && 'active')}
|
||||
|
@ -6,8 +6,9 @@ import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
|
||||
const EmojiInteractionAnimationAsync: FC<OwnProps> = (props) => {
|
||||
const { activeEmojiInteraction } = props;
|
||||
const EmojiInteractionAnimation = useModuleLoader(Bundles.Extra, 'EmojiInteractionAnimation',
|
||||
!activeEmojiInteraction);
|
||||
const EmojiInteractionAnimation = useModuleLoader(
|
||||
Bundles.Extra, 'EmojiInteractionAnimation', !activeEmojiInteraction,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return EmojiInteractionAnimation ? <EmojiInteractionAnimation {...props} /> : undefined;
|
||||
|
@ -354,7 +354,10 @@ const MiddleColumn: FC<StateProps> = ({
|
||||
|
||||
useHistoryBack(
|
||||
renderingChatId && renderingThreadId,
|
||||
closeChat, undefined, undefined, undefined,
|
||||
closeChat,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
messageLists?.map(createMessageHash) || [],
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React, { FC, memo, useCallback, useState } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
FC, memo, useCallback, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { withGlobal, getDispatch } from '../../lib/teact/teactn';
|
||||
|
||||
import { ApiUser } from '../../api/types';
|
||||
@ -61,10 +63,9 @@ const UserReportPanel: FC<OwnProps & StateProps> = ({ userId, user }) => {
|
||||
]);
|
||||
|
||||
if (!settings) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="UserReportPanel">
|
||||
{canAddContact && (
|
||||
|
@ -57,7 +57,7 @@ const AttachMenu: FC<OwnProps> = ({
|
||||
const lang = useLang();
|
||||
|
||||
if (!isButtonVisible) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -27,6 +27,7 @@ const StickerSetCover: FC<OwnProps> = ({ stickerSet, observeIntersection }) => {
|
||||
|
||||
const firstLetters = useMemo(() => {
|
||||
if ((isVideo && !IS_WEBM_SUPPORTED) || !mediaData) return getFirstLetters(stickerSet.title, 2);
|
||||
return undefined;
|
||||
}, [isVideo, mediaData, stickerSet.title]);
|
||||
|
||||
return (
|
||||
|
@ -2,7 +2,7 @@ export default async function getFilesFromDataTransferItems(dataTransferItems: D
|
||||
const files: File[] = [];
|
||||
|
||||
function traverseFileTreePromise(entry: FileSystemEntry | File, item: DataTransferItem) {
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve) => {
|
||||
if (entry instanceof File) {
|
||||
files.push(entry);
|
||||
resolve(entry);
|
||||
@ -20,11 +20,11 @@ export default async function getFilesFromDataTransferItems(dataTransferItems: D
|
||||
resolve(itemFile);
|
||||
});
|
||||
} else if (entry.isDirectory) {
|
||||
let dirReader = (entry as FileSystemDirectoryEntry).createReader();
|
||||
const dirReader = (entry as FileSystemDirectoryEntry).createReader();
|
||||
dirReader.readEntries((entries) => {
|
||||
let entriesPromises = [];
|
||||
for (let entr of entries) {
|
||||
entriesPromises.push(traverseFileTreePromise(entr, item));
|
||||
const entriesPromises = [];
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
entriesPromises.push(traverseFileTreePromise(entries[i], item));
|
||||
}
|
||||
resolve(Promise.all(entriesPromises));
|
||||
});
|
||||
@ -32,8 +32,9 @@ export default async function getFilesFromDataTransferItems(dataTransferItems: D
|
||||
});
|
||||
}
|
||||
|
||||
let entriesPromises = [];
|
||||
for (let item of dataTransferItems) {
|
||||
const entriesPromises = [];
|
||||
for (let i = 0; i < dataTransferItems.length; i++) {
|
||||
const item = dataTransferItems[i];
|
||||
if (item.kind === 'file') {
|
||||
const entry = item.webkitGetAsEntry() || item.getAsFile();
|
||||
if (entry) {
|
||||
@ -46,4 +47,3 @@ export default async function getFilesFromDataTransferItems(dataTransferItems: D
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ const useClipboardPaste = (
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const pastedText = e.clipboardData.getData('text').substring(0, MAX_MESSAGE_LENGTH);
|
||||
const { items } = e.clipboardData;
|
||||
let files: File[] = [];
|
||||
|
@ -36,10 +36,10 @@ const prepareLibraryMemo = memoized(prepareLibrary);
|
||||
const searchInLibraryMemo = memoized(searchInLibrary);
|
||||
|
||||
try {
|
||||
RE_EMOJI_SEARCH = new RegExp('(^|\\s):[-+_:\\p{L}\\p{N}]*$', 'gui');
|
||||
RE_EMOJI_SEARCH = /(^|\s):[-+_:\p{L}\p{N}]*$/gui;
|
||||
} catch (e) {
|
||||
// Support for older versions of firefox
|
||||
RE_EMOJI_SEARCH = new RegExp('(^|\\s):[-+_:\\d\\wа-яё]*$', 'gi');
|
||||
RE_EMOJI_SEARCH = /(^|\s):[-+_:\d\wа-яё]*$/gi;
|
||||
}
|
||||
|
||||
export default function useEmojiTooltip(
|
||||
|
@ -16,10 +16,10 @@ const runThrottled = throttle((cb) => cb(), 500, true);
|
||||
let RE_USERNAME_SEARCH: RegExp;
|
||||
|
||||
try {
|
||||
RE_USERNAME_SEARCH = new RegExp('(^|\\s)@[-_\\p{L}\\p{M}\\p{N}]*$', 'gui');
|
||||
RE_USERNAME_SEARCH = /(^|\s)@[-_\p{L}\p{M}\p{N}]*$/gui;
|
||||
} catch (e) {
|
||||
// Support for older versions of firefox
|
||||
RE_USERNAME_SEARCH = new RegExp('(^|\\s)@[-_\\d\\wа-яё]*$', 'gi');
|
||||
RE_USERNAME_SEARCH = /(^|\s)@[-_\d\wа-яё]*$/gi;
|
||||
}
|
||||
|
||||
export default function useMentionTooltip(
|
||||
|
@ -19,7 +19,9 @@ import { formatCountdownShort, formatLastUpdated } from '../../../util/dateForma
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useForceUpdate from '../../../hooks/useForceUpdate';
|
||||
import useTimeout from '../../../hooks/useTimeout';
|
||||
import { getMetersPerPixel, getVenueColor, getVenueIconUrl, prepareMapUrl } from '../../../util/map';
|
||||
import {
|
||||
getMetersPerPixel, getVenueColor, getVenueIconUrl, prepareMapUrl,
|
||||
} from '../../../util/map';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
import useInterval from '../../../hooks/useInterval';
|
||||
@ -28,7 +30,7 @@ import { getServerTime } from '../../../util/serverTime';
|
||||
import Avatar from '../../common/Avatar';
|
||||
import Skeleton from '../../ui/Skeleton';
|
||||
|
||||
import mapPin from '/src/assets/map-pin.svg';
|
||||
import mapPin from '../../../assets/map-pin.svg';
|
||||
import './Location.scss';
|
||||
|
||||
const MOVE_THRESHOLD = 0.0001; // ~11m
|
||||
@ -79,7 +81,9 @@ const Location: FC<OwnProps> = ({
|
||||
const [point, setPoint] = useState(geo);
|
||||
|
||||
const shouldRenderText = type === 'venue' || (type === 'geoLive' && !isExpired);
|
||||
const { width, height, zoom, scale } = DEFAULT_MAP_CONFIG;
|
||||
const {
|
||||
width, height, zoom, scale,
|
||||
} = DEFAULT_MAP_CONFIG;
|
||||
|
||||
const mediaHash = Boolean(lastSyncTime) && buildStaticMapHash(point, width, height, zoom, scale);
|
||||
const mediaBlobUrl = useMedia(mediaHash);
|
||||
@ -206,13 +210,15 @@ const Location: FC<OwnProps> = ({
|
||||
|
||||
function renderMap() {
|
||||
if (!mapBlobUrl) return <Skeleton width={width} height={height} />;
|
||||
return <img
|
||||
className="full-media map"
|
||||
src={mapBlobUrl}
|
||||
alt="Location on a map"
|
||||
width={DEFAULT_MAP_CONFIG.width}
|
||||
height={DEFAULT_MAP_CONFIG.height}
|
||||
/>;
|
||||
return (
|
||||
<img
|
||||
className="full-media map"
|
||||
src={mapBlobUrl}
|
||||
alt="Location on a map"
|
||||
width={DEFAULT_MAP_CONFIG.width}
|
||||
height={DEFAULT_MAP_CONFIG.height}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function renderPin() {
|
||||
@ -279,4 +285,3 @@ const Location: FC<OwnProps> = ({
|
||||
};
|
||||
|
||||
export default memo(Location);
|
||||
|
||||
|
@ -964,7 +964,9 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, ownProps): StateProps => {
|
||||
const { focusedMessage, forwardMessages, lastSyncTime, serverTimeOffset } = global;
|
||||
const {
|
||||
focusedMessage, forwardMessages, lastSyncTime, serverTimeOffset,
|
||||
} = global;
|
||||
const {
|
||||
message, album, withSenderName, withAvatar, threadId, messageListType, isLastInDocumentGroup,
|
||||
} = ownProps;
|
||||
|
@ -25,7 +25,9 @@ type OwnProps = {
|
||||
|
||||
const cn = createClassNameBuilder('ReactionSelectorReaction');
|
||||
|
||||
const ReactionSelectorReaction: FC<OwnProps> = ({ reaction, previewIndex, onSendReaction, isReady }) => {
|
||||
const ReactionSelectorReaction: FC<OwnProps> = ({
|
||||
reaction, previewIndex, onSendReaction, isReady,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
@ -41,16 +41,17 @@ export default function withSelectControl(WrappedComponent: FC) {
|
||||
}, [toggleMessageSelection, message]);
|
||||
|
||||
const newProps = useMemo(() => {
|
||||
const { dimensions: dims, onClick } = props;
|
||||
return {
|
||||
...props,
|
||||
isInSelectMode,
|
||||
isSelected,
|
||||
dimensions: {
|
||||
...props.dimensions,
|
||||
...dims,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
onClick: isInSelectMode ? undefined : props.onClick,
|
||||
onClick: isInSelectMode ? undefined : onClick,
|
||||
};
|
||||
}, [props, isInSelectMode, isSelected]);
|
||||
|
||||
|
@ -167,8 +167,21 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
const tabType = tabs[activeTab].type as ProfileTabType;
|
||||
|
||||
const [resultType, viewportIds, getMore, noProfileInfo] = useProfileViewportIds(
|
||||
isRightColumnShown, loadMoreMembers, loadCommonChats, searchMediaMessagesLocal, tabType, mediaSearchType, members,
|
||||
commonChatIds, usersById, userStatusesById, chatsById, chatMessages, foundIds, chatId, lastSyncTime,
|
||||
isRightColumnShown,
|
||||
loadMoreMembers,
|
||||
loadCommonChats,
|
||||
searchMediaMessagesLocal,
|
||||
tabType,
|
||||
mediaSearchType,
|
||||
members,
|
||||
commonChatIds,
|
||||
usersById,
|
||||
userStatusesById,
|
||||
chatsById,
|
||||
chatMessages,
|
||||
foundIds,
|
||||
chatId,
|
||||
lastSyncTime,
|
||||
serverTimeOffset,
|
||||
);
|
||||
const activeKey = tabs.findIndex(({ type }) => type === resultType);
|
||||
|
@ -211,7 +211,7 @@ const RightColumn: FC<StateProps> = ({
|
||||
|
||||
// We need to clear profile state and management screen state, when changing chats
|
||||
useLayoutEffectWithPrevDeps(([prevChatId]) => {
|
||||
if (prevChatId !== chatId ) {
|
||||
if (prevChatId !== chatId) {
|
||||
setProfileState(ProfileState.Profile);
|
||||
setManagementScreen(ManagementScreens.Initial);
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ const ManageInvites: FC<OwnProps & StateProps> = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<p className='text-muted'>{isChannel ? lang('PrimaryLinkHelpChannel') : lang('PrimaryLinkHelp')}</p>
|
||||
<p className="text-muted">{isChannel ? lang('PrimaryLinkHelpChannel') : lang('PrimaryLinkHelp')}</p>
|
||||
</div>
|
||||
{primaryInviteLink && (
|
||||
<div className="section">
|
||||
|
@ -148,7 +148,7 @@ const Statistics: FC<OwnProps & StateProps> = ({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{Boolean(statistics.recentTopMessages?.length) &&
|
||||
{Boolean(statistics.recentTopMessages?.length) && (
|
||||
<div className="Statistics--messages">
|
||||
<h2 className="Statistics--messages-title">{lang('ChannelStats.Recent.Header')}</h2>
|
||||
|
||||
@ -156,7 +156,7 @@ const Statistics: FC<OwnProps & StateProps> = ({
|
||||
<StatisticsRecentMessage message={message as ApiMessage & StatisticsRecentMessageType} />
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ const StatisticsRecentMessage: FC<OwnProps> = ({ message }) => {
|
||||
{formatDateTimeToString(message.date * 1000, lang.code)}
|
||||
</div>
|
||||
<div className="StatisticsRecentMessage--meta">
|
||||
{Boolean(message.forwards) ? lang('ChannelStats.SharesCount', message.forwards) : 'No shares'}
|
||||
{message.forwards ? lang('ChannelStats.SharesCount', message.forwards) : 'No shares'}
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
@ -137,7 +137,6 @@ const Button: FC<OwnProps> = ({
|
||||
dir={isRtl ? 'rtl' : undefined}
|
||||
aria-label={ariaLabel}
|
||||
aria-controls={ariaControls}
|
||||
aria-haspopup={hasPopup}
|
||||
>
|
||||
{children}
|
||||
{!disabled && ripple && (
|
||||
@ -148,7 +147,6 @@ const Button: FC<OwnProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line react/button-has-type
|
||||
<button
|
||||
ref={elementRef as RefObject<HTMLButtonElement>}
|
||||
id={id}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React, { FC, memo, useCallback, useRef } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
FC, memo, useCallback, useRef,
|
||||
} from '../../lib/teact/teact';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import { TextPart } from '../common/helpers/renderMessageText';
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { FC, useRef, useLayoutEffect, VirtualElement } from '../../lib/teact/teact';
|
||||
import {
|
||||
FC, useRef, useLayoutEffect, VirtualElement,
|
||||
} from '../../lib/teact/teact';
|
||||
import TeactDOM from '../../lib/teact/teact-dom';
|
||||
|
||||
type OwnProps = {
|
||||
|
@ -4,7 +4,6 @@ import useShowTransition from '../../hooks/useShowTransition';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
|
||||
type OwnProps = {
|
||||
isOpen: boolean;
|
||||
isCustom?: boolean;
|
||||
|
@ -12,7 +12,9 @@ type OwnProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Skeleton: FC<OwnProps> = ({ variant = 'rectangular', animation = 'wave', width, height, className }) => {
|
||||
const Skeleton: FC<OwnProps> = ({
|
||||
variant = 'rectangular', animation = 'wave', width, height, className,
|
||||
}) => {
|
||||
const classNames = buildClassName('Skeleton', variant, animation, className);
|
||||
const style = (width ? `width: ${width}px;` : '') + (height ? `height: ${height}px;` : '');
|
||||
return (
|
||||
|
@ -260,7 +260,8 @@ const Transition: FC<TransitionProps> = ({
|
||||
typeof render === 'function'
|
||||
? render(key === activeKey, key === prevActiveKey, activeKey)
|
||||
: render
|
||||
}</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -39,7 +39,7 @@ export const useResize = (
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isActive) return;
|
||||
if (!isActive) return undefined;
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
const newWidth = Math.ceil(initialElementWidth + event.clientX - initialMouseX);
|
||||
|
@ -1,29 +1,34 @@
|
||||
{
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
4,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/indent": [
|
||||
"error",
|
||||
4,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"max-len": [
|
||||
"error",
|
||||
120
|
||||
],
|
||||
"no-bitwise": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-continue": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"class-methods-use-this": "off",
|
||||
"max-classes-per-file": "off",
|
||||
"camelcase": "error"
|
||||
}
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
4,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/indent": [
|
||||
"error",
|
||||
4,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"max-len": [
|
||||
"error",
|
||||
120
|
||||
],
|
||||
"no-bitwise": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-continue": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"class-methods-use-this": "off",
|
||||
"max-classes-per-file": "off",
|
||||
"camelcase": "off"
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +186,6 @@ class TelegramClient {
|
||||
}
|
||||
// set defaults vars
|
||||
this._sender.userDisconnected = false;
|
||||
// eslint-disable-next-line camelcase
|
||||
this._sender._user_connected = false;
|
||||
this._sender.isReconnecting = false;
|
||||
this._sender._disconnected = true;
|
||||
|
@ -31,11 +31,11 @@
|
||||
@keyframes lovely-chart--animation-fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale3d(.5, .5, 1);
|
||||
transform: scale3d(0.5, 0.5, 1);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale3d(.75, .75, 1);
|
||||
transform: scale3d(0.75, 0.75, 1);
|
||||
}
|
||||
|
||||
to {
|
||||
@ -51,12 +51,12 @@
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: scale3d(.75, .75, 1);
|
||||
transform: scale3d(0.75, 0.75, 1);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale3d(.5, .5, 1);
|
||||
transform: scale3d(0.5, 0.5, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
.lovely-chart--button {
|
||||
border: 1px solid #E6ECF0;
|
||||
background-color: transparent;
|
||||
padding: 7px 7px;
|
||||
display: inline-block;
|
||||
border-radius: 18px;
|
||||
@ -11,7 +10,7 @@
|
||||
position: relative;
|
||||
|
||||
border-color: var(--text-color);
|
||||
background: transparent;
|
||||
background-color: transparent;
|
||||
color: var(--text-color);
|
||||
|
||||
&.lovely-chart--state-checked {
|
||||
|
@ -169,7 +169,8 @@ addReducer('openTipsChat', (global, actions, payload) => {
|
||||
|
||||
addReducer('loadAllChats', (global, actions, payload) => {
|
||||
const listType = payload.listType as 'active' | 'archived';
|
||||
let { shouldReplace, onReplace } = payload;
|
||||
const { onReplace } = payload;
|
||||
let { shouldReplace } = payload;
|
||||
let i = 0;
|
||||
|
||||
(async () => {
|
||||
|
@ -34,7 +34,9 @@ addReducer('loadStatistics', (global, actions, payload) => {
|
||||
});
|
||||
|
||||
addReducer('loadStatisticsAsyncGraph', (global, actions, payload) => {
|
||||
const { chatId, token, name, isPercentage } = payload;
|
||||
const {
|
||||
chatId, token, name, isPercentage,
|
||||
} = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat?.fullInfo) {
|
||||
return;
|
||||
|
@ -43,8 +43,9 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
|
||||
global = getGlobal();
|
||||
participants.forEach((participant) => {
|
||||
if (participant.id) {
|
||||
global = updateGroupCallParticipant(global, groupCallId, participant.id, participant,
|
||||
Boolean(nextOffset) || currentUserId === participant.id);
|
||||
global = updateGroupCallParticipant(
|
||||
global, groupCallId, participant.id, participant, Boolean(nextOffset) || currentUserId === participant.id,
|
||||
);
|
||||
}
|
||||
});
|
||||
if (nextOffset) {
|
||||
|
@ -687,7 +687,7 @@ addReducer('copySelectedMessages', (global) => {
|
||||
copyTextForMessages(global, chatId, messageIds);
|
||||
});
|
||||
|
||||
addReducer('copyMessagesByIds', (global, actions, payload: { messageIds?: number[] } ) => {
|
||||
addReducer('copyMessagesByIds', (global, actions, payload: { messageIds?: number[] }) => {
|
||||
const { messageIds } = payload;
|
||||
const chat = selectCurrentChat(global);
|
||||
if (!messageIds || messageIds.length === 0 || !chat) {
|
||||
@ -697,7 +697,6 @@ addReducer('copyMessagesByIds', (global, actions, payload: { messageIds?: number
|
||||
copyTextForMessages(global, chat.id, messageIds);
|
||||
});
|
||||
|
||||
|
||||
function copyTextForMessages(global: GlobalState, chatId: string, messageIds: number[]) {
|
||||
const { threadId } = selectCurrentMessageList(global) || {};
|
||||
const lang = langProvider.getTranslation;
|
||||
@ -712,7 +711,7 @@ function copyTextForMessages(global: GlobalState, chatId: string, messageIds: nu
|
||||
const result = messages.reduce((acc, message) => {
|
||||
const sender = selectSender(global, message);
|
||||
acc.push(`> ${sender ? getSenderTitle(lang, sender) : ''}:`);
|
||||
acc.push(getMessageSummaryText(lang, message, false, 0, undefined, true) + '\n');
|
||||
acc.push(`${getMessageSummaryText(lang, message, false, 0, undefined, true)}\n`);
|
||||
|
||||
return acc;
|
||||
}, [] as string[]);
|
||||
|
@ -134,7 +134,9 @@ export function buildStaticMapHash(
|
||||
zoom: number,
|
||||
scale: number,
|
||||
) {
|
||||
const { long, lat, accessHash, accuracyRadius } = geo;
|
||||
const {
|
||||
long, lat, accessHash, accuracyRadius,
|
||||
} = geo;
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
return `staticMap:${accessHash}?lat=${lat}&long=${long}&w=${width}&h=${height}&zoom=${zoom}&scale=${scale}&accuracyRadius=${accuracyRadius}`;
|
||||
|
@ -48,7 +48,6 @@ export function getMessageTextWithSpoilers(message: ApiMessage) {
|
||||
|
||||
const spoiler = generateBrailleSpoiler(length);
|
||||
|
||||
|
||||
return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`;
|
||||
}, text);
|
||||
}
|
||||
@ -160,12 +159,12 @@ export function getMessageSummaryDescription(
|
||||
}
|
||||
|
||||
if (invoice) {
|
||||
summary = lang('PaymentInvoice') + ': ' + invoice.text;
|
||||
summary = `${lang('PaymentInvoice')}: ${invoice.text}`;
|
||||
}
|
||||
|
||||
if (text) {
|
||||
if (isExtended && summary) {
|
||||
summary += '\n' + truncatedText;
|
||||
summary += `\n${truncatedText}`;
|
||||
} else {
|
||||
summary = truncatedText;
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ export function checkIfReactionAdded(oldReactions?: ApiReactions, newReactions?:
|
||||
if (!oldReactions || !oldReactions.recentReactions) return true;
|
||||
if (!newReactions || !newReactions.recentReactions) return false;
|
||||
// Skip reactions from yourself
|
||||
if (newReactions.recentReactions.every(reaction => reaction.userId === currentUserId)) return false;
|
||||
if (newReactions.recentReactions.every((reaction) => reaction.userId === currentUserId)) return false;
|
||||
const oldReactionsMap = oldReactions.results.reduce<Record<string, number>>((acc, reaction) => {
|
||||
acc[reaction.reaction] = reaction.count;
|
||||
return acc;
|
||||
}, {});
|
||||
return newReactions.results.some(r => !oldReactionsMap[r.reaction] || oldReactionsMap[r.reaction] < r.count);
|
||||
return newReactions.results.some((r) => !oldReactionsMap[r.reaction] || oldReactionsMap[r.reaction] < r.count);
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ export function leaveChat(global: GlobalState, leftChatId: string): GlobalState
|
||||
|
||||
export function addChatMembers(global: GlobalState, chat: ApiChat, membersToAdd: ApiChatMember[]): GlobalState {
|
||||
const currentMembers = chat.fullInfo?.members;
|
||||
const newMemberIds = new Set(membersToAdd.map(m => m.userId));
|
||||
const newMemberIds = new Set(membersToAdd.map((m) => m.userId));
|
||||
const updatedMembers = [
|
||||
...currentMembers?.filter((m) => !newMemberIds.has(m.userId)) || [],
|
||||
...membersToAdd,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DEBUG } from '../config';
|
||||
|
||||
export const CLIPBOARD_ITEM_SUPPORTED = navigator.clipboard && window.ClipboardItem;
|
||||
export const CLIPBOARD_ITEM_SUPPORTED = window.navigator.clipboard && window.ClipboardItem;
|
||||
|
||||
const textCopyEl = document.createElement('textarea');
|
||||
textCopyEl.setAttribute('readonly', '');
|
||||
@ -51,7 +51,7 @@ async function copyBlobToClipboard(pngBlob: Blob | null) {
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.write?.([
|
||||
await window.navigator.clipboard.write?.([
|
||||
new ClipboardItem({
|
||||
[pngBlob.type]: pngBlob,
|
||||
}),
|
||||
|
@ -55,7 +55,7 @@ export const IS_TABLET_COLUMN_LAYOUT = !IS_SINGLE_COLUMN_LAYOUT && (
|
||||
window.innerWidth <= MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN
|
||||
);
|
||||
export const IS_VOICE_RECORDING_SUPPORTED = Boolean(
|
||||
navigator.mediaDevices && 'getUserMedia' in navigator.mediaDevices && (
|
||||
window.navigator.mediaDevices && 'getUserMedia' in window.navigator.mediaDevices && (
|
||||
window.AudioContext || (window as any).webkitAudioContext
|
||||
),
|
||||
);
|
||||
|
@ -203,9 +203,12 @@ function updateFolderManager(global: GlobalState) {
|
||||
updateFolders(global, isAllFolderChanged, isArchivedFolderChanged, areFoldersChanged);
|
||||
|
||||
affectedFolderIds = affectedFolderIds.concat(updateChats(
|
||||
global, areFoldersChanged || isAllFolderChanged || isArchivedFolderChanged,
|
||||
areNotifySettingsChanged, areNotifyExceptionsChanged,
|
||||
prevAllFolderListIds, prevArchivedFolderListIds,
|
||||
global,
|
||||
areFoldersChanged || isAllFolderChanged || isArchivedFolderChanged,
|
||||
areNotifySettingsChanged,
|
||||
areNotifyExceptionsChanged,
|
||||
prevAllFolderListIds,
|
||||
prevArchivedFolderListIds,
|
||||
));
|
||||
|
||||
updateResults(unique(affectedFolderIds));
|
||||
@ -315,7 +318,7 @@ function buildFolderSummaryFromMainList(
|
||||
return {
|
||||
id: folderId,
|
||||
listIds: new Set(listIds),
|
||||
orderedPinnedIds: orderedPinnedIds,
|
||||
orderedPinnedIds,
|
||||
pinnedChatIds: new Set(orderedPinnedIds),
|
||||
};
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ export default function getMessageIdsForSelectedText() {
|
||||
const selection = window.getSelection();
|
||||
let selectedFragments = selection && selection.rangeCount ? selection.getRangeAt(0).cloneContents() : undefined;
|
||||
if (!selectedFragments || selectedFragments.childElementCount === 0) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const messageIds = Array.from(selectedFragments.children)
|
||||
@ -19,7 +19,6 @@ export default function getMessageIdsForSelectedText() {
|
||||
return result;
|
||||
}, [] as number[]);
|
||||
|
||||
|
||||
// Cleanup a document fragment because it is playing media content in the background
|
||||
while (selectedFragments.firstChild) {
|
||||
selectedFragments.removeChild(selectedFragments.firstChild);
|
||||
|
@ -5,23 +5,23 @@ const PROVIDER = 'http://maps.google.com/maps';
|
||||
const VENUE_COLORS = new Map(Object.entries({
|
||||
'building/medical': '#43b3f4',
|
||||
'building/gym': '#43b3f4',
|
||||
'arts_entertainment': '#e56dd6',
|
||||
'education/cafeteria': '#f7943f',
|
||||
'travel/bedandbreakfast': '#9987ff',
|
||||
'travel/hotel': '#9987ff',
|
||||
'travel/hostel': '#9987ff',
|
||||
'travel/resort': '#9987ff',
|
||||
'building': '#6e81b2',
|
||||
'education': '#a57348',
|
||||
'event': '#959595',
|
||||
'food': '#f7943f',
|
||||
'education/cafeteria': '#f7943f',
|
||||
'nightlife': '#e56dd6',
|
||||
'travel/hotel_bar': '#e56dd6',
|
||||
'parks_outdoors': '#6cc039',
|
||||
'shops': '#ffb300',
|
||||
'travel': '#1c9fff',
|
||||
'work': '#ad7854',
|
||||
'home': '#00aeef',
|
||||
arts_entertainment: '#e56dd6',
|
||||
building: '#6e81b2',
|
||||
education: '#a57348',
|
||||
event: '#959595',
|
||||
food: '#f7943f',
|
||||
home: '#00aeef',
|
||||
nightlife: '#e56dd6',
|
||||
parks_outdoors: '#6cc039',
|
||||
shops: '#ffb300',
|
||||
travel: '#1c9fff',
|
||||
work: '#ad7854',
|
||||
}));
|
||||
|
||||
const RANDOM_COLORS = [
|
||||
@ -34,7 +34,7 @@ export function prepareMapUrl(lat: number, long: number, zoom: number) {
|
||||
|
||||
export function getMetersPerPixel(lat: number, zoom: number) {
|
||||
// https://groups.google.com/g/google-maps-js-api-v3/c/hDRO4oHVSeM/m/osOYQYXg2oUJ
|
||||
return 156543.03392 * Math.cos(lat * Math.PI / 180) / Math.pow(2, zoom);
|
||||
return (156543.03392 * Math.cos(lat * (Math.PI / 180))) / 2 ** zoom;
|
||||
}
|
||||
|
||||
export function getVenueIconUrl(type?: string) {
|
||||
@ -52,6 +52,7 @@ export function getVenueColor(type?: string) {
|
||||
}
|
||||
|
||||
function stringToNumber(str: string) {
|
||||
return str.split('').reduce((prevHash, currVal) =>
|
||||
(((prevHash << 5) - prevHash) + currVal.charCodeAt(0)) | 0, 0);
|
||||
return str.split('').reduce((prevHash, currVal) => (
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(((prevHash << 5) - prevHash) + currVal.charCodeAt(0)) | 0), 0);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { callApi } from '../api/gramjs';
|
||||
import { ApiChat, ApiMediaFormat, ApiMessage, ApiUser, ApiUserReaction } from '../api/types';
|
||||
import {
|
||||
ApiChat, ApiMediaFormat, ApiMessage, ApiUser, ApiUserReaction,
|
||||
} from '../api/types';
|
||||
import { renderActionMessageText } from '../components/common/helpers/renderActionMessageText';
|
||||
import { DEBUG, IS_TEST } from '../config';
|
||||
import { getDispatch, getGlobal, setGlobal } from '../lib/teact/teactn';
|
||||
@ -264,9 +266,11 @@ function checkIfShouldNotify(chat: ApiChat) {
|
||||
|
||||
function getNotificationContent(chat: ApiChat, message: ApiMessage, reaction?: ApiUserReaction) {
|
||||
const global = getGlobal();
|
||||
const {
|
||||
replyToMessageId,
|
||||
} = message;
|
||||
let {
|
||||
senderId,
|
||||
replyToMessageId,
|
||||
} = message;
|
||||
if (reaction) senderId = reaction.userId;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
let RE_NOT_LETTER: RegExp;
|
||||
|
||||
try {
|
||||
RE_NOT_LETTER = new RegExp('[^\\p{L}\\p{M}]+', 'ui');
|
||||
RE_NOT_LETTER = /[^\p{L}\p{M}]+/ui;
|
||||
} catch (e) {
|
||||
// Support for older versions of firefox
|
||||
RE_NOT_LETTER = new RegExp('[^\\wа-яё]+', 'i');
|
||||
RE_NOT_LETTER = /[^\wа-яё]+/i;
|
||||
}
|
||||
|
||||
export default function searchWords(haystack: string, needle: string | string[]) {
|
||||
|
@ -52,7 +52,7 @@ if (IS_SERVICE_WORKER_SUPPORTED) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[SW] Hard reload detected, re-enabling Service Worker');
|
||||
}
|
||||
await Promise.all(registrations.map(r => r.unregister()));
|
||||
await Promise.all(registrations.map((r) => r.unregister()));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user