[Dev] Bump dependencies (#1677)
This commit is contained in:
parent
23b96505df
commit
51b2893b39
@ -63,6 +63,7 @@
|
|||||||
],
|
],
|
||||||
"@typescript-eslint/camelcase": "off",
|
"@typescript-eslint/camelcase": "off",
|
||||||
"@typescript-eslint/member-delimiter-style": "error",
|
"@typescript-eslint/member-delimiter-style": "error",
|
||||||
|
"@typescript-eslint/default-param-last": "off",
|
||||||
"teactn/prefer-separate-component-file": "off"
|
"teactn/prefer-separate-component-file": "off"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
|||||||
30
.github/workflows/tests.yml
vendored
30
.github/workflows/tests.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
||||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
||||||
|
|
||||||
name: Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_and_test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [12.x]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- run: npm ci
|
|
||||||
- run: npm run gramjs:tl
|
|
||||||
- run: npm test
|
|
||||||
env:
|
|
||||||
TELEGRAM_T_API_ID: ${{ secrets.TELEGRAM_API_ID }}
|
|
||||||
TELEGRAM_T_API_HASH: ${{ secrets.TELEGRAM_API_HASH }}
|
|
||||||
TEST_SESSION: ${{ secrets.TEST_SESSION }}
|
|
||||||
34380
package-lock.json
generated
34380
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
108
package.json
108
package.json
@ -10,7 +10,6 @@
|
|||||||
"build:production": "npm i && rm -rf dist/ && APP_VERSION=$(npm run inc_version --silent) APP_ENV=production npm run build && ./deploy/copy_to_dist.sh",
|
"build:production": "npm i && rm -rf dist/ && APP_VERSION=$(npm run inc_version --silent) APP_ENV=production npm run build && ./deploy/copy_to_dist.sh",
|
||||||
"deploy:production": "npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push",
|
"deploy:production": "npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push",
|
||||||
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"",
|
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"",
|
||||||
"perf:serve": "cross-env APP_ENV=perf parcel src/index-perf.html",
|
|
||||||
"lint": "tsc && eslint . --ext .ts,.tsx --ignore-pattern src/lib/gramjs",
|
"lint": "tsc && eslint . --ext .ts,.tsx --ignore-pattern src/lib/gramjs",
|
||||||
"lint:fix": "npm run lint -- --fix",
|
"lint:fix": "npm run lint -- --fix",
|
||||||
"gramjs:tl": "node ./src/lib/gramjs/tl/generateModules.js",
|
"gramjs:tl": "node ./src/lib/gramjs/tl/generateModules.js",
|
||||||
@ -33,83 +32,80 @@
|
|||||||
"author": "Alexander Zinchuk (alexander@zinchuk.com)",
|
"author": "Alexander Zinchuk (alexander@zinchuk.com)",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.15.0",
|
"@babel/core": "^7.16.12",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
|
||||||
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
|
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
|
||||||
"@babel/preset-env": "^7.15.0",
|
"@babel/preset-env": "^7.16.11",
|
||||||
"@babel/preset-react": "^7.14.5",
|
"@babel/preset-react": "^7.16.7",
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
"@babel/preset-typescript": "^7.16.7",
|
||||||
"@peculiar/webcrypto": "^1.1.7",
|
"@peculiar/webcrypto": "^1.2.3",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.16.1",
|
||||||
"@types/croppie": "^2.6.1",
|
"@types/croppie": "^2.6.1",
|
||||||
"@types/css-font-loading-module": "0.0.6",
|
"@types/css-font-loading-module": "0.0.7",
|
||||||
"@types/dom-mediacapture-record": "^1.0.10",
|
"@types/dom-mediacapture-record": "^1.0.11",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.4.0",
|
||||||
"@types/react": "^17.0.19",
|
"@types/react": "^17.0.38",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.11",
|
||||||
"@types/resize-observer-browser": "^0.1.6",
|
"@types/resize-observer-browser": "^0.1.6",
|
||||||
"@types/wicg-mediasession": "^1.1.2",
|
"@types/wicg-mediasession": "^1.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
||||||
"@typescript-eslint/parser": "^4.29.1",
|
"@typescript-eslint/parser": "^5.10.1",
|
||||||
"@webpack-cli/serve": "^1.5.1",
|
"@webpack-cli/serve": "^1.6.1",
|
||||||
"autoprefixer": "^10.3.7",
|
"autoprefixer": "^10.4.2",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-loader": "^8.2.3",
|
||||||
"babel-loader": "^8.2.2",
|
|
||||||
"browserlist": "^1.0.1",
|
"browserlist": "^1.0.1",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^6.2.0",
|
"css-loader": "^6.5.1",
|
||||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^14.3.2",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^8.7.0",
|
||||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
"eslint-config-airbnb-typescript": "^16.1.0",
|
||||||
"eslint-config-react-app": "^6.0.0",
|
"eslint-config-react-app": "^7.0.0",
|
||||||
"eslint-import-resolver-webpack": "^0.13.1",
|
"eslint-import-resolver-webpack": "^0.13.2",
|
||||||
"eslint-plugin-flowtype": "^5.9.0",
|
"eslint-plugin-flowtype": "^8.0.3",
|
||||||
"eslint-plugin-import": "^2.24.0",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
"eslint-plugin-no-async-without-await": "^1.2.0",
|
"eslint-plugin-no-async-without-await": "^1.2.0",
|
||||||
"eslint-plugin-no-null": "^1.0.2",
|
"eslint-plugin-no-null": "^1.0.2",
|
||||||
"eslint-plugin-react": "^7.24.0",
|
"eslint-plugin-react": "^7.28.0",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.3.0",
|
||||||
"eslint-plugin-teactn": "github:korenskoy/eslint-plugin-teactn#8fbd2b9",
|
"eslint-plugin-teactn": "github:korenskoy/eslint-plugin-teactn#8fbd2b9",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"html-webpack-plugin": "^5.3.2",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"husky": "^7.0.1",
|
"husky": "^7.0.4",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.4.7",
|
||||||
"jest-raw-loader": "^1.0.1",
|
"jest-raw-loader": "^1.0.1",
|
||||||
"lint-staged": "^11.1.2",
|
"lint-staged": "^12.3.2",
|
||||||
"mini-css-extract-plugin": "^2.2.0",
|
"mini-css-extract-plugin": "^2.5.3",
|
||||||
"node-sass": "^6.0.1",
|
"postcss-loader": "^6.2.1",
|
||||||
"optimize-css-assets-webpack-plugin": "^6.0.1",
|
"postcss-modules": "^4.3.0",
|
||||||
"postcss-loader": "^6.1.1",
|
|
||||||
"postcss-modules": "^4.2.2",
|
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"replace-in-file": "^6.2.0",
|
"replace-in-file": "^6.3.2",
|
||||||
"sass": "^1.38.0",
|
"sass": "^1.49.0",
|
||||||
"sass-loader": "^12.1.0",
|
"sass-loader": "^12.4.0",
|
||||||
"style-loader": "^3.2.1",
|
"style-loader": "^3.3.1",
|
||||||
"terser": "^5.7.1",
|
"terser": "^5.10.0",
|
||||||
"terser-webpack-plugin": "^5.1.4",
|
"terser-webpack-plugin": "^5.3.0",
|
||||||
"ts-node": "^10.2.1",
|
"ts-node": "^10.4.0",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.5.5",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^5.51.0",
|
"webpack": "^5.67.0",
|
||||||
"webpack-bundle-analyzer": "^4.4.2",
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
"webpack-cli": "^4.8.0",
|
"webpack-cli": "^4.9.2",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^4.7.3",
|
||||||
"webpack-merge": "^5.8.0"
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cryptography/aes": "^0.1.1",
|
"@cryptography/aes": "^0.1.1",
|
||||||
"async-mutex": "^0.3.1",
|
"async-mutex": "^0.3.2",
|
||||||
"big-integer": "github:painor/BigInteger.js",
|
"big-integer": "github:painor/BigInteger.js",
|
||||||
"croppie": "^2.6.5",
|
"croppie": "^2.6.5",
|
||||||
"emoji-data-ios": "github:korenskoy/emoji-data-ios#162c821",
|
"emoji-data-ios": "github:korenskoy/emoji-data-ios#162c821",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"idb-keyval": "^5.1.3",
|
"idb-keyval": "^6.1.0",
|
||||||
"opus-recorder": "github:Ajaxy/opus-recorder",
|
"opus-recorder": "github:Ajaxy/opus-recorder",
|
||||||
"os-browserify": "^0.3.0",
|
"os-browserify": "^0.3.0",
|
||||||
"pako": "^2.0.4",
|
"pako": "^2.0.4",
|
||||||
|
|||||||
34
src/@types/global.d.ts
vendored
34
src/@types/global.d.ts
vendored
@ -11,10 +11,6 @@ declare namespace React {
|
|||||||
teactOrderKey?: number;
|
teactOrderKey?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
|
|
||||||
loading?: 'auto' | 'eager' | 'lazy';
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VideoHTMLAttributes {
|
interface VideoHTMLAttributes {
|
||||||
srcObject?: MediaStream;
|
srcObject?: MediaStream;
|
||||||
}
|
}
|
||||||
@ -55,10 +51,6 @@ declare module 'pako/dist/pako_inflate' {
|
|||||||
function inflate(...args: any[]): string;
|
function inflate(...args: any[]): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type WindowWithPerf =
|
|
||||||
typeof window
|
|
||||||
& { perf: AnyLiteral };
|
|
||||||
|
|
||||||
interface TEncodedImage {
|
interface TEncodedImage {
|
||||||
result: Uint8ClampedArray;
|
result: Uint8ClampedArray;
|
||||||
width: number;
|
width: number;
|
||||||
@ -70,15 +62,6 @@ interface IWebpWorker extends Worker {
|
|||||||
requests: Map<string, (value: PromiseLike<TEncodedImage>) => void>;
|
requests: Map<string, (value: PromiseLike<TEncodedImage>) => void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
|
||||||
ClipboardItem?: any;
|
|
||||||
requestIdleCallback: (cb: AnyToVoidFunction, options: { timeout?: number }) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Clipboard {
|
|
||||||
write?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Document {
|
interface Document {
|
||||||
mozFullScreenElement: any;
|
mozFullScreenElement: any;
|
||||||
webkitFullscreenElement: any;
|
webkitFullscreenElement: any;
|
||||||
@ -97,3 +80,20 @@ interface Navigator {
|
|||||||
// PWA badging extensions https://w3c.github.io/badging/
|
// PWA badging extensions https://w3c.github.io/badging/
|
||||||
setAppBadge?(count: number): Promise<void>;
|
setAppBadge?(count: number): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix to make Boolean() work as !!
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/16655
|
||||||
|
type Falsy = false | 0 | '' | null | undefined;
|
||||||
|
|
||||||
|
interface BooleanConstructor {
|
||||||
|
new<T>(value: T | Falsy): value is T;
|
||||||
|
<T>(value: T | Falsy): value is T;
|
||||||
|
readonly prototype: Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Array<T> {
|
||||||
|
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Exclude<S, Falsy>[];
|
||||||
|
}
|
||||||
|
interface ReadonlyArray<T> {
|
||||||
|
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Exclude<S, Falsy>[];
|
||||||
|
}
|
||||||
|
|||||||
@ -191,7 +191,7 @@ export async function searchChats({ query }: { query: string }) {
|
|||||||
const allChats = result.chats.concat(result.users)
|
const allChats = result.chats.concat(result.users)
|
||||||
.map((user) => buildApiChatFromPreview(user))
|
.map((user) => buildApiChatFromPreview(user))
|
||||||
.filter<ApiChat>(Boolean as any);
|
.filter<ApiChat>(Boolean as any);
|
||||||
const allUsers = result.users.map(buildApiUser).filter((user) => !!user && !user.isSelf) as ApiUser[];
|
const allUsers = result.users.map(buildApiUser).filter((user) => Boolean(user) && !user.isSelf) as ApiUser[];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
localChats: allChats.filter((r) => localPeerIds.includes(r.id)),
|
localChats: allChats.filter((r) => localPeerIds.includes(r.id)),
|
||||||
|
|||||||
@ -92,7 +92,7 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
|
|||||||
onError: onAuthError,
|
onError: onAuthError,
|
||||||
initialMethod: platform === 'iOS' || platform === 'Android' ? 'phoneNumber' : 'qrCode',
|
initialMethod: platform === 'iOS' || platform === 'Android' ? 'phoneNumber' : 'qrCode',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ export async function invokeRequest<T extends GramJs.AnyRequest>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return shouldReturnTrue ? result && true : result;
|
return shouldReturnTrue ? result && true : result;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`[GramJs/client] INVOKE ERROR ${request.className}`);
|
console.log(`[GramJs/client] INVOKE ERROR ${request.className}`);
|
||||||
@ -323,7 +323,7 @@ async function handleTerminatedSession() {
|
|||||||
await invokeRequest(new GramJs.users.GetFullUser({
|
await invokeRequest(new GramJs.users.GetFullUser({
|
||||||
id: new GramJs.InputUserSelf(),
|
id: new GramJs.InputUserSelf(),
|
||||||
}), undefined, true);
|
}), undefined, true);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'AUTH_KEY_UNREGISTERED') {
|
if (err.message === 'AUTH_KEY_UNREGISTERED') {
|
||||||
onUpdate({
|
onUpdate({
|
||||||
'@type': 'updateConnectionState',
|
'@type': 'updateConnectionState',
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export async function fetchMessages({
|
|||||||
}),
|
}),
|
||||||
...pagination,
|
...pagination,
|
||||||
}), undefined, true);
|
}), undefined, true);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'CHANNEL_PRIVATE') {
|
if (err.message === 'CHANNEL_PRIVATE') {
|
||||||
onUpdate({
|
onUpdate({
|
||||||
'@type': 'updateChat',
|
'@type': 'updateChat',
|
||||||
@ -146,7 +146,7 @@ export async function fetchMessage({ chat, messageId }: { chat: ApiChat; message
|
|||||||
undefined,
|
undefined,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
const { message } = err;
|
const { message } = err;
|
||||||
|
|
||||||
// When fetching messages for the bot @replies, there may be situations when the user was banned
|
// When fetching messages for the bot @replies, there may be situations when the user was banned
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export async function checkPassword(currentPassword: string) {
|
|||||||
await updateTwoFaSettings({ isCheckPassword: true, currentPassword });
|
await updateTwoFaSettings({ isCheckPassword: true, currentPassword });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
onError(err);
|
onError(err);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -65,7 +65,7 @@ export async function clearPassword(currentPassword: string) {
|
|||||||
await updateTwoFaSettings({ currentPassword });
|
await updateTwoFaSettings({ currentPassword });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
onError(err);
|
onError(err);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -84,7 +84,7 @@ export async function updatePassword(currentPassword: string, password: string,
|
|||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
onError(err);
|
onError(err);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -102,7 +102,7 @@ export async function updateRecoveryEmail(currentPassword: string, email: string
|
|||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
onError(err);
|
onError(err);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -98,7 +98,7 @@ export async function fetchTopUsers() {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const users = topPeers.users.map(buildApiUser).filter((user) => !!user && !user.isSelf) as ApiUser[];
|
const users = topPeers.users.map(buildApiUser).filter((user) => Boolean(user) && !user.isSelf) as ApiUser[];
|
||||||
const ids = users.map(({ id }) => id);
|
const ids = users.map(({ id }) => id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -230,7 +230,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
|||||||
} else if (action instanceof GramJs.MessageActionChatDeleteUser) {
|
} else if (action instanceof GramJs.MessageActionChatDeleteUser) {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
if (update._entities && update._entities.some((e): e is GramJs.User => (
|
if (update._entities && update._entities.some((e): e is GramJs.User => (
|
||||||
e instanceof GramJs.User && !!e.self && e.id === action.userId
|
e instanceof GramJs.User && Boolean(e.self) && e.id === action.userId
|
||||||
))) {
|
))) {
|
||||||
onUpdate({
|
onUpdate({
|
||||||
'@type': 'updateChat',
|
'@type': 'updateChat',
|
||||||
@ -248,7 +248,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
|||||||
} else if (action instanceof GramJs.MessageActionChatAddUser) {
|
} else if (action instanceof GramJs.MessageActionChatAddUser) {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
if (update._entities && update._entities.some((e): e is GramJs.User => (
|
if (update._entities && update._entities.some((e): e is GramJs.User => (
|
||||||
e instanceof GramJs.User && !!e.self && action.users.includes(e.id)
|
e instanceof GramJs.User && Boolean(e.self) && action.users.includes(e.id)
|
||||||
))) {
|
))) {
|
||||||
onUpdate({
|
onUpdate({
|
||||||
'@type': 'updateChatJoin',
|
'@type': 'updateChatJoin',
|
||||||
|
|||||||
@ -58,7 +58,7 @@ onmessage = async (message: OriginMessageEvent) => {
|
|||||||
response,
|
response,
|
||||||
}, arrayBuffer);
|
}, arrayBuffer);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@ -402,7 +402,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isSpeakerEnabled: !isSpeakerDisabled,
|
isSpeakerEnabled: !isSpeakerDisabled,
|
||||||
participantsCount,
|
participantsCount,
|
||||||
meParticipant: selectGroupCallParticipant(global, groupCallId, global.currentUserId!),
|
meParticipant: selectGroupCallParticipant(global, groupCallId, global.currentUserId!),
|
||||||
isGroupCallPanelHidden: !!global.groupCalls.isGroupCallPanelHidden,
|
isGroupCallPanelHidden: Boolean(global.groupCalls.isGroupCallPanelHidden),
|
||||||
isAdmin: selectIsAdminInActiveGroupCall(global),
|
isAdmin: selectIsAdminInActiveGroupCall(global),
|
||||||
participants,
|
participants,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const OutlinedMicrophoneIcon: FC<OwnProps> = ({
|
|||||||
const isSpeaking = (participant.amplitude || 0) > THRESHOLD;
|
const isSpeaking = (participant.amplitude || 0) > THRESHOLD;
|
||||||
const isRaiseHand = Boolean(participant.raiseHandRating);
|
const isRaiseHand = Boolean(participant.raiseHandRating);
|
||||||
const prevIsRaiseHand = usePrevious(isRaiseHand);
|
const prevIsRaiseHand = usePrevious(isRaiseHand);
|
||||||
const canSelfUnmute = !!participant?.canSelfUnmute;
|
const canSelfUnmute = Boolean(participant?.canSelfUnmute);
|
||||||
const shouldRaiseHand = !canSelfUnmute && isMuted;
|
const shouldRaiseHand = !canSelfUnmute && isMuted;
|
||||||
const prevIsMuted = usePrevious(isMuted);
|
const prevIsMuted = usePrevious(isMuted);
|
||||||
|
|
||||||
|
|||||||
@ -301,7 +301,7 @@ const CalendarModal: FC<OwnProps> = ({
|
|||||||
selectedDay === formatDay(currentYear, currentMonth, gridDate) && 'selected',
|
selectedDay === formatDay(currentYear, currentMonth, gridDate) && 'selected',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!!gridDate && (
|
{Boolean(gridDate) && (
|
||||||
<span>{gridDate}</span>
|
<span>{gridDate}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -85,7 +85,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ChatExtra">
|
<div className="ChatExtra">
|
||||||
{formattedNumber && !!formattedNumber.length && (
|
{formattedNumber && Boolean(formattedNumber.length) && (
|
||||||
<ListItem icon="phone" multiline narrow ripple onClick={() => copy(formattedNumber, lang('Phone'))}>
|
<ListItem icon="phone" multiline narrow ripple onClick={() => copy(formattedNumber, lang('Phone'))}>
|
||||||
<span className="title" dir="auto">{formattedNumber}</span>
|
<span className="title" dir="auto">{formattedNumber}</span>
|
||||||
<span className="subtitle">{lang('Phone')}</span>
|
<span className="subtitle">{lang('Phone')}</span>
|
||||||
@ -103,7 +103,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
|||||||
<span className="subtitle">{lang('Username')}</span>
|
<span className="subtitle">{lang('Username')}</span>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
{description && !!description.length && (
|
{description && Boolean(description.length) && (
|
||||||
<ListItem
|
<ListItem
|
||||||
icon="info"
|
icon="info"
|
||||||
multiline
|
multiline
|
||||||
|
|||||||
@ -102,9 +102,9 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const isPrivateChat = isUserId(chatId);
|
const isPrivateChat = isUserId(chatId);
|
||||||
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
const isChannel = !!chat && isChatChannel(chat);
|
const isChannel = Boolean(chat) && isChatChannel(chat);
|
||||||
const isGroup = !!chat && isChatBasicGroup(chat);
|
const isGroup = Boolean(chat) && isChatBasicGroup(chat);
|
||||||
const isSuperGroup = !!chat && isChatSuperGroup(chat);
|
const isSuperGroup = Boolean(chat) && isChatSuperGroup(chat);
|
||||||
const canPinForAll = (isPrivateChat && !isChatWithSelf) || isSuperGroup || isGroup;
|
const canPinForAll = (isPrivateChat && !isChatWithSelf) || isSuperGroup || isGroup;
|
||||||
const contactName = chat && isUserId(chat.id)
|
const contactName = chat && isUserId(chat.id)
|
||||||
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
|
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const DETECT_UP_TO = 3;
|
|||||||
const MAX_LENGTH = DETECT_UP_TO * 8; // Maximum 8 per one emoji.
|
const MAX_LENGTH = DETECT_UP_TO * 8; // Maximum 8 per one emoji.
|
||||||
const RE_EMOJI_ONLY = new RegExp(`^(?:${twemojiRegex.source})+$`, '');
|
const RE_EMOJI_ONLY = new RegExp(`^(?:${twemojiRegex.source})+$`, '');
|
||||||
|
|
||||||
export default (text: string): number | false => {
|
const parseEmojiOnlyString = (text: string): number | false => {
|
||||||
if (text.length > MAX_LENGTH) {
|
if (text.length > MAX_LENGTH) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -27,3 +27,5 @@ export default (text: string): number | false => {
|
|||||||
|
|
||||||
return emojiCount;
|
return emojiCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default parseEmojiOnlyString;
|
||||||
|
|||||||
@ -54,7 +54,7 @@ export function renderMessageSummary(
|
|||||||
emojiWithSpace,
|
emojiWithSpace,
|
||||||
...(Array.isArray(description) ? description : [description]),
|
...(Array.isArray(description) ? description : [description]),
|
||||||
shouldAddEllipsis && '...',
|
shouldAddEllipsis && '...',
|
||||||
].filter(Boolean);
|
].filter<TextPart>(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderMessageText(
|
export function renderMessageText(
|
||||||
|
|||||||
@ -116,7 +116,7 @@ const ChatMessageResults: FC<OwnProps & StateProps> = ({
|
|||||||
description={lang('ChatList.Search.NoResultsDescription')}
|
description={lang('ChatList.Search.NoResultsDescription')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!!foundMessages.length && foundMessages.map(renderFoundMessage)}
|
{foundMessages.map(renderFoundMessage)}
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -204,7 +204,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
|||||||
description={lang('ChatList.Search.NoResultsDescription')}
|
description={lang('ChatList.Search.NoResultsDescription')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!!localResults.length && (
|
{Boolean(localResults.length) && (
|
||||||
<div className="chat-selection no-selection no-scrollbar" dir={lang.isRtl ? 'rtl' : undefined}>
|
<div className="chat-selection no-selection no-scrollbar" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
{localResults.map((id) => (
|
{localResults.map((id) => (
|
||||||
<PickerSelectedItem
|
<PickerSelectedItem
|
||||||
@ -215,7 +215,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!!localResults.length && (
|
{Boolean(localResults.length) && (
|
||||||
<div className="search-section">
|
<div className="search-section">
|
||||||
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
||||||
{localResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
{localResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
||||||
@ -239,7 +239,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!!globalResults.length && (
|
{Boolean(globalResults.length) && (
|
||||||
<div className="search-section">
|
<div className="search-section">
|
||||||
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>
|
||||||
{globalResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
{globalResults.length > LESS_LIST_ITEMS_AMOUNT && (
|
||||||
@ -264,7 +264,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!!foundMessages.length && (
|
{Boolean(foundMessages.length) && (
|
||||||
<div className="search-section">
|
<div className="search-section">
|
||||||
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>{lang('SearchMessages')}</h3>
|
<h3 className="section-heading" dir={lang.isRtl ? 'auto' : undefined}>{lang('SearchMessages')}</h3>
|
||||||
{foundMessages.map(renderFoundMessage)}
|
{foundMessages.map(renderFoundMessage)}
|
||||||
|
|||||||
@ -298,7 +298,7 @@ const SettingsFoldersEdit: FC<OwnProps & StateProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FloatingActionButton
|
<FloatingActionButton
|
||||||
isShown={!!state.isTouched}
|
isShown={Boolean(state.isTouched)}
|
||||||
disabled={state.isLoading}
|
disabled={state.isLoading}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
ariaLabel={state.mode === 'edit' ? 'Save changes' : 'Create folder'}
|
ariaLabel={state.mode === 'edit' ? 'Save changes' : 'Create folder'}
|
||||||
|
|||||||
@ -189,7 +189,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps> = ({
|
|||||||
) : <Loading />}
|
) : <Loading />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(recommendedChatFolders && !!recommendedChatFolders.length) && (
|
{(recommendedChatFolders && Boolean(recommendedChatFolders.length)) && (
|
||||||
<div className="settings-item pt-3">
|
<div className="settings-item pt-3">
|
||||||
<h4 className="settings-item-header mb-3" dir={lang.isRtl ? 'rtl' : undefined}>
|
<h4 className="settings-item-header mb-3" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
{lang('FilterRecommended')}
|
{lang('FilterRecommended')}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
const units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'];
|
const units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'];
|
||||||
|
|
||||||
export default (bytes: number) => {
|
const formatFileSize = (bytes: number) => {
|
||||||
const number = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024));
|
const number = bytes === 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024));
|
||||||
|
|
||||||
return `${(bytes / 1024 ** Math.floor(number)).toFixed(1)} ${units[number]}`;
|
return `${(bytes / 1024 ** Math.floor(number)).toFixed(1)} ${units[number]}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default formatFileSize;
|
||||||
|
|||||||
@ -126,7 +126,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
|||||||
{formattedMessagesCount}
|
{formattedMessagesCount}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{!!selectedMessagesCount && (
|
{Boolean(selectedMessagesCount) && (
|
||||||
<div className="MessageSelectToolbar-actions">
|
<div className="MessageSelectToolbar-actions">
|
||||||
{messageListType !== 'scheduled' && (
|
{messageListType !== 'scheduled' && (
|
||||||
renderButton(
|
renderButton(
|
||||||
|
|||||||
@ -376,8 +376,8 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
<GroupCallTopPane
|
<GroupCallTopPane
|
||||||
hasPinnedOffset={
|
hasPinnedOffset={
|
||||||
(shouldRenderPinnedMessage && !!renderingPinnedMessage)
|
(shouldRenderPinnedMessage && Boolean(renderingPinnedMessage))
|
||||||
|| (shouldRenderAudioPlayer && !!renderingAudioMessage)
|
|| (shouldRenderAudioPlayer && Boolean(renderingAudioMessage))
|
||||||
}
|
}
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -682,7 +682,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
+ (isWhenOnline ? 0 : serverTimeOffset);
|
+ (isWhenOnline ? 0 : serverTimeOffset);
|
||||||
|
|
||||||
if (!scheduledMessageArgs || Object.keys(restArgs).length === 0) {
|
if (!scheduledMessageArgs || Object.keys(restArgs).length === 0) {
|
||||||
void handleSend(!!isSilent, scheduledAt);
|
void handleSend(Boolean(isSilent), scheduledAt);
|
||||||
} else {
|
} else {
|
||||||
sendMessage({
|
sendMessage({
|
||||||
...scheduledMessageArgs,
|
...scheduledMessageArgs,
|
||||||
|
|||||||
@ -180,7 +180,7 @@ const TextFormatter: FC<OwnProps> = ({
|
|||||||
|
|
||||||
if (key === 'monospace' || key === 'strikethrough') {
|
if (key === 'monospace' || key === 'strikethrough') {
|
||||||
if (Object.keys(selectedTextFormats).some(
|
if (Object.keys(selectedTextFormats).some(
|
||||||
(fKey) => fKey !== key && !!selectedTextFormats[fKey as keyof ISelectedTextFormats],
|
(fKey) => fKey !== key && Boolean(selectedTextFormats[fKey as keyof ISelectedTextFormats]),
|
||||||
)) {
|
)) {
|
||||||
return 'disabled';
|
return 'disabled';
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ const TextFormatter: FC<OwnProps> = ({
|
|||||||
// Somehow re-applying 'bold' command to already bold text doesn't work
|
// Somehow re-applying 'bold' command to already bold text doesn't work
|
||||||
document.execCommand(selectedFormats.bold ? 'removeFormat' : 'bold');
|
document.execCommand(selectedFormats.bold ? 'removeFormat' : 'bold');
|
||||||
Object.keys(selectedFormats).forEach((key) => {
|
Object.keys(selectedFormats).forEach((key) => {
|
||||||
if ((key === 'italic' || key === 'underline') && !!selectedFormats[key]) {
|
if ((key === 'italic' || key === 'underline') && Boolean(selectedFormats[key])) {
|
||||||
document.execCommand(key);
|
document.execCommand(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -395,7 +395,7 @@ const TextFormatter: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const linkUrlConfirmClassName = buildClassName(
|
const linkUrlConfirmClassName = buildClassName(
|
||||||
'TextFormatter-link-url-confirm',
|
'TextFormatter-link-url-confirm',
|
||||||
!!linkUrl.length && 'shown',
|
Boolean(linkUrl.length) && 'shown',
|
||||||
);
|
);
|
||||||
|
|
||||||
const style = anchorPosition
|
const style = anchorPosition
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { EDITABLE_INPUT_ID, EDITABLE_INPUT_MODAL_ID } from '../../../../config';
|
|||||||
const CLIPBOARD_ACCEPTED_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
|
const CLIPBOARD_ACCEPTED_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
|
||||||
const MAX_MESSAGE_LENGTH = 4096;
|
const MAX_MESSAGE_LENGTH = 4096;
|
||||||
|
|
||||||
export default (
|
const useClipboardPaste = (
|
||||||
insertTextAndUpdateCursor: (text: string, inputId?: string) => void,
|
insertTextAndUpdateCursor: (text: string, inputId?: string) => void,
|
||||||
setAttachments: StateHookSetter<ApiAttachment[]>,
|
setAttachments: StateHookSetter<ApiAttachment[]>,
|
||||||
editedMessage: ApiMessage | undefined,
|
editedMessage: ApiMessage | undefined,
|
||||||
@ -55,3 +55,5 @@ export default (
|
|||||||
};
|
};
|
||||||
}, [insertTextAndUpdateCursor, editedMessage, setAttachments]);
|
}, [insertTextAndUpdateCursor, editedMessage, setAttachments]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useClipboardPaste;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import { IS_TOUCH_ENV } from '../../../../util/environment';
|
|||||||
let currentChatId: string | undefined;
|
let currentChatId: string | undefined;
|
||||||
let currentThreadId: number | undefined;
|
let currentThreadId: number | undefined;
|
||||||
|
|
||||||
export default (
|
const useDraft = (
|
||||||
draft: ApiFormattedText | undefined,
|
draft: ApiFormattedText | undefined,
|
||||||
chatId: string,
|
chatId: string,
|
||||||
threadId: number,
|
threadId: number,
|
||||||
@ -105,3 +105,5 @@ export default (
|
|||||||
useBackgroundMode(handleBlur);
|
useBackgroundMode(handleBlur);
|
||||||
useBeforeUnload(handleBlur);
|
useBeforeUnload(handleBlur);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useDraft;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import getMessageTextAsHtml from '../helpers/getMessageTextAsHtml';
|
|||||||
import focusEditableElement from '../../../../util/focusEditableElement';
|
import focusEditableElement from '../../../../util/focusEditableElement';
|
||||||
import { hasMessageMedia } from '../../../../modules/helpers';
|
import { hasMessageMedia } from '../../../../modules/helpers';
|
||||||
|
|
||||||
export default (
|
const useEditing = (
|
||||||
htmlRef: { current: string },
|
htmlRef: { current: string },
|
||||||
setHtml: (html: string) => void,
|
setHtml: (html: string) => void,
|
||||||
editedMessage: ApiMessage | undefined,
|
editedMessage: ApiMessage | undefined,
|
||||||
@ -57,3 +57,5 @@ export default (
|
|||||||
|
|
||||||
return handleEditComplete;
|
return handleEditComplete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useEditing;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import captureEscKeyListener from '../../../../util/captureEscKeyListener';
|
|||||||
|
|
||||||
type ActiveVoiceRecording = { stop: () => Promise<voiceRecording.Result>; pause: NoneToVoidFunction } | undefined;
|
type ActiveVoiceRecording = { stop: () => Promise<voiceRecording.Result>; pause: NoneToVoidFunction } | undefined;
|
||||||
|
|
||||||
export default () => {
|
const useVoiceRecording = () => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const recordButtonRef = useRef<HTMLButtonElement>(null);
|
const recordButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
const [activeVoiceRecording, setActiveVoiceRecording] = useState<ActiveVoiceRecording>();
|
const [activeVoiceRecording, setActiveVoiceRecording] = useState<ActiveVoiceRecording>();
|
||||||
@ -93,3 +93,5 @@ export default () => {
|
|||||||
startRecordTimeRef,
|
startRecordTimeRef,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useVoiceRecording;
|
||||||
|
|||||||
@ -1041,7 +1041,9 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isInSelectMode: selectIsInSelectMode(global),
|
isInSelectMode: selectIsInSelectMode(global),
|
||||||
isSelected,
|
isSelected,
|
||||||
isGroupSelected: (
|
isGroupSelected: (
|
||||||
!!message.groupedId && !message.isInAlbum && selectIsDocumentGroupSelected(global, chatId, message.groupedId)
|
Boolean(message.groupedId)
|
||||||
|
&& !message.isInAlbum
|
||||||
|
&& selectIsDocumentGroupSelected(global, chatId, message.groupedId)
|
||||||
),
|
),
|
||||||
threadId,
|
threadId,
|
||||||
isDownloading,
|
isDownloading,
|
||||||
|
|||||||
@ -202,7 +202,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="changeInfo"
|
name="changeInfo"
|
||||||
checked={!!permissions.changeInfo}
|
checked={Boolean(permissions.changeInfo)}
|
||||||
label={lang(isChannel ? 'EditAdminChangeChannelInfo' : 'EditAdminChangeGroupInfo')}
|
label={lang(isChannel ? 'EditAdminChangeChannelInfo' : 'EditAdminChangeGroupInfo')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('changeInfo')}
|
disabled={getControlIsDisabled('changeInfo')}
|
||||||
@ -213,7 +213,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="postMessages"
|
name="postMessages"
|
||||||
checked={!!permissions.postMessages}
|
checked={Boolean(permissions.postMessages)}
|
||||||
label={lang('EditAdminPostMessages')}
|
label={lang('EditAdminPostMessages')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('postMessages')}
|
disabled={getControlIsDisabled('postMessages')}
|
||||||
@ -225,7 +225,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="editMessages"
|
name="editMessages"
|
||||||
checked={!!permissions.editMessages}
|
checked={Boolean(permissions.editMessages)}
|
||||||
label={lang('EditAdminEditMessages')}
|
label={lang('EditAdminEditMessages')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('editMessages')}
|
disabled={getControlIsDisabled('editMessages')}
|
||||||
@ -236,7 +236,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="deleteMessages"
|
name="deleteMessages"
|
||||||
checked={!!permissions.deleteMessages}
|
checked={Boolean(permissions.deleteMessages)}
|
||||||
label={lang(isChannel ? 'EditAdminDeleteMessages' : 'EditAdminGroupDeleteMessages')}
|
label={lang(isChannel ? 'EditAdminDeleteMessages' : 'EditAdminGroupDeleteMessages')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('deleteMessages')}
|
disabled={getControlIsDisabled('deleteMessages')}
|
||||||
@ -247,7 +247,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="banUsers"
|
name="banUsers"
|
||||||
checked={!!permissions.banUsers}
|
checked={Boolean(permissions.banUsers)}
|
||||||
label={lang('EditAdminBanUsers')}
|
label={lang('EditAdminBanUsers')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('banUsers')}
|
disabled={getControlIsDisabled('banUsers')}
|
||||||
@ -258,7 +258,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="inviteUsers"
|
name="inviteUsers"
|
||||||
checked={!!permissions.inviteUsers}
|
checked={Boolean(permissions.inviteUsers)}
|
||||||
label={lang('EditAdminAddUsers')}
|
label={lang('EditAdminAddUsers')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('inviteUsers')}
|
disabled={getControlIsDisabled('inviteUsers')}
|
||||||
@ -269,7 +269,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="pinMessages"
|
name="pinMessages"
|
||||||
checked={!!permissions.pinMessages}
|
checked={Boolean(permissions.pinMessages)}
|
||||||
label={lang('EditAdminPinMessages')}
|
label={lang('EditAdminPinMessages')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('pinMessages')}
|
disabled={getControlIsDisabled('pinMessages')}
|
||||||
@ -280,7 +280,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="addAdmins"
|
name="addAdmins"
|
||||||
checked={!!permissions.addAdmins}
|
checked={Boolean(permissions.addAdmins)}
|
||||||
label={lang('EditAdminAddAdmins')}
|
label={lang('EditAdminAddAdmins')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('addAdmins')}
|
disabled={getControlIsDisabled('addAdmins')}
|
||||||
@ -290,7 +290,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="manageCall"
|
name="manageCall"
|
||||||
checked={!!permissions.manageCall}
|
checked={Boolean(permissions.manageCall)}
|
||||||
label={lang('StartVoipChatPermission')}
|
label={lang('StartVoipChatPermission')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('manageCall')}
|
disabled={getControlIsDisabled('manageCall')}
|
||||||
@ -301,7 +301,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<div className="ListItem no-selection">
|
<div className="ListItem no-selection">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="anonymous"
|
name="anonymous"
|
||||||
checked={!!permissions.anonymous}
|
checked={Boolean(permissions.anonymous)}
|
||||||
label={lang('EditAdminSendAnonymously')}
|
label={lang('EditAdminSendAnonymously')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('anonymous')}
|
disabled={getControlIsDisabled('anonymous')}
|
||||||
|
|||||||
@ -95,7 +95,7 @@ const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
|||||||
// No need for expensive global updates on users, so we avoid them
|
// No need for expensive global updates on users, so we avoid them
|
||||||
const usersById = getGlobal().users.byId;
|
const usersById = getGlobal().users.byId;
|
||||||
const chatsById = getGlobal().chats.byId;
|
const chatsById = getGlobal().chats.byId;
|
||||||
const shouldUseSearchResults = !!searchQuery;
|
const shouldUseSearchResults = Boolean(searchQuery);
|
||||||
const listedIds = !shouldUseSearchResults
|
const listedIds = !shouldUseSearchResults
|
||||||
? memberIds
|
? memberIds
|
||||||
: (localContactIds ? filterUsersByName(localContactIds, usersById, searchQuery) : []);
|
: (localContactIds ? filterUsersByName(localContactIds, usersById, searchQuery) : []);
|
||||||
|
|||||||
@ -131,7 +131,7 @@ const ManageGroupPermissions: FC<OwnProps & StateProps> = ({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return chat.fullInfo.members.filter(({ bannedRights }) => !!bannedRights);
|
return chat.fullInfo.members.filter(({ bannedRights }) => Boolean(bannedRights));
|
||||||
}, [chat]);
|
}, [chat]);
|
||||||
|
|
||||||
const getMemberExceptions = useCallback((member: ApiChatMember) => {
|
const getMemberExceptions = useCallback((member: ApiChatMember) => {
|
||||||
|
|||||||
@ -71,7 +71,7 @@ const DropdownMenu: FC<OwnProps> = ({
|
|||||||
<Menu
|
<Menu
|
||||||
ref={menuRef}
|
ref={menuRef}
|
||||||
containerRef={dropdownRef}
|
containerRef={dropdownRef}
|
||||||
isOpen={isOpen || !!forceOpen}
|
isOpen={isOpen || Boolean(forceOpen)}
|
||||||
className={className || ''}
|
className={className || ''}
|
||||||
positionX={positionX}
|
positionX={positionX}
|
||||||
positionY={positionY}
|
positionY={positionY}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ const Tab: FC<OwnProps> = ({
|
|||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{renderText(title)}
|
{renderText(title)}
|
||||||
{!!badgeCount && (
|
{Boolean(badgeCount) && (
|
||||||
<span className={buildClassName('badge', isBadgeActive && classNames.badgeActive)}>{badgeCount}</span>
|
<span className={buildClassName('badge', isBadgeActive && classNames.badgeActive)}>{badgeCount}</span>
|
||||||
)}
|
)}
|
||||||
<i />
|
<i />
|
||||||
|
|||||||
@ -238,6 +238,8 @@ const foldersReducer: StateReducer<FoldersState, FoldersActions> = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
const useFoldersReducer = () => {
|
||||||
return useReducer(foldersReducer, INITIAL_STATE);
|
return useReducer(foldersReducer, INITIAL_STATE);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useFoldersReducer;
|
||||||
|
|||||||
@ -224,6 +224,8 @@ function getBillingCountry(countryCode: string) {
|
|||||||
return country ? country.name : '';
|
return country ? country.name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
const usePaymentReducer = () => {
|
||||||
return useReducer(reducer, INITIAL_STATE);
|
return useReducer(reducer, INITIAL_STATE);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default usePaymentReducer;
|
||||||
|
|||||||
@ -56,6 +56,8 @@ const twoFaReducer: StateReducer<TwoFaState, TwoFaActions> = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
const useTwoFaReducer = () => {
|
||||||
return useReducer(twoFaReducer, INITIAL_STATE);
|
return useReducer(twoFaReducer, INITIAL_STATE);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useTwoFaReducer;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ type Handler = (e: Event) => void;
|
|||||||
|
|
||||||
const DEFAULT_SKIP_TIME = 10;
|
const DEFAULT_SKIP_TIME = 10;
|
||||||
|
|
||||||
export default (
|
const useAudioPlayer = (
|
||||||
trackId: TrackId,
|
trackId: TrackId,
|
||||||
originalDuration: number, // Sometimes incorrect for voice messages
|
originalDuration: number, // Sometimes incorrect for voice messages
|
||||||
trackType: Track['type'],
|
trackType: Track['type'],
|
||||||
@ -54,7 +54,7 @@ export default (
|
|||||||
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
||||||
setPlaybackState('playing');
|
setPlaybackState('playing');
|
||||||
setVolume(getGlobal().audioPlayer.volume);
|
setVolume(getGlobal().audioPlayer.volume);
|
||||||
toggleMuted(!!getGlobal().audioPlayer.isMuted);
|
toggleMuted(Boolean(getGlobal().audioPlayer.isMuted));
|
||||||
if (trackType === 'voice') {
|
if (trackType === 'voice') {
|
||||||
setPlaybackRate(getGlobal().audioPlayer.playbackRate);
|
setPlaybackRate(getGlobal().audioPlayer.playbackRate);
|
||||||
}
|
}
|
||||||
@ -242,3 +242,5 @@ function makeMediaHandlers(controllerRef: React.RefObject<ReturnType<typeof regi
|
|||||||
}
|
}
|
||||||
return mediaHandlers;
|
return mediaHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useAudioPlayer;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const MIN_READY_STATE = 3;
|
|||||||
// Avoid flickering when re-mounting previously buffered video
|
// Avoid flickering when re-mounting previously buffered video
|
||||||
const DEBOUNCE = 200;
|
const DEBOUNCE = 200;
|
||||||
|
|
||||||
export default (noInitiallyBuffered = false) => {
|
const useBuffering = (noInitiallyBuffered = false) => {
|
||||||
const [isBuffered, setIsBuffered] = useState(!noInitiallyBuffered);
|
const [isBuffered, setIsBuffered] = useState(!noInitiallyBuffered);
|
||||||
const [bufferedProgress, setBufferedProgress] = useState(0);
|
const [bufferedProgress, setBufferedProgress] = useState(0);
|
||||||
|
|
||||||
@ -46,3 +46,5 @@ export default (noInitiallyBuffered = false) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useBuffering;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useState } from '../lib/teact/teact';
|
import { useCallback, useState } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default () => {
|
const useCacheBuster = () => {
|
||||||
const [cacheBuster, setCacheBuster] = useState<boolean>(false);
|
const [cacheBuster, setCacheBuster] = useState<boolean>(false);
|
||||||
|
|
||||||
const updateCacheBuster = useCallback(() => {
|
const updateCacheBuster = useCallback(() => {
|
||||||
@ -9,3 +9,5 @@ export default () => {
|
|||||||
|
|
||||||
return [cacheBuster, updateCacheBuster] as const;
|
return [cacheBuster, updateCacheBuster] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useCacheBuster;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
import { compact } from '../util/iteratees';
|
import { compact } from '../util/iteratees';
|
||||||
import useLang from './useLang';
|
import useLang from './useLang';
|
||||||
|
|
||||||
export default ({
|
const useChatContextActions = ({
|
||||||
chat,
|
chat,
|
||||||
user,
|
user,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
@ -107,3 +107,5 @@ export default ({
|
|||||||
chat, canChangeFolder, lang, handleChatFolderChange, isPinned, isInSearch, isMuted, handleDelete, folderId, isSelf,
|
chat, canChangeFolder, lang, handleChatFolderChange, isPinned, isInSearch, isMuted, handleDelete, folderId, isSelf,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useChatContextActions;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ function stopEvent(e: Event) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (
|
const useContextMenuHandlers = (
|
||||||
elementRef: RefObject<HTMLElement>,
|
elementRef: RefObject<HTMLElement>,
|
||||||
isMenuDisabled?: boolean,
|
isMenuDisabled?: boolean,
|
||||||
shouldDisableOnLink?: boolean,
|
shouldDisableOnLink?: boolean,
|
||||||
@ -140,3 +140,5 @@ export default (
|
|||||||
handleContextMenuHide,
|
handleContextMenuHide,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useContextMenuHandlers;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { CUSTOM_BG_CACHE_NAME } from '../config';
|
|||||||
import * as cacheApi from '../util/cacheApi';
|
import * as cacheApi from '../util/cacheApi';
|
||||||
import { preloadImage } from '../util/files';
|
import { preloadImage } from '../util/files';
|
||||||
|
|
||||||
export default (theme: ThemeKey, settingValue?: string) => {
|
const useCustomBackground = (theme: ThemeKey, settingValue?: string) => {
|
||||||
const [value, setValue] = useState(settingValue);
|
const [value, setValue] = useState(settingValue);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -30,3 +30,5 @@ export default (theme: ThemeKey, settingValue?: string) => {
|
|||||||
|
|
||||||
return settingValue ? value : undefined;
|
return settingValue ? value : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useCustomBackground;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from '../lib/teact/teact';
|
import { useEffect } from '../lib/teact/teact';
|
||||||
import usePrevious from './usePrevious';
|
import usePrevious from './usePrevious';
|
||||||
|
|
||||||
export default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T, debugKey?: string) => {
|
const useEffectWithPrevDeps = <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T, debugKey?: string) => {
|
||||||
const prevDeps = usePrevious<T>(dependencies);
|
const prevDeps = usePrevious<T>(dependencies);
|
||||||
return useEffect(() => {
|
return useEffect(() => {
|
||||||
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
||||||
@ -9,3 +9,5 @@ export default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, dependencies, debugKey);
|
}, dependencies, debugKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useEffectWithPrevDeps;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ApiMessage } from '../api/types';
|
|||||||
|
|
||||||
import { throttle } from '../util/schedulers';
|
import { throttle } from '../util/schedulers';
|
||||||
|
|
||||||
export default (
|
const useEnsureMessage = (
|
||||||
chatId: string,
|
chatId: string,
|
||||||
messageId?: number,
|
messageId?: number,
|
||||||
message?: ApiMessage,
|
message?: ApiMessage,
|
||||||
@ -25,3 +25,5 @@ export default (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useEnsureMessage;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useState } from '../lib/teact/teact';
|
import { useCallback, useState } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (initial = false): [boolean, AnyToVoidFunction, AnyToVoidFunction] => {
|
const useFlag = (initial = false): [boolean, AnyToVoidFunction, AnyToVoidFunction] => {
|
||||||
const [value, setValue] = useState(initial);
|
const [value, setValue] = useState(initial);
|
||||||
|
|
||||||
const setTrue = useCallback(() => {
|
const setTrue = useCallback(() => {
|
||||||
@ -13,3 +13,5 @@ export default (initial = false): [boolean, AnyToVoidFunction, AnyToVoidFunction
|
|||||||
|
|
||||||
return [value, setTrue, setFalse];
|
return [value, setTrue, setFalse];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useFlag;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { useCallback, useState } from '../lib/teact/teact';
|
import { useCallback, useState } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default () => {
|
const useForceUpdate = () => {
|
||||||
const [, setTrigger] = useState<boolean>(false);
|
const [, setTrigger] = useState<boolean>(false);
|
||||||
|
|
||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
setTrigger((trigger) => !trigger);
|
setTrigger((trigger) => !trigger);
|
||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useForceUpdate;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ let isAnimating = false;
|
|||||||
// Make sure to end even if end callback was not called (which was some hardly-reproducible bug)
|
// Make sure to end even if end callback was not called (which was some hardly-reproducible bug)
|
||||||
const AUTO_END_TIMEOUT = 1000;
|
const AUTO_END_TIMEOUT = 1000;
|
||||||
|
|
||||||
export default (
|
const useHeavyAnimationCheck = (
|
||||||
handleAnimationStart: AnyToVoidFunction,
|
handleAnimationStart: AnyToVoidFunction,
|
||||||
handleAnimationEnd: AnyToVoidFunction,
|
handleAnimationEnd: AnyToVoidFunction,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
@ -63,3 +63,5 @@ export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
|
|||||||
|
|
||||||
return onEnd;
|
return onEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useHeavyAnimationCheck;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect } from '../lib/teact/teact';
|
import { useEffect } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (container: HTMLElement | null, isDisabled?: boolean) => {
|
const useHorizontalScroll = (container: HTMLElement | null, isDisabled?: boolean) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!container || isDisabled) {
|
if (!container || isDisabled) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -20,3 +20,5 @@ export default (container: HTMLElement | null, isDisabled?: boolean) => {
|
|||||||
};
|
};
|
||||||
}, [container, isDisabled]);
|
}, [container, isDisabled]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useHorizontalScroll;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ type LoadMoreBackwards = (args: { offsetId?: string | number }) => void;
|
|||||||
|
|
||||||
const DEFAULT_LIST_SLICE = 30;
|
const DEFAULT_LIST_SLICE = 30;
|
||||||
|
|
||||||
export default <ListId extends string | number>(
|
const useInfiniteScroll = <ListId extends string | number>(
|
||||||
loadMoreBackwards?: LoadMoreBackwards,
|
loadMoreBackwards?: LoadMoreBackwards,
|
||||||
listIds?: ListId[],
|
listIds?: ListId[],
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
@ -120,3 +120,5 @@ function getViewportSlice<ListId extends string | number>(
|
|||||||
|
|
||||||
return { newViewportIds, areSomeLocal, areAllLocal };
|
return { newViewportIds, areSomeLocal, areAllLocal };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useInfiniteScroll;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
import { useState, useCallback, useEffect } from '../lib/teact/teact';
|
import { useState, useCallback, useEffect } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (
|
const useKeyboardListNavigation = (
|
||||||
elementRef: RefObject<HTMLElement>,
|
elementRef: RefObject<HTMLElement>,
|
||||||
isOpen: boolean,
|
isOpen: boolean,
|
||||||
onSelectWithEnter?: (index: number) => void,
|
onSelectWithEnter?: (index: number) => void,
|
||||||
@ -60,3 +60,5 @@ export default (
|
|||||||
|
|
||||||
return handleKeyDown;
|
return handleKeyDown;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useKeyboardListNavigation;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import useOnChange from './useOnChange';
|
|||||||
|
|
||||||
export type LangFn = typeof langProvider.getTranslation;
|
export type LangFn = typeof langProvider.getTranslation;
|
||||||
|
|
||||||
export default (): LangFn => {
|
const useLang = (): LangFn => {
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
|
|
||||||
useOnChange(() => {
|
useOnChange(() => {
|
||||||
@ -13,3 +13,5 @@ export default (): LangFn => {
|
|||||||
|
|
||||||
return langProvider.getTranslation;
|
return langProvider.getTranslation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useLang;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import * as langProvider from '../util/langProvider';
|
import * as langProvider from '../util/langProvider';
|
||||||
import { useState } from '../lib/teact/teact';
|
import { useState } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (langCode: string | undefined, key: string): string | undefined => {
|
const useLangString = (langCode: string | undefined, key: string): string | undefined => {
|
||||||
const [translation, setTranslation] = useState<string>();
|
const [translation, setTranslation] = useState<string>();
|
||||||
|
|
||||||
if (langCode) {
|
if (langCode) {
|
||||||
@ -12,3 +12,5 @@ export default (langCode: string | undefined, key: string): string | undefined =
|
|||||||
|
|
||||||
return translation;
|
return translation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useLangString;
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { useLayoutEffect } from '../lib/teact/teact';
|
import { useLayoutEffect } from '../lib/teact/teact';
|
||||||
import usePrevious from './usePrevious';
|
import usePrevious from './usePrevious';
|
||||||
|
|
||||||
export default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T, debugKey?: string) => {
|
const useLayoutEffectWithPrevDeps = <T extends any[], PT = T>(
|
||||||
|
cb: (args: PT) => void, dependencies: T, debugKey?: string,
|
||||||
|
) => {
|
||||||
const prevDeps = usePrevious<T>(dependencies);
|
const prevDeps = usePrevious<T>(dependencies);
|
||||||
return useLayoutEffect(() => {
|
return useLayoutEffect(() => {
|
||||||
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
||||||
@ -9,3 +11,5 @@ export default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, dependencies, debugKey);
|
}, dependencies, debugKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useLayoutEffectWithPrevDeps;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ApiMediaFormat } from '../api/types';
|
|||||||
import * as mediaLoader from '../util/mediaLoader';
|
import * as mediaLoader from '../util/mediaLoader';
|
||||||
import useForceUpdate from './useForceUpdate';
|
import useForceUpdate from './useForceUpdate';
|
||||||
|
|
||||||
export default <T extends ApiMediaFormat = ApiMediaFormat.BlobUrl>(
|
const useMedia = <T extends ApiMediaFormat = ApiMediaFormat.BlobUrl>(
|
||||||
mediaHash: string | false | undefined,
|
mediaHash: string | false | undefined,
|
||||||
noLoad = false,
|
noLoad = false,
|
||||||
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
||||||
@ -33,3 +33,5 @@ export default <T extends ApiMediaFormat = ApiMediaFormat.BlobUrl>(
|
|||||||
|
|
||||||
return mediaData;
|
return mediaData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useMedia;
|
||||||
|
|||||||
@ -21,7 +21,9 @@ const LOGO_DIMENSIONS = { width: 200, height: 200 };
|
|||||||
const MINIMAL_SIZE = 115; // spec says 100, but on Chrome 93 it's not showing
|
const MINIMAL_SIZE = 115; // spec says 100, but on Chrome 93 it's not showing
|
||||||
|
|
||||||
// TODO Add support for video in future
|
// TODO Add support for video in future
|
||||||
export default (message: ApiMessage, sender?: ApiUser | ApiChat, chat?: ApiChat): MediaMetadata | undefined => {
|
const useMessageMediaMetadata = (
|
||||||
|
message: ApiMessage, sender?: ApiUser | ApiChat, chat?: ApiChat,
|
||||||
|
): MediaMetadata | undefined => {
|
||||||
const { audio, voice } = getMessageContent(message);
|
const { audio, voice } = getMessageContent(message);
|
||||||
const title = audio ? (audio.title || audio.fileName) : voice ? 'Voice message' : '';
|
const title = audio ? (audio.title || audio.fileName) : voice ? 'Voice message' : '';
|
||||||
const artist = (audio && audio.performer) || (sender && getSenderTitle(getTranslation, sender));
|
const artist = (audio && audio.performer) || (sender && getSenderTitle(getTranslation, sender));
|
||||||
@ -71,3 +73,5 @@ function getCoverSize(audio?: ApiAudio, voice?: ApiVoice, url?: string) {
|
|||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useMessageMediaMetadata;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
|
|
||||||
import useForceUpdate from './useForceUpdate';
|
import useForceUpdate from './useForceUpdate';
|
||||||
|
|
||||||
export default <B extends Bundles, M extends BundleModules<B>>(
|
const useModuleLoader = <B extends Bundles, M extends BundleModules<B>>(
|
||||||
bundleName: B, moduleName: M, noLoad = false, autoUpdate = false,
|
bundleName: B, moduleName: M, noLoad = false, autoUpdate = false,
|
||||||
) => {
|
) => {
|
||||||
const module = getModuleFromMemory(bundleName, moduleName);
|
const module = getModuleFromMemory(bundleName, moduleName);
|
||||||
@ -28,3 +28,5 @@ export default <B extends Bundles, M extends BundleModules<B>>(
|
|||||||
|
|
||||||
return module;
|
return module;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useModuleLoader;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import usePrevious from './usePrevious';
|
import usePrevious from './usePrevious';
|
||||||
|
|
||||||
export default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T) => {
|
const useOnChange = <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T) => {
|
||||||
const prevDeps = usePrevious<T>(dependencies);
|
const prevDeps = usePrevious<T>(dependencies);
|
||||||
if (!prevDeps || dependencies.some((d, i) => d !== prevDeps[i])) {
|
if (!prevDeps || dependencies.some((d, i) => d !== prevDeps[i])) {
|
||||||
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
// @ts-ignore (workaround for "could be instantiated with a different subtype" issue)
|
||||||
cb(prevDeps || []);
|
cb(prevDeps || []);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useOnChange;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useEffect, useRef } from '../lib/teact/teact';
|
import { useCallback, useEffect, useRef } from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (
|
const useSendWithEnter = (
|
||||||
onSelect: NoneToVoidFunction,
|
onSelect: NoneToVoidFunction,
|
||||||
) => {
|
) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
@ -23,3 +23,5 @@ export default (
|
|||||||
|
|
||||||
return buttonRef;
|
return buttonRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useSendWithEnter;
|
||||||
|
|||||||
@ -6,10 +6,12 @@ import { ApiSendMessageAction } from '../api/types';
|
|||||||
import { SEND_MESSAGE_ACTION_INTERVAL } from '../config';
|
import { SEND_MESSAGE_ACTION_INTERVAL } from '../config';
|
||||||
import { throttle } from '../util/schedulers';
|
import { throttle } from '../util/schedulers';
|
||||||
|
|
||||||
export default (chatId: string, threadId?: number) => {
|
const useSendMessageAction = (chatId: string, threadId?: number) => {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return throttle((action: ApiSendMessageAction) => {
|
return throttle((action: ApiSendMessageAction) => {
|
||||||
getDispatch().sendMessageAction({ chatId, threadId, action });
|
getDispatch().sendMessageAction({ chatId, threadId, action });
|
||||||
}, SEND_MESSAGE_ACTION_INTERVAL);
|
}, SEND_MESSAGE_ACTION_INTERVAL);
|
||||||
}, [chatId, threadId]);
|
}, [chatId, threadId]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useSendMessageAction;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import buildClassName from '../util/buildClassName';
|
|||||||
|
|
||||||
const CLOSE_DURATION = 350;
|
const CLOSE_DURATION = 350;
|
||||||
|
|
||||||
export default (
|
const useShowTransition = (
|
||||||
isOpen = false,
|
isOpen = false,
|
||||||
onCloseTransitionEnd?: () => void,
|
onCloseTransitionEnd?: () => void,
|
||||||
noOpenTransition = false,
|
noOpenTransition = false,
|
||||||
@ -62,3 +62,5 @@ export default (
|
|||||||
transitionClassNames,
|
transitionClassNames,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useShowTransition;
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import { useMemo } from '../lib/teact/teact';
|
|||||||
|
|
||||||
import { throttle } from '../util/schedulers';
|
import { throttle } from '../util/schedulers';
|
||||||
|
|
||||||
export default (ms: number, noFirst = false) => {
|
const useThrottle = (ms: number, noFirst = false) => {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return throttle((cb) => cb(), ms, !noFirst);
|
return throttle((cb) => cb(), ms, !noFirst);
|
||||||
}, [ms, noFirst]);
|
}, [ms, noFirst]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useThrottle;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import generateIdFor from '../util/generateIdFor';
|
|||||||
|
|
||||||
const store: Record<string, boolean> = {};
|
const store: Record<string, boolean> = {};
|
||||||
|
|
||||||
export default () => {
|
const useUniqueId = () => {
|
||||||
const idRef = useRef<string>();
|
const idRef = useRef<string>();
|
||||||
|
|
||||||
if (!idRef.current) {
|
if (!idRef.current) {
|
||||||
@ -13,3 +13,5 @@ export default () => {
|
|||||||
|
|
||||||
return idRef.current;
|
return idRef.current;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useUniqueId;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { ApiDimensions } from '../api/types';
|
|||||||
|
|
||||||
const THROTTLE = 250;
|
const THROTTLE = 250;
|
||||||
|
|
||||||
export default () => {
|
const useWindowSize = () => {
|
||||||
const [size, setSize] = useState<ApiDimensions>(windowSize.get());
|
const [size, setSize] = useState<ApiDimensions>(windowSize.get());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -23,3 +23,5 @@ export default () => {
|
|||||||
|
|
||||||
return size;
|
return size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default useWindowSize;
|
||||||
|
|||||||
@ -594,7 +594,7 @@ Duplicate ?
|
|||||||
function isListLike(item) {
|
function isListLike(item) {
|
||||||
return (
|
return (
|
||||||
Array.isArray(item) ||
|
Array.isArray(item) ||
|
||||||
(!!item &&
|
(Boolean(item) &&
|
||||||
typeof item === 'object' &&
|
typeof item === 'object' &&
|
||||||
typeof (item.length) === 'number' &&
|
typeof (item.length) === 'number' &&
|
||||||
(item.length === 0 ||
|
(item.length === 0 ||
|
||||||
|
|||||||
@ -112,7 +112,7 @@ export async function updateTwoFaSettings(
|
|||||||
|
|
||||||
await client.invoke(new Api.account.ConfirmPasswordEmail({ code }));
|
await client.invoke(new Api.account.ConfirmPasswordEmail({ code }));
|
||||||
break;
|
break;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
onEmailCodeError!(err);
|
onEmailCodeError!(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -369,7 +369,7 @@ class TelegramClient {
|
|||||||
|
|
||||||
async _connectSender(sender, dcId) {
|
async _connectSender(sender, dcId) {
|
||||||
// if we don't already have an auth key we want to use normal DCs not -1
|
// if we don't already have an auth key we want to use normal DCs not -1
|
||||||
const dc = utils.getDC(dcId, !!sender.authKey.getKey());
|
const dc = utils.getDC(dcId, Boolean(sender.authKey.getKey()));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -54,7 +54,7 @@ export async function checkAuthorization(client: TelegramClient) {
|
|||||||
try {
|
try {
|
||||||
await client.invoke(new Api.updates.GetState());
|
await client.invoke(new Api.updates.GetState());
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if (e.message === 'Disconnect') throw e;
|
if (e.message === 'Disconnect') throw e;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ async function signInUser(
|
|||||||
if (typeof authParams.phoneNumber === 'function') {
|
if (typeof authParams.phoneNumber === 'function') {
|
||||||
try {
|
try {
|
||||||
phoneNumber = await authParams.phoneNumber();
|
phoneNumber = await authParams.phoneNumber();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'RESTART_AUTH_WITH_QR') {
|
if (err.message === 'RESTART_AUTH_WITH_QR') {
|
||||||
return signInUserWithQrCode(client, apiCredentials, authParams);
|
return signInUserWithQrCode(client, apiCredentials, authParams);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ async function signInUser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (typeof authParams.phoneNumber !== 'function') {
|
if (typeof authParams.phoneNumber !== 'function') {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ async function signInUser(
|
|||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
phoneCode = await authParams.phoneCode(isCodeViaApp);
|
phoneCode = await authParams.phoneCode(isCodeViaApp);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// This is the support for changing phone number from the phone code screen.
|
// This is the support for changing phone number from the phone code screen.
|
||||||
if (err.message === 'RESTART_AUTH') {
|
if (err.message === 'RESTART_AUTH') {
|
||||||
return signInUser(client, apiCredentials, authParams);
|
return signInUser(client, apiCredentials, authParams);
|
||||||
@ -136,7 +136,7 @@ async function signInUser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result.user;
|
return result.user;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'SESSION_PASSWORD_NEEDED') {
|
if (err.message === 'SESSION_PASSWORD_NEEDED') {
|
||||||
return signInWithPassword(client, apiCredentials, authParams);
|
return signInWithPassword(client, apiCredentials, authParams);
|
||||||
} else {
|
} else {
|
||||||
@ -167,7 +167,7 @@ async function signInUser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
authParams.onError(err);
|
authParams.onError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ async function signInUserWithQrCode(
|
|||||||
// Either we receive an update that QR is successfully scanned,
|
// Either we receive an update that QR is successfully scanned,
|
||||||
// or we receive a rejection caused by user going back to the regular auth form
|
// or we receive a rejection caused by user going back to the regular auth form
|
||||||
await Promise.race([updatePromise, inputPromise]);
|
await Promise.race([updatePromise, inputPromise]);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'RESTART_AUTH') {
|
if (err.message === 'RESTART_AUTH') {
|
||||||
return await signInUser(client, apiCredentials, authParams);
|
return await signInUser(client, apiCredentials, authParams);
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ async function signInUserWithQrCode(
|
|||||||
return migratedResult.authorization.user;
|
return migratedResult.authorization.user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'SESSION_PASSWORD_NEEDED') {
|
if (err.message === 'SESSION_PASSWORD_NEEDED') {
|
||||||
return signInWithPassword(client, apiCredentials, authParams);
|
return signInWithPassword(client, apiCredentials, authParams);
|
||||||
}
|
}
|
||||||
@ -258,7 +258,7 @@ async function signInUserWithQrCode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a workaround for TypeScript (never actually reached)
|
// This is a workaround for TypeScript (never actually reached)
|
||||||
// eslint-disable-next-line no-throw-literal
|
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||||
throw undefined;
|
throw undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ async function sendCode(
|
|||||||
phoneCodeHash: resendResult.phoneCodeHash,
|
phoneCodeHash: resendResult.phoneCodeHash,
|
||||||
isCodeViaApp: resendResult.type instanceof Api.auth.SentCodeTypeApp,
|
isCodeViaApp: resendResult.type instanceof Api.auth.SentCodeTypeApp,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message === 'AUTH_RESTART') {
|
if (err.message === 'AUTH_RESTART') {
|
||||||
return sendCode(client, apiCredentials, phoneNumber, forceSMS);
|
return sendCode(client, apiCredentials, phoneNumber, forceSMS);
|
||||||
} else {
|
} else {
|
||||||
@ -321,7 +321,7 @@ async function signInWithPassword(
|
|||||||
})) as Api.auth.Authorization;
|
})) as Api.auth.Authorization;
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
authParams.onError(err);
|
authParams.onError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -480,4 +480,5 @@ function DEBUG_addToVirtualTreeSize($current: VirtualRealElement | VirtualDomHea
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { render };
|
const TeactDOM = { render };
|
||||||
|
export default TeactDOM;
|
||||||
|
|||||||
@ -298,7 +298,7 @@ export function renderComponent(componentInstance: ComponentInstance) {
|
|||||||
DEBUG_components[componentName].renderTimes.push(duration);
|
DEBUG_components[componentName].renderTimes.push(duration);
|
||||||
DEBUG_components[componentName].renderCount++;
|
DEBUG_components[componentName].renderCount++;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
|
|
||||||
newRenderedValue = componentInstance.renderedValue;
|
newRenderedValue = componentInstance.renderedValue;
|
||||||
@ -382,7 +382,7 @@ function unmountComponent(componentInstance: ComponentInstance) {
|
|||||||
if (typeof cleanup === 'function') {
|
if (typeof cleanup === 'function') {
|
||||||
try {
|
try {
|
||||||
cleanup();
|
cleanup();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,7 +552,7 @@ function useLayoutEffectBase(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,7 +698,9 @@ export function memo<T extends FC>(Component: T, areEqual = arePropsShallowEqual
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need to keep it here for JSX.
|
// We need to keep it here for JSX.
|
||||||
export default {
|
const Teact = {
|
||||||
createElement,
|
createElement,
|
||||||
Fragment,
|
Fragment,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Teact;
|
||||||
|
|||||||
@ -99,7 +99,7 @@ function updateContainers() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
newMappedProps = mapStateToProps(currentGlobal, ownProps);
|
newMappedProps = mapStateToProps(currentGlobal, ownProps);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -205,7 +205,7 @@ export function withGlobal<OwnProps>(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
container.mappedProps = mapStateToProps(currentGlobal, props);
|
container.mappedProps = mapStateToProps(currentGlobal, props);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
handleError(err);
|
handleError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -713,7 +713,7 @@ addReducer('updateChatMemberBannedRights', (global, actions, payload) => {
|
|||||||
|
|
||||||
const { members, kickedMembers } = chatAfterUpdate.fullInfo;
|
const { members, kickedMembers } = chatAfterUpdate.fullInfo;
|
||||||
|
|
||||||
const isBanned = !!bannedRights.viewMessages;
|
const isBanned = Boolean(bannedRights.viewMessages);
|
||||||
const isUnblocked = !Object.keys(bannedRights).length;
|
const isUnblocked = !Object.keys(bannedRights).length;
|
||||||
|
|
||||||
setGlobal(updateChat(newGlobal, chatId, {
|
setGlobal(updateChat(newGlobal, chatId, {
|
||||||
@ -1184,7 +1184,7 @@ async function createGroupChat(title: string, users: ApiUser[], photo?: File) {
|
|||||||
photo,
|
photo,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if (e.message === 'USERS_TOO_FEW') {
|
if (e.message === 'USERS_TOO_FEW') {
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
setGlobal({
|
setGlobal({
|
||||||
|
|||||||
@ -44,7 +44,7 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
|
|||||||
participants.forEach((participant) => {
|
participants.forEach((participant) => {
|
||||||
if (participant.id) {
|
if (participant.id) {
|
||||||
global = updateGroupCallParticipant(global, groupCallId, participant.id, participant,
|
global = updateGroupCallParticipant(global, groupCallId, participant.id, participant,
|
||||||
!!nextOffset || currentUserId === participant.id);
|
Boolean(nextOffset) || currentUserId === participant.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (nextOffset) {
|
if (nextOffset) {
|
||||||
|
|||||||
@ -158,7 +158,7 @@ addReducer('createGroupCallInviteLink', (global, actions) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canInvite = !!chat && !!chat.username;
|
const canInvite = Boolean(chat.username);
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
let { inviteLink } = chat.fullInfo!;
|
let { inviteLink } = chat.fullInfo!;
|
||||||
|
|||||||
@ -360,9 +360,9 @@ function filterChatFolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type === 'chatTypeChannel') {
|
} else if (type === 'chatTypeChannel') {
|
||||||
return !!folder.channels;
|
return Boolean(folder.channels);
|
||||||
} else if (type === 'chatTypeBasicGroup' || type === 'chatTypeSuperGroup') {
|
} else if (type === 'chatTypeBasicGroup' || type === 'chatTypeSuperGroup') {
|
||||||
return !!folder.groups;
|
return Boolean(folder.groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -144,7 +144,7 @@ export function isForwardedMessage(message: ApiMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isActionMessage(message: ApiMessage) {
|
export function isActionMessage(message: ApiMessage) {
|
||||||
return !!message.content.action;
|
return Boolean(message.content.action);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isServiceNotificationMessage(message: ApiMessage) {
|
export function isServiceNotificationMessage(message: ApiMessage) {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export function selectIsAdminInActiveGroupCall(global: GlobalState): boolean {
|
|||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) return false;
|
if (!chat) return false;
|
||||||
|
|
||||||
return (isChatBasicGroup(chat) && chat.isCreator) || !!chat.adminRights?.manageCall;
|
return (isChatBasicGroup(chat) && chat.isCreator) || Boolean(chat.adminRights?.manageCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectActiveGroupCall(global: GlobalState) {
|
export function selectActiveGroupCall(global: GlobalState) {
|
||||||
|
|||||||
@ -133,17 +133,17 @@ export function selectIsChatPinned(global: GlobalState, chatId: string, folderId
|
|||||||
const { active, archived } = global.chats.orderedPinnedIds;
|
const { active, archived } = global.chats.orderedPinnedIds;
|
||||||
|
|
||||||
if (folderId === ALL_FOLDER_ID) {
|
if (folderId === ALL_FOLDER_ID) {
|
||||||
return !!active && active.includes(chatId);
|
return Boolean(active?.includes(chatId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderId === ARCHIVED_FOLDER_ID) {
|
if (folderId === ARCHIVED_FOLDER_ID) {
|
||||||
return !!archived && archived.includes(chatId);
|
return Boolean(archived?.includes(chatId));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { byId: chatFoldersById } = global.chatFolders;
|
const { byId: chatFoldersById } = global.chatFolders;
|
||||||
|
|
||||||
const { pinnedChatIds } = chatFoldersById[folderId] || {};
|
const { pinnedChatIds } = chatFoldersById[folderId] || {};
|
||||||
return !!pinnedChatIds && pinnedChatIds.includes(chatId);
|
return Boolean(pinnedChatIds?.includes(chatId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slow, not to be used in `withGlobal`
|
// Slow, not to be used in `withGlobal`
|
||||||
|
|||||||
@ -253,6 +253,6 @@ export function handleClientMessage(e: ExtendableMessageEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.onsync = () => {
|
self.addEventListener('sync', () => {
|
||||||
lastSyncAt = new Date().valueOf();
|
lastSyncAt = Date.now();
|
||||||
};
|
});
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
export default {
|
const oggToWav = {
|
||||||
oggToWav() {
|
oggToWav() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default oggToWav;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
export default {
|
const webpToPng = {
|
||||||
webpToPng() {
|
webpToPng() {
|
||||||
},
|
},
|
||||||
webpToPngBase64() {
|
webpToPngBase64() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default webpToPng;
|
||||||
|
|||||||
@ -51,8 +51,8 @@ async function copyBlobToClipboard(pngBlob: Blob | null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.write([
|
await navigator.clipboard.write?.([
|
||||||
new window.ClipboardItem({
|
new ClipboardItem({
|
||||||
[pngBlob.type]: pngBlob,
|
[pngBlob.type]: pngBlob,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export default function createInterface(api: Record<string, Function>) {
|
|||||||
arrayBuffers,
|
arrayBuffers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export default (store: AnyLiteral) => {
|
const generateIdFor = (store: AnyLiteral) => {
|
||||||
let id;
|
let id;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -7,3 +7,5 @@ export default (store: AnyLiteral) => {
|
|||||||
|
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default generateIdFor;
|
||||||
|
|||||||
@ -4,7 +4,10 @@ export function scaleImage(image: string | Blob, ratio: number, outputType: stri
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
scale(img, img.width * ratio, img.height * ratio, outputType)
|
scale(img, img.width * ratio, img.height * ratio, outputType)
|
||||||
.then((blob) => URL.createObjectURL(blob))
|
.then((blob) => {
|
||||||
|
if (!blob) throw new Error('Image resize failed!');
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
})
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (image instanceof Blob) {
|
if (image instanceof Blob) {
|
||||||
@ -24,7 +27,10 @@ export function resizeImage(
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
scale(img, width, height, outputType)
|
scale(img, width, height, outputType)
|
||||||
.then((blob) => URL.createObjectURL(blob))
|
.then((blob) => {
|
||||||
|
if (!blob) throw new Error('Image resize failed!');
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
})
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (image instanceof Blob) {
|
if (image instanceof Blob) {
|
||||||
@ -38,7 +44,7 @@ export function resizeImage(
|
|||||||
|
|
||||||
async function scale(
|
async function scale(
|
||||||
img: HTMLImageElement, width: number, height: number, outputType: string = 'image/png',
|
img: HTMLImageElement, width: number, height: number, outputType: string = 'image/png',
|
||||||
) {
|
): Promise<Blob | null> {
|
||||||
// Safari does not have built-in resize method with quality control
|
// Safari does not have built-in resize method with quality control
|
||||||
if ('createImageBitmap' in window) {
|
if ('createImageBitmap' in window) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -95,7 +95,7 @@ export function unique<T extends any>(array: T[]): T[] {
|
|||||||
return Array.from(new Set(array));
|
return Array.from(new Set(array));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compact(array: any[]) {
|
export function compact<T extends any>(array: T[]) {
|
||||||
return array.filter(Boolean);
|
return array.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -213,7 +213,7 @@ export async function subscribe() {
|
|||||||
await callApi('registerDevice', deviceToken);
|
await callApi('registerDevice', deviceToken);
|
||||||
getDispatch()
|
getDispatch()
|
||||||
.setDeviceToken(deviceToken);
|
.setDeviceToken(deviceToken);
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
if (Notification.permission === 'denied' as NotificationPermission) {
|
if (Notification.permission === 'denied' as NotificationPermission) {
|
||||||
// The user denied the notification permission which
|
// The user denied the notification permission which
|
||||||
// means we failed to subscribe and the user will need
|
// means we failed to subscribe and the user will need
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { IS_IOS } from './environment';
|
import { IS_IOS } from './environment';
|
||||||
import forceReflow from './forceReflow';
|
import forceReflow from './forceReflow';
|
||||||
|
|
||||||
export default (container: HTMLDivElement, scrollTop?: number) => {
|
const resetScroll = (container: HTMLDivElement, scrollTop?: number) => {
|
||||||
if (IS_IOS) {
|
if (IS_IOS) {
|
||||||
container.style.overflow = 'hidden';
|
container.style.overflow = 'hidden';
|
||||||
}
|
}
|
||||||
@ -21,3 +21,5 @@ export function patchChromiumScroll(element: HTMLElement) {
|
|||||||
forceReflow(element);
|
forceReflow(element);
|
||||||
element.style.display = '';
|
element.style.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default resetScroll;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const parseLocationHash = (value: string): MessageList | undefined => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
chatId,
|
chatId,
|
||||||
type: !!typeOrThreadId && isType ? (typeOrThreadId as MessageListType) : 'thread',
|
type: Boolean(typeOrThreadId) && isType ? (typeOrThreadId as MessageListType) : 'thread',
|
||||||
threadId: !!typeOrThreadId && !isType ? Number(typeOrThreadId) : MAIN_THREAD_ID,
|
threadId: Boolean(typeOrThreadId) && !isType ? Number(typeOrThreadId) : MAIN_THREAD_ID,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DEBUG } from '../config';
|
import { DEBUG } from '../config';
|
||||||
|
|
||||||
export default (mediaEl: HTMLMediaElement) => {
|
const safePlay = (mediaEl: HTMLMediaElement) => {
|
||||||
mediaEl.play().catch((err) => {
|
mediaEl.play().catch((err) => {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@ -8,3 +8,5 @@ export default (mediaEl: HTMLMediaElement) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default safePlay;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React from '../lib/teact/teact';
|
import React from '../lib/teact/teact';
|
||||||
|
|
||||||
export default (e: React.UIEvent | Event) => {
|
const stopEvent = (e: React.UIEvent | Event) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default stopEvent;
|
||||||
|
|||||||
@ -31,7 +31,7 @@ const colors = (Object.keys(themeColors) as Array<keyof typeof themeColors>).map
|
|||||||
colors: [hexToRgb(themeColors[property][0]), hexToRgb(themeColors[property][1])],
|
colors: [hexToRgb(themeColors[property][0]), hexToRgb(themeColors[property][1])],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default (theme: ISettings['theme'], withAnimation: boolean) => {
|
const switchTheme = (theme: ISettings['theme'], withAnimation: boolean) => {
|
||||||
const isDarkTheme = theme === 'dark';
|
const isDarkTheme = theme === 'dark';
|
||||||
const shouldAnimate = isInitialized && withAnimation;
|
const shouldAnimate = isInitialized && withAnimation;
|
||||||
const startIndex = isDarkTheme ? 0 : 1;
|
const startIndex = isDarkTheme ? 0 : 1;
|
||||||
@ -102,3 +102,5 @@ function applyColorAnimationStep(startIndex: number, endIndex: number, interpola
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default switchTheme;
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const forceWebsync = (authed: boolean) => {
|
|||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
|
|
||||||
const removeElement = () => !!document.body.removeChild(script);
|
const removeElement = () => Boolean(document.body.removeChild(script));
|
||||||
|
|
||||||
script.src = url + new URLSearchParams({
|
script.src = url + new URLSearchParams({
|
||||||
authed: Number(authed).toString(),
|
authed: Number(authed).toString(),
|
||||||
|
|||||||
@ -14,7 +14,7 @@ type IDimensions = {
|
|||||||
const IS_LANDSCAPE = IS_SINGLE_COLUMN_LAYOUT && isLandscape();
|
const IS_LANDSCAPE = IS_SINGLE_COLUMN_LAYOUT && isLandscape();
|
||||||
|
|
||||||
const initialHeight = window.innerHeight;
|
const initialHeight = window.innerHeight;
|
||||||
let windowSize = updateSizes();
|
let currentWindowSize = updateSizes();
|
||||||
let isRefreshDisabled = false;
|
let isRefreshDisabled = false;
|
||||||
|
|
||||||
function disableRefresh() {
|
function disableRefresh() {
|
||||||
@ -26,7 +26,7 @@ function enableRefresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleResize = throttle(() => {
|
const handleResize = throttle(() => {
|
||||||
windowSize = updateSizes();
|
currentWindowSize = updateSizes();
|
||||||
|
|
||||||
if (!isRefreshDisabled && (
|
if (!isRefreshDisabled && (
|
||||||
isMobileScreen() !== IS_SINGLE_COLUMN_LAYOUT
|
isMobileScreen() !== IS_SINGLE_COLUMN_LAYOUT
|
||||||
@ -61,8 +61,9 @@ export function updateSizes(): IDimensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isMobileScreen() {
|
function isMobileScreen() {
|
||||||
return windowSize.width <= MOBILE_SCREEN_MAX_WIDTH || (
|
return currentWindowSize.width <= MOBILE_SCREEN_MAX_WIDTH || (
|
||||||
windowSize.width <= MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH && windowSize.height <= MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT
|
currentWindowSize.width <= MOBILE_SCREEN_LANDSCAPE_MAX_WIDTH
|
||||||
|
&& currentWindowSize.height <= MOBILE_SCREEN_LANDSCAPE_MAX_HEIGHT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +79,11 @@ function isLandscape() {
|
|||||||
return window.matchMedia('screen and (min-device-aspect-ratio: 1/1) and (orientation: landscape)').matches;
|
return window.matchMedia('screen and (min-device-aspect-ratio: 1/1) and (orientation: landscape)').matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
const windowSize = {
|
||||||
get: () => windowSize,
|
get: () => currentWindowSize,
|
||||||
getIsKeyboardVisible: () => initialHeight > windowSize.height,
|
getIsKeyboardVisible: () => initialHeight > currentWindowSize.height,
|
||||||
disableRefresh,
|
disableRefresh,
|
||||||
enableRefresh,
|
enableRefresh,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default windowSize;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// We don't care about this since Parcel runs Babel after TypeScript
|
// We don't care about this since Webpack runs Babel after TypeScript
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
|
|||||||
@ -19,18 +19,32 @@ module.exports = (env = {}, argv = {}) => {
|
|||||||
entry: './src/index.tsx',
|
entry: './src/index.tsx',
|
||||||
target: 'web',
|
target: 'web',
|
||||||
devServer: {
|
devServer: {
|
||||||
contentBase: [
|
|
||||||
path.resolve(__dirname, 'public'),
|
|
||||||
path.resolve(__dirname, 'node_modules/emoji-data-ios'),
|
|
||||||
path.resolve(__dirname, 'node_modules/opus-recorder/dist'),
|
|
||||||
path.resolve(__dirname, 'src/lib/webp'),
|
|
||||||
path.resolve(__dirname, 'src/lib/rlottie'),
|
|
||||||
path.resolve(__dirname, 'src/lib/secret-sauce'),
|
|
||||||
],
|
|
||||||
port: 1234,
|
port: 1234,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
disableHostCheck: true,
|
allowedHosts: "all",
|
||||||
stats: 'minimal'
|
static: [
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'public'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'node_modules/emoji-data-ios'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'node_modules/opus-recorder/dist'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'src/lib/webp'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'src/lib/rlottie'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
directory: path.resolve(__dirname, 'src/lib/secret-sauce'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
devMiddleware: {
|
||||||
|
stats: 'minimal',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].[contenthash].js',
|
filename: '[name].[contenthash].js',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user