Introduce Multi-Accounts
This commit is contained in:
parent
65e0d05ac4
commit
a6f8f232a8
@ -11,9 +11,10 @@ function compatTest() {
|
|||||||
var hasNumberFormat = hasIntl && typeof Intl.NumberFormat !== 'undefined';
|
var hasNumberFormat = hasIntl && typeof Intl.NumberFormat !== 'undefined';
|
||||||
var hasWebLocks = typeof navigator.locks !== 'undefined';
|
var hasWebLocks = typeof navigator.locks !== 'undefined';
|
||||||
var hasBigInt = typeof BigInt !== 'undefined';
|
var hasBigInt = typeof BigInt !== 'undefined';
|
||||||
|
var hasBroadcastChannel = typeof BroadcastChannel !== 'undefined';
|
||||||
|
|
||||||
var isCompatible = hasPromise && hasWebSockets && hasWebCrypto && hasObjectFromEntries && hasResizeObserver
|
var isCompatible = hasPromise && hasWebSockets && hasWebCrypto && hasObjectFromEntries && hasResizeObserver
|
||||||
&& hasCssSupports && hasDisplayNames && hasPluralRules && hasNumberFormat && hasWebLocks && hasBigInt;
|
&& hasCssSupports && hasDisplayNames && hasPluralRules && hasNumberFormat && hasWebLocks && hasBigInt && hasBroadcastChannel;
|
||||||
|
|
||||||
if (isCompatible || (window.localStorage && window.localStorage.getItem('tt-ignore-compat'))) {
|
if (isCompatible || (window.localStorage && window.localStorage.getItem('tt-ignore-compat'))) {
|
||||||
window.isCompatTestPassed = true;
|
window.isCompatTestPassed = true;
|
||||||
@ -33,6 +34,7 @@ function compatTest() {
|
|||||||
console.warn('Intl.NumberFormat', hasNumberFormat);
|
console.warn('Intl.NumberFormat', hasNumberFormat);
|
||||||
console.warn('WebLocks', hasWebLocks);
|
console.warn('WebLocks', hasWebLocks);
|
||||||
console.warn('BigInt', hasBigInt);
|
console.warn('BigInt', hasBigInt);
|
||||||
|
console.warn('BroadcastChannel', hasBroadcastChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hardcoded page because server forbids iframe embedding
|
// Hardcoded page because server forbids iframe embedding
|
||||||
|
|||||||
@ -159,6 +159,7 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
|
|||||||
chatlistJoined: getLimit(appConfig, 'chatlist_joined_limit', 'chatlistJoined'),
|
chatlistJoined: getLimit(appConfig, 'chatlist_joined_limit', 'chatlistJoined'),
|
||||||
recommendedChannels: getLimit(appConfig, 'recommended_channels_limit', 'recommendedChannels'),
|
recommendedChannels: getLimit(appConfig, 'recommended_channels_limit', 'recommendedChannels'),
|
||||||
savedDialogsPinned: getLimit(appConfig, 'saved_dialogs_pinned_limit', 'savedDialogsPinned'),
|
savedDialogsPinned: getLimit(appConfig, 'saved_dialogs_pinned_limit', 'savedDialogsPinned'),
|
||||||
|
moreAccounts: DEFAULT_LIMITS.moreAccounts,
|
||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
areStoriesHidden: appConfig.stories_all_hidden,
|
areStoriesHidden: appConfig.stories_all_hidden,
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import BigInt from 'big-integer';
|
import BigInt from 'big-integer';
|
||||||
import { Api as GramJs } from '../../lib/gramjs';
|
import { Api as GramJs } from '../../lib/gramjs';
|
||||||
|
|
||||||
import { DATA_BROADCAST_CHANNEL_NAME, DEBUG } from '../../config';
|
import { DEBUG } from '../../config';
|
||||||
|
import { DATA_BROADCAST_CHANNEL_NAME } from '../../util/multiaccount';
|
||||||
import { throttle } from '../../util/schedulers';
|
import { throttle } from '../../util/schedulers';
|
||||||
import { omitVirtualClassFields } from './apiBuilders/helpers';
|
import { omitVirtualClassFields } from './apiBuilders/helpers';
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-globals
|
|
||||||
const IS_MULTITAB_SUPPORTED = 'BroadcastChannel' in self;
|
|
||||||
|
|
||||||
export type StoryRepairInfo = {
|
export type StoryRepairInfo = {
|
||||||
type: 'story';
|
type: 'story';
|
||||||
peerId: string;
|
peerId: string;
|
||||||
@ -36,7 +34,7 @@ export interface LocalDb {
|
|||||||
channelPtsById: Record<string, number>;
|
channelPtsById: Record<string, number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = IS_MULTITAB_SUPPORTED ? new BroadcastChannel(DATA_BROADCAST_CHANNEL_NAME) : undefined;
|
const channel = new BroadcastChannel(DATA_BROADCAST_CHANNEL_NAME);
|
||||||
|
|
||||||
let batchedUpdates: {
|
let batchedUpdates: {
|
||||||
name: string;
|
name: string;
|
||||||
@ -44,7 +42,7 @@ let batchedUpdates: {
|
|||||||
value: any;
|
value: any;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
const throttledLocalDbUpdate = throttle(() => {
|
const throttledLocalDbUpdate = throttle(() => {
|
||||||
channel!.postMessage({
|
channel.postMessage({
|
||||||
type: 'localDbUpdate',
|
type: 'localDbUpdate',
|
||||||
batchedUpdates,
|
batchedUpdates,
|
||||||
});
|
});
|
||||||
@ -109,9 +107,7 @@ function createLocalDbInitial(initial?: LocalDb): LocalDb {
|
|||||||
return acc2;
|
return acc2;
|
||||||
}, {} as Record<string, any>);
|
}, {} as Record<string, any>);
|
||||||
|
|
||||||
acc[key] = IS_MULTITAB_SUPPORTED
|
acc[key] = createProxy(key, convertedValue);
|
||||||
? createProxy(key, convertedValue)
|
|
||||||
: convertedValue;
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as LocalDb) as LocalDb;
|
}, {} as LocalDb) as LocalDb;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export async function init(initialArgs: ApiInitialArgs) {
|
|||||||
const {
|
const {
|
||||||
userAgent, platform, sessionData, isWebmSupported, maxBufferSize, webAuthToken, dcId,
|
userAgent, platform, sessionData, isWebmSupported, maxBufferSize, webAuthToken, dcId,
|
||||||
mockScenario, shouldForceHttpTransport, shouldAllowHttpTransport,
|
mockScenario, shouldForceHttpTransport, shouldAllowHttpTransport,
|
||||||
shouldDebugExportedSenders, langCode, isTestServerRequested,
|
shouldDebugExportedSenders, langCode, isTestServerRequested, accountIds,
|
||||||
} = initialArgs;
|
} = initialArgs;
|
||||||
|
|
||||||
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
|
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
|
||||||
@ -133,6 +133,7 @@ export async function init(initialArgs: ApiInitialArgs) {
|
|||||||
webAuthToken,
|
webAuthToken,
|
||||||
webAuthTokenFailed: onWebAuthTokenFailed,
|
webAuthTokenFailed: onWebAuthTokenFailed,
|
||||||
mockScenario,
|
mockScenario,
|
||||||
|
accountIds,
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import type { Api } from '../../../lib/gramjs';
|
import type { Api } from '../../../lib/gramjs';
|
||||||
import type { TypedBroadcastChannel } from '../../../util/multitab';
|
import type { TypedBroadcastChannel } from '../../../util/browser/multitab';
|
||||||
import type { ApiInitialArgs, ApiOnProgress, OnApiUpdate } from '../../types';
|
import type { ApiInitialArgs, ApiOnProgress, OnApiUpdate } from '../../types';
|
||||||
import type { LocalDb } from '../localDb';
|
import type { LocalDb } from '../localDb';
|
||||||
import type { MethodArgs, MethodResponse, Methods } from '../methods/types';
|
import type { MethodArgs, MethodResponse, Methods } from '../methods/types';
|
||||||
import type { OriginPayload, ThenArg, WorkerMessageEvent } from './types';
|
import type { OriginPayload, ThenArg, WorkerMessageEvent } from './types';
|
||||||
|
|
||||||
import { DATA_BROADCAST_CHANNEL_NAME, DEBUG, IGNORE_UNHANDLED_ERRORS } from '../../../config';
|
import { DEBUG, IGNORE_UNHANDLED_ERRORS } from '../../../config';
|
||||||
import { logDebugMessage } from '../../../util/debugConsole';
|
import { logDebugMessage } from '../../../util/debugConsole';
|
||||||
import Deferred from '../../../util/Deferred';
|
import Deferred from '../../../util/Deferred';
|
||||||
import { getCurrentTabId, subscribeToMasterChange } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId, subscribeToMasterChange } from '../../../util/establishMultitabRole';
|
||||||
import generateUniqueId from '../../../util/generateUniqueId';
|
import generateUniqueId from '../../../util/generateUniqueId';
|
||||||
|
import { ACCOUNT_SLOT, DATA_BROADCAST_CHANNEL_NAME } from '../../../util/multiaccount';
|
||||||
import { pause, throttleWithTickEnd } from '../../../util/schedulers';
|
import { pause, throttleWithTickEnd } from '../../../util/schedulers';
|
||||||
import { IS_MULTITAB_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
type RequestState = {
|
type RequestState = {
|
||||||
messageId: string;
|
messageId: string;
|
||||||
@ -48,9 +48,7 @@ subscribeToMasterChange((isMasterTabNew) => {
|
|||||||
isMasterTab = isMasterTabNew;
|
isMasterTab = isMasterTabNew;
|
||||||
});
|
});
|
||||||
|
|
||||||
const channel = IS_MULTITAB_SUPPORTED
|
const channel = new BroadcastChannel(DATA_BROADCAST_CHANNEL_NAME) as TypedBroadcastChannel;
|
||||||
? new BroadcastChannel(DATA_BROADCAST_CHANNEL_NAME) as TypedBroadcastChannel
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const postMessagesOnTickEnd = throttleWithTickEnd(() => {
|
const postMessagesOnTickEnd = throttleWithTickEnd(() => {
|
||||||
const payloads = pendingPayloads;
|
const payloads = pendingPayloads;
|
||||||
@ -64,8 +62,6 @@ function postMessageOnTickEnd(payload: OriginPayload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initApiOnMasterTab(initialArgs: ApiInitialArgs) {
|
export function initApiOnMasterTab(initialArgs: ApiInitialArgs) {
|
||||||
if (!channel) return;
|
|
||||||
|
|
||||||
channel.postMessage({
|
channel.postMessage({
|
||||||
type: 'initApi',
|
type: 'initApi',
|
||||||
token: getCurrentTabId(),
|
token: getCurrentTabId(),
|
||||||
@ -93,7 +89,14 @@ export function initApi(onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs) {
|
|||||||
console.log('>>> START LOAD WORKER');
|
console.log('>>> START LOAD WORKER');
|
||||||
}
|
}
|
||||||
|
|
||||||
worker = new Worker(new URL('./worker.ts', import.meta.url));
|
const params = new URLSearchParams();
|
||||||
|
if (ACCOUNT_SLOT) {
|
||||||
|
params.set('account', String(ACCOUNT_SLOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
worker = new Worker(new URL('./worker.ts', import.meta.url), {
|
||||||
|
name: params.toString(),
|
||||||
|
});
|
||||||
subscribeToWorker(onUpdate);
|
subscribeToWorker(onUpdate);
|
||||||
|
|
||||||
if (initialArgs.platform === 'iOS') {
|
if (initialArgs.platform === 'iOS') {
|
||||||
@ -132,8 +135,6 @@ export function updateFullLocalDb(initial: LocalDb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function callApiOnMasterTab(payload: any) {
|
export function callApiOnMasterTab(payload: any) {
|
||||||
if (!channel) return;
|
|
||||||
|
|
||||||
channel.postMessage({
|
channel.postMessage({
|
||||||
type: 'callApi',
|
type: 'callApi',
|
||||||
token: getCurrentTabId(),
|
token: getCurrentTabId(),
|
||||||
@ -254,8 +255,6 @@ export function cancelApiProgress(progressCallback: ApiOnProgress) {
|
|||||||
if (isMasterTab) {
|
if (isMasterTab) {
|
||||||
cancelApiProgressMaster(messageId);
|
cancelApiProgressMaster(messageId);
|
||||||
} else {
|
} else {
|
||||||
if (!channel) return;
|
|
||||||
|
|
||||||
channel.postMessage({
|
channel.postMessage({
|
||||||
type: 'cancelApiProgress',
|
type: 'cancelApiProgress',
|
||||||
token: getCurrentTabId(),
|
token: getCurrentTabId(),
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export interface ApiInitialArgs {
|
|||||||
shouldDebugExportedSenders?: boolean;
|
shouldDebugExportedSenders?: boolean;
|
||||||
langCode: string;
|
langCode: string;
|
||||||
isTestServerRequested?: boolean;
|
isTestServerRequested?: boolean;
|
||||||
|
accountIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiOnProgress {
|
export interface ApiOnProgress {
|
||||||
@ -102,7 +103,7 @@ export interface ApiWebSession {
|
|||||||
|
|
||||||
export interface ApiSessionData {
|
export interface ApiSessionData {
|
||||||
mainDcId: number;
|
mainDcId: number;
|
||||||
keys: Record<number, string | number[]>;
|
keys: Record<number, string>;
|
||||||
isTest?: true;
|
isTest?: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,10 +344,11 @@ export type ApiLimitType =
|
|||||||
| 'chatlistInvites'
|
| 'chatlistInvites'
|
||||||
| 'chatlistJoined'
|
| 'chatlistJoined'
|
||||||
| 'recommendedChannels'
|
| 'recommendedChannels'
|
||||||
| 'savedDialogsPinned';
|
| 'savedDialogsPinned'
|
||||||
|
| 'moreAccounts';
|
||||||
|
|
||||||
export type ApiLimitTypeWithModal = Exclude<ApiLimitType, (
|
export type ApiLimitTypeWithModal = Exclude<ApiLimitType, (
|
||||||
'captionLength' | 'aboutLength' | 'stickersFaved' | 'savedGifs' | 'recommendedChannels'
|
'captionLength' | 'aboutLength' | 'stickersFaved' | 'savedGifs' | 'recommendedChannels' | 'moreAccounts'
|
||||||
)>;
|
)>;
|
||||||
|
|
||||||
export type ApiLimitTypeForPromo = Exclude<ApiLimitType,
|
export type ApiLimitTypeForPromo = Exclude<ApiLimitType,
|
||||||
|
|||||||
@ -71,6 +71,9 @@
|
|||||||
"PremiumPreviewUploadsDescription" = "4 GB per each document, unlimited storage for your chats and media overall.";
|
"PremiumPreviewUploadsDescription" = "4 GB per each document, unlimited storage for your chats and media overall.";
|
||||||
"PremiumPreviewAdvancedChatManagementDescription" = "Tools to set the default folder, auto-archive and hide new chats from non-contacts.";
|
"PremiumPreviewAdvancedChatManagementDescription" = "Tools to set the default folder, auto-archive and hide new chats from non-contacts.";
|
||||||
"PremiumPreviewAnimatedProfilesDescription" = "Video avatars animated in chat lists and chats to allow for additional self-expression.";
|
"PremiumPreviewAnimatedProfilesDescription" = "Video avatars animated in chat lists and chats to allow for additional self-expression.";
|
||||||
|
"PremiumLimitAccountsTitle" = "Limit Reached";
|
||||||
|
"PremiumLimitAccountsNoPremium" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium.";
|
||||||
|
"PremiumLimitAccounts" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium with one of these connected accounts.";
|
||||||
"SendMessage" = "Send Message";
|
"SendMessage" = "Send Message";
|
||||||
"ConversationDefaultRestrictedMedia" = "Sending media isn't allowed in this group.";
|
"ConversationDefaultRestrictedMedia" = "Sending media isn't allowed in this group.";
|
||||||
"AccDescrVoiceMessage" = "Record voice message";
|
"AccDescrVoiceMessage" = "Record voice message";
|
||||||
@ -172,6 +175,7 @@
|
|||||||
"LoginRegisterLastNamePlaceholder" = "Last Name";
|
"LoginRegisterLastNamePlaceholder" = "Last Name";
|
||||||
"Next" = "Next";
|
"Next" = "Next";
|
||||||
"LoginSelectCountryTitle" = "Country";
|
"LoginSelectCountryTitle" = "Country";
|
||||||
|
"MenuAddAccount" = "Add Account";
|
||||||
"CountryNone" = "Country not found";
|
"CountryNone" = "Country not found";
|
||||||
"VoipGroupVoiceChat" = "Video Chat";
|
"VoipGroupVoiceChat" = "Video Chat";
|
||||||
"AccDescrMoreOptions" = "More options";
|
"AccDescrMoreOptions" = "More options";
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { initializeSoundsForSafari } from '../global/actions/ui/calls';
|
import { initializeSoundsForSafari } from '../global/actions/ui/calls';
|
||||||
import { IS_IOS, IS_SAFARI } from '../util/windowEnvironment';
|
import { IS_IOS, IS_SAFARI } from '../util/browser/windowEnvironment';
|
||||||
|
|
||||||
export { default as GroupCall } from '../components/calls/group/GroupCall';
|
export { default as GroupCall } from '../components/calls/group/GroupCall';
|
||||||
export { default as ActiveCallHeader } from '../components/calls/ActiveCallHeader';
|
export { default as ActiveCallHeader } from '../components/calls/ActiveCallHeader';
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import { getActions, getGlobal } from '../global';
|
|
||||||
|
|
||||||
import { DEBUG } from '../config';
|
import { DEBUG } from '../config';
|
||||||
import { IS_MULTITAB_SUPPORTED } from '../util/windowEnvironment';
|
|
||||||
|
|
||||||
export { default as Main } from '../components/main/Main';
|
export { default as Main } from '../components/main/Main';
|
||||||
export { default as LockScreen } from '../components/main/LockScreen';
|
export { default as LockScreen } from '../components/main/LockScreen';
|
||||||
@ -10,8 +7,3 @@ if (DEBUG) {
|
|||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('>>> FINISH LOAD MAIN BUNDLE');
|
console.log('>>> FINISH LOAD MAIN BUNDLE');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { passcode: { isScreenLocked }, connectionState } = getGlobal();
|
|
||||||
if (!connectionState && !isScreenLocked && !IS_MULTITAB_SUPPORTED) {
|
|
||||||
getActions().initApi();
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { FC } from '../lib/teact/teact';
|
import type { FC } from '../lib/teact/teact';
|
||||||
import React, { useEffect, useLayoutEffect } from '../lib/teact/teact';
|
import React, { useEffect, useLayoutEffect } from '../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../global';
|
import { withGlobal } from '../global';
|
||||||
|
|
||||||
import type { GlobalState } from '../global/types';
|
import type { GlobalState } from '../global/types';
|
||||||
import type { ThemeKey } from '../types';
|
import type { ThemeKey } from '../types';
|
||||||
@ -10,12 +10,12 @@ import {
|
|||||||
DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE,
|
DARK_THEME_BG_COLOR, INACTIVE_MARKER, LIGHT_THEME_BG_COLOR, PAGE_TITLE,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { selectTabState, selectTheme } from '../global/selectors';
|
import { selectTabState, selectTheme } from '../global/selectors';
|
||||||
import { addActiveTabChangeListener } from '../util/activeTabMonitor';
|
import { IS_INSTALL_PROMPT_SUPPORTED, PLATFORM_ENV } from '../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../util/buildClassName';
|
import buildClassName from '../util/buildClassName';
|
||||||
import { setupBeforeInstallPrompt } from '../util/installPrompt';
|
import { setupBeforeInstallPrompt } from '../util/installPrompt';
|
||||||
import { parseInitialLocationHash } from '../util/routing';
|
import { ACCOUNT_SLOT, getAccountsInfo, getAccountSlotUrl } from '../util/multiaccount';
|
||||||
|
import { getInitialLocationHash, parseInitialLocationHash } from '../util/routing';
|
||||||
import { hasStoredSession } from '../util/sessions';
|
import { hasStoredSession } from '../util/sessions';
|
||||||
import { IS_INSTALL_PROMPT_SUPPORTED, IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from '../util/windowEnvironment';
|
|
||||||
import { updateSizes } from '../util/windowSize';
|
import { updateSizes } from '../util/windowSize';
|
||||||
|
|
||||||
import useAppLayout from '../hooks/useAppLayout';
|
import useAppLayout from '../hooks/useAppLayout';
|
||||||
@ -61,8 +61,6 @@ const App: FC<StateProps> = ({
|
|||||||
isTestServer,
|
isTestServer,
|
||||||
theme,
|
theme,
|
||||||
}) => {
|
}) => {
|
||||||
const { disconnect } = getActions();
|
|
||||||
|
|
||||||
const [isInactive, markInactive, unmarkInactive] = useFlag(false);
|
const [isInactive, markInactive, unmarkInactive] = useFlag(false);
|
||||||
const { isMobile } = useAppLayout();
|
const { isMobile } = useAppLayout();
|
||||||
const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android';
|
const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android';
|
||||||
@ -73,6 +71,22 @@ const App: FC<StateProps> = ({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const hash = getInitialLocationHash();
|
||||||
|
// If there is no stored session on first slot, navigate to any other slot with stored session
|
||||||
|
if (!hasStoredSession() && !ACCOUNT_SLOT && !hash) {
|
||||||
|
const accounts = getAccountsInfo();
|
||||||
|
Object.keys(accounts).forEach((key) => {
|
||||||
|
const slot = Number(key);
|
||||||
|
const account = accounts[slot];
|
||||||
|
if (account) {
|
||||||
|
const url = getAccountSlotUrl(slot);
|
||||||
|
window.location.href = `${url}#${hash || 'login'}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Prevent drop on elements that do not accept it
|
// Prevent drop on elements that do not accept it
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
@ -161,17 +175,6 @@ const App: FC<StateProps> = ({
|
|||||||
updateSizes();
|
updateSizes();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (IS_MULTITAB_SUPPORTED) return;
|
|
||||||
|
|
||||||
addActiveTabChangeListener(() => {
|
|
||||||
disconnect();
|
|
||||||
document.title = INACTIVE_PAGE_TITLE;
|
|
||||||
|
|
||||||
markInactive();
|
|
||||||
});
|
|
||||||
}, [activeKey, disconnect, markInactive]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInactiveAuth) {
|
if (isInactiveAuth) {
|
||||||
document.title = INACTIVE_PAGE_TITLE;
|
document.title = INACTIVE_PAGE_TITLE;
|
||||||
|
|||||||
@ -225,6 +225,12 @@
|
|||||||
right: 0.5rem;
|
right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes qr-show {
|
@keyframes qr-show {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { getActions, withGlobal } from '../../global';
|
|||||||
|
|
||||||
import type { GlobalState } from '../../global/types';
|
import type { GlobalState } from '../../global/types';
|
||||||
|
|
||||||
import { PLATFORM_ENV } from '../../util/windowEnvironment';
|
import { PLATFORM_ENV } from '../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
import useElectronDrag from '../../hooks/useElectronDrag';
|
import useElectronDrag from '../../hooks/useElectronDrag';
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import { getActions, withGlobal } from '../../global';
|
|||||||
|
|
||||||
import type { GlobalState } from '../../global/types';
|
import type { GlobalState } from '../../global/types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import { pick } from '../../util/iteratees';
|
import { pick } from '../../util/iteratees';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { ChangeEvent } from 'react';
|
import type { ChangeEvent } from 'react';
|
||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import React, {
|
import React, {
|
||||||
memo, useCallback, useEffect, useLayoutEffect, useRef, useState,
|
memo, useEffect, useLayoutEffect, useMemo, useRef, useState,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, withGlobal } from '../../global';
|
||||||
|
|
||||||
@ -9,18 +9,23 @@ import type { ApiCountryCode } from '../../api/types';
|
|||||||
import type { GlobalState } from '../../global/types';
|
import type { GlobalState } from '../../global/types';
|
||||||
|
|
||||||
import { requestMeasure } from '../../lib/fasterdom/fasterdom';
|
import { requestMeasure } from '../../lib/fasterdom/fasterdom';
|
||||||
|
import { IS_SAFARI, IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import { preloadImage } from '../../util/files';
|
import { preloadImage } from '../../util/files';
|
||||||
import preloadFonts from '../../util/fonts';
|
import preloadFonts from '../../util/fonts';
|
||||||
import { pick } from '../../util/iteratees';
|
import { pick } from '../../util/iteratees';
|
||||||
|
import { getAccountSlotUrl } from '../../util/multiaccount';
|
||||||
import { oldSetLanguage } from '../../util/oldLangProvider';
|
import { oldSetLanguage } from '../../util/oldLangProvider';
|
||||||
import { formatPhoneNumber, getCountryCodeByIso, getCountryFromPhoneNumber } from '../../util/phoneNumber';
|
import { formatPhoneNumber, getCountryCodeByIso, getCountryFromPhoneNumber } from '../../util/phoneNumber';
|
||||||
import { IS_SAFARI, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
import { navigateBack } from './helpers/backNavigation';
|
||||||
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
||||||
|
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
import useLangString from '../../hooks/useLangString';
|
import useLangString from '../../hooks/useLangString';
|
||||||
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
|
import useMultiaccountInfo from '../../hooks/useMultiaccountInfo';
|
||||||
|
|
||||||
|
import Icon from '../common/icons/Icon';
|
||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
import Checkbox from '../ui/Checkbox';
|
import Checkbox from '../ui/Checkbox';
|
||||||
import InputText from '../ui/InputText';
|
import InputText from '../ui/InputText';
|
||||||
@ -62,7 +67,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
loadCountryList,
|
loadCountryList,
|
||||||
clearAuthErrorKey,
|
clearAuthErrorKey,
|
||||||
goToAuthQrCode,
|
goToAuthQrCode,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -78,6 +83,16 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
const [lastSelection, setLastSelection] = useState<[number, number] | undefined>();
|
const [lastSelection, setLastSelection] = useState<[number, number] | undefined>();
|
||||||
const [isLoading, markIsLoading, unmarkIsLoading] = useFlag();
|
const [isLoading, markIsLoading, unmarkIsLoading] = useFlag();
|
||||||
|
|
||||||
|
const accountsInfo = useMultiaccountInfo();
|
||||||
|
const hasActiveAccount = Object.values(accountsInfo).length > 0;
|
||||||
|
const phoneNumberSlots = useMemo(() => (
|
||||||
|
Object.entries(accountsInfo)
|
||||||
|
.reduce((acc, [key, { phone }]) => {
|
||||||
|
if (phone) acc[phone] = Number(key);
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, number>)
|
||||||
|
), [accountsInfo]);
|
||||||
|
|
||||||
const fullNumber = country ? `+${country.countryCode} ${phoneNumber || ''}` : phoneNumber;
|
const fullNumber = country ? `+${country.countryCode} ${phoneNumber || ''}` : phoneNumber;
|
||||||
const canSubmit = fullNumber && fullNumber.replace(/[^\d]+/g, '').length >= MIN_NUMBER_LENGTH;
|
const canSubmit = fullNumber && fullNumber.replace(/[^\d]+/g, '').length >= MIN_NUMBER_LENGTH;
|
||||||
|
|
||||||
@ -105,7 +120,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
}
|
}
|
||||||
}, [country, authNearestCountry, isTouched, phoneCodeList]);
|
}, [country, authNearestCountry, isTouched, phoneCodeList]);
|
||||||
|
|
||||||
const parseFullNumber = useCallback((newFullNumber: string) => {
|
const parseFullNumber = useLastCallback((newFullNumber: string) => {
|
||||||
if (!newFullNumber.length) {
|
if (!newFullNumber.length) {
|
||||||
setPhoneNumber('');
|
setPhoneNumber('');
|
||||||
}
|
}
|
||||||
@ -123,17 +138,17 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
setCountry(selectedCountry);
|
setCountry(selectedCountry);
|
||||||
}
|
}
|
||||||
setPhoneNumber(formatPhoneNumber(newFullNumber, selectedCountry));
|
setPhoneNumber(formatPhoneNumber(newFullNumber, selectedCountry));
|
||||||
}, [phoneCodeList, country]);
|
});
|
||||||
|
|
||||||
const handleLangChange = useCallback(() => {
|
const handleLangChange = useLastCallback(() => {
|
||||||
markIsLoading();
|
markIsLoading();
|
||||||
|
|
||||||
void oldSetLanguage(suggestedLanguage, () => {
|
void oldSetLanguage(suggestedLanguage, () => {
|
||||||
unmarkIsLoading();
|
unmarkIsLoading();
|
||||||
|
|
||||||
setSettingOption({ language: suggestedLanguage });
|
setSharedSettingOption({ language: suggestedLanguage });
|
||||||
});
|
});
|
||||||
}, [markIsLoading, setSettingOption, suggestedLanguage, unmarkIsLoading]);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phoneNumber === undefined && authPhoneNumber) {
|
if (phoneNumber === undefined && authPhoneNumber) {
|
||||||
@ -148,19 +163,23 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
}, [lastSelection]);
|
}, [lastSelection]);
|
||||||
|
|
||||||
const isJustPastedRef = useRef(false);
|
const isJustPastedRef = useRef(false);
|
||||||
const handlePaste = useCallback(() => {
|
const handlePaste = useLastCallback(() => {
|
||||||
isJustPastedRef.current = true;
|
isJustPastedRef.current = true;
|
||||||
requestMeasure(() => {
|
requestMeasure(() => {
|
||||||
isJustPastedRef.current = false;
|
isJustPastedRef.current = false;
|
||||||
});
|
});
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
const handleCountryChange = useCallback((value: ApiCountryCode) => {
|
const handleBackNavigation = useLastCallback(() => {
|
||||||
|
navigateBack();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCountryChange = useLastCallback((value: ApiCountryCode) => {
|
||||||
setCountry(value);
|
setCountry(value);
|
||||||
setPhoneNumber('');
|
setPhoneNumber('');
|
||||||
}, []);
|
});
|
||||||
|
|
||||||
const handlePhoneNumberChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handlePhoneNumberChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (authErrorKey) {
|
if (authErrorKey) {
|
||||||
clearAuthErrorKey();
|
clearAuthErrorKey();
|
||||||
}
|
}
|
||||||
@ -186,11 +205,11 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
&& value.length - fullNumber.length > 1 && !isJustPastedRef.current
|
&& value.length - fullNumber.length > 1 && !isJustPastedRef.current
|
||||||
);
|
);
|
||||||
parseFullNumber(shouldFixSafariAutoComplete ? `${country!.countryCode} ${value}` : value);
|
parseFullNumber(shouldFixSafariAutoComplete ? `${country!.countryCode} ${value}` : value);
|
||||||
}, [authErrorKey, country, fullNumber, parseFullNumber]);
|
});
|
||||||
|
|
||||||
const handleKeepSessionChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
const handleKeepSessionChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setAuthRememberMe(e.target.checked);
|
setAuthRememberMe(e.target.checked);
|
||||||
}, [setAuthRememberMe]);
|
});
|
||||||
|
|
||||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -199,19 +218,30 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const adaptedPhoneNumber = fullNumber?.replace(/[^\d]/g, '');
|
||||||
|
if (adaptedPhoneNumber && phoneNumberSlots[adaptedPhoneNumber]) {
|
||||||
|
window.location.replace(getAccountSlotUrl(phoneNumberSlots[adaptedPhoneNumber]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (canSubmit) {
|
if (canSubmit) {
|
||||||
setAuthPhoneNumber({ phoneNumber: fullNumber });
|
setAuthPhoneNumber({ phoneNumber: fullNumber });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGoToAuthQrCode = useCallback(() => {
|
const handleGoToAuthQrCode = useLastCallback(() => {
|
||||||
goToAuthQrCode();
|
goToAuthQrCode();
|
||||||
}, [goToAuthQrCode]);
|
});
|
||||||
|
|
||||||
const isAuthReady = authState === 'authorizationStateWaitPhoneNumber';
|
const isAuthReady = authState === 'authorizationStateWaitPhoneNumber';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="auth-phone-number-form" className="custom-scroll">
|
<div id="auth-phone-number-form" className="custom-scroll">
|
||||||
|
{hasActiveAccount && (
|
||||||
|
<Button size="smaller" round color="translucent" className="auth-close" onClick={handleBackNavigation}>
|
||||||
|
<Icon name="close" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<div className="auth-form">
|
<div className="auth-form">
|
||||||
<div id="logo" />
|
<div id="logo" />
|
||||||
<h1>{lang('AuthTitle')}</h1>
|
<h1>{lang('AuthTitle')}</h1>
|
||||||
@ -263,7 +293,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
|
|||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const {
|
const {
|
||||||
settings: { byKey: { language } },
|
sharedState: { settings: { language } },
|
||||||
countryList: { phoneCodes: phoneCodeList },
|
countryList: { phoneCodes: phoneCodeList },
|
||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {
|
import React, {
|
||||||
memo, useCallback, useLayoutEffect, useRef,
|
memo, useLayoutEffect, useRef,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, withGlobal } from '../../global';
|
||||||
|
|
||||||
@ -7,18 +7,23 @@ import type { GlobalState } from '../../global/types';
|
|||||||
|
|
||||||
import { STRICTERDOM_ENABLED } from '../../config';
|
import { STRICTERDOM_ENABLED } from '../../config';
|
||||||
import { disableStrict, enableStrict } from '../../lib/fasterdom/stricterdom';
|
import { disableStrict, enableStrict } from '../../lib/fasterdom/stricterdom';
|
||||||
|
import { selectSharedSettings } from '../../global/selectors/sharedState';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { oldSetLanguage } from '../../util/oldLangProvider';
|
import { oldSetLanguage } from '../../util/oldLangProvider';
|
||||||
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
||||||
|
import { navigateBack } from './helpers/backNavigation';
|
||||||
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
import { getSuggestedLanguage } from './helpers/getSuggestedLanguage';
|
||||||
|
|
||||||
import useAsync from '../../hooks/useAsync';
|
import useAsync from '../../hooks/useAsync';
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
import useLangString from '../../hooks/useLangString';
|
import useLangString from '../../hooks/useLangString';
|
||||||
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
import useMediaTransitionDeprecated from '../../hooks/useMediaTransitionDeprecated';
|
import useMediaTransitionDeprecated from '../../hooks/useMediaTransitionDeprecated';
|
||||||
|
import useMultiaccountInfo from '../../hooks/useMultiaccountInfo';
|
||||||
|
|
||||||
import AnimatedIcon from '../common/AnimatedIcon';
|
import AnimatedIcon from '../common/AnimatedIcon';
|
||||||
|
import Icon from '../common/icons/Icon';
|
||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
import Loading from '../ui/Loading';
|
import Loading from '../ui/Loading';
|
||||||
|
|
||||||
@ -26,7 +31,9 @@ import blankUrl from '../../assets/blank.png';
|
|||||||
|
|
||||||
type StateProps =
|
type StateProps =
|
||||||
Pick<GlobalState, 'connectionState' | 'authState' | 'authQrCode'>
|
Pick<GlobalState, 'connectionState' | 'authState' | 'authQrCode'>
|
||||||
& { language?: string };
|
& {
|
||||||
|
language?: string;
|
||||||
|
};
|
||||||
|
|
||||||
const DATA_PREFIX = 'tg://login?token=';
|
const DATA_PREFIX = 'tg://login?token=';
|
||||||
const QR_SIZE = 280;
|
const QR_SIZE = 280;
|
||||||
@ -50,7 +57,7 @@ const AuthCode = ({
|
|||||||
}: StateProps) => {
|
}: StateProps) => {
|
||||||
const {
|
const {
|
||||||
returnToAuthPhoneNumber,
|
returnToAuthPhoneNumber,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const suggestedLanguage = getSuggestedLanguage();
|
const suggestedLanguage = getSuggestedLanguage();
|
||||||
@ -63,6 +70,9 @@ const AuthCode = ({
|
|||||||
const [isLoading, markIsLoading, unmarkIsLoading] = useFlag();
|
const [isLoading, markIsLoading, unmarkIsLoading] = useFlag();
|
||||||
const [isQrMounted, markQrMounted, unmarkQrMounted] = useFlag();
|
const [isQrMounted, markQrMounted, unmarkQrMounted] = useFlag();
|
||||||
|
|
||||||
|
const accountsInfo = useMultiaccountInfo();
|
||||||
|
const hasActiveAccount = Object.values(accountsInfo).length > 0;
|
||||||
|
|
||||||
const { result: qrCode } = useAsync(async () => {
|
const { result: qrCode } = useAsync(async () => {
|
||||||
const QrCodeStyling = (await ensureQrCodeStyling()).default;
|
const QrCodeStyling = (await ensureQrCodeStyling()).default;
|
||||||
return new QrCodeStyling({
|
return new QrCodeStyling({
|
||||||
@ -125,24 +135,33 @@ const AuthCode = ({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}, [isConnected, authQrCode, isQrMounted, markQrMounted, unmarkQrMounted, qrCode]);
|
}, [isConnected, authQrCode, isQrMounted, markQrMounted, unmarkQrMounted, qrCode]);
|
||||||
|
|
||||||
const handleLangChange = useCallback(() => {
|
const handleBackNavigation = useLastCallback(() => {
|
||||||
|
navigateBack();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleLangChange = useLastCallback(() => {
|
||||||
markIsLoading();
|
markIsLoading();
|
||||||
|
|
||||||
void oldSetLanguage(suggestedLanguage, () => {
|
void oldSetLanguage(suggestedLanguage, () => {
|
||||||
unmarkIsLoading();
|
unmarkIsLoading();
|
||||||
|
|
||||||
setSettingOption({ language: suggestedLanguage });
|
setSharedSettingOption({ language: suggestedLanguage });
|
||||||
});
|
});
|
||||||
}, [markIsLoading, setSettingOption, suggestedLanguage, unmarkIsLoading]);
|
});
|
||||||
|
|
||||||
const habdleReturnToAuthPhoneNumber = useCallback(() => {
|
const handleReturnToAuthPhoneNumber = useLastCallback(() => {
|
||||||
returnToAuthPhoneNumber();
|
returnToAuthPhoneNumber();
|
||||||
}, [returnToAuthPhoneNumber]);
|
});
|
||||||
|
|
||||||
const isAuthReady = authState === 'authorizationStateWaitQrCode';
|
const isAuthReady = authState === 'authorizationStateWaitQrCode';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="auth-qr-form" className="custom-scroll">
|
<div id="auth-qr-form" className="custom-scroll">
|
||||||
|
{hasActiveAccount && (
|
||||||
|
<Button size="smaller" round color="translucent" className="auth-close" onClick={handleBackNavigation}>
|
||||||
|
<Icon name="close" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<div className="auth-form qr">
|
<div className="auth-form qr">
|
||||||
<div className="qr-outer">
|
<div className="qr-outer">
|
||||||
<div
|
<div
|
||||||
@ -172,7 +191,7 @@ const AuthCode = ({
|
|||||||
<li><span>{lang('LoginQRHelp3')}</span></li>
|
<li><span>{lang('LoginQRHelp3')}</span></li>
|
||||||
</ol>
|
</ol>
|
||||||
{isAuthReady && (
|
{isAuthReady && (
|
||||||
<Button size="smaller" isText onClick={habdleReturnToAuthPhoneNumber}>{lang('LoginQRCancel')}</Button>
|
<Button size="smaller" isText onClick={handleReturnToAuthPhoneNumber}>{lang('LoginQRCancel')}</Button>
|
||||||
)}
|
)}
|
||||||
{suggestedLanguage && suggestedLanguage !== language && continueText && (
|
{suggestedLanguage && suggestedLanguage !== language && continueText && (
|
||||||
<Button size="smaller" isText isLoading={isLoading} onClick={handleLangChange}>{continueText}</Button>
|
<Button size="smaller" isText isLoading={isLoading} onClick={handleLangChange}>{continueText}</Button>
|
||||||
@ -185,9 +204,11 @@ const AuthCode = ({
|
|||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const {
|
const {
|
||||||
connectionState, authState, authQrCode, settings: { byKey: { language } },
|
connectionState, authState, authQrCode,
|
||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
|
const { language } = selectSharedSettings(global);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connectionState,
|
connectionState,
|
||||||
authState,
|
authState,
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import { withGlobal } from '../../global';
|
|||||||
import type { ApiCountryCode } from '../../api/types';
|
import type { ApiCountryCode } from '../../api/types';
|
||||||
|
|
||||||
import { ANIMATION_END_DELAY } from '../../config';
|
import { ANIMATION_END_DELAY } from '../../config';
|
||||||
|
import { IS_EMOJI_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { isoToEmoji } from '../../util/emoji/emoji';
|
import { isoToEmoji } from '../../util/emoji/emoji';
|
||||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||||
import { IS_EMOJI_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
import renderText from '../common/helpers/renderText';
|
import renderText from '../common/helpers/renderText';
|
||||||
|
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
|||||||
13
src/components/auth/helpers/backNavigation.ts
Normal file
13
src/components/auth/helpers/backNavigation.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { getAccountSlotUrl } from '../../../util/multiaccount';
|
||||||
|
|
||||||
|
export function navigateBack() {
|
||||||
|
const currentUrl = new URL(window.location.href);
|
||||||
|
const referrer = document.referrer ? new URL(document.referrer) : undefined;
|
||||||
|
if (referrer?.origin === currentUrl.origin && referrer.pathname === currentUrl.pathname) {
|
||||||
|
window.history.back(); // Return to previous account with it's state
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = getAccountSlotUrl(1);
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
@ -14,9 +14,9 @@ import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
|||||||
import { getUserStreams, THRESHOLD } from '../../../lib/secret-sauce';
|
import { getUserStreams, THRESHOLD } from '../../../lib/secret-sauce';
|
||||||
import { selectChat, selectUser } from '../../../global/selectors';
|
import { selectChat, selectUser } from '../../../global/selectors';
|
||||||
import { animate } from '../../../util/animation';
|
import { animate } from '../../../util/animation';
|
||||||
|
import { IS_CANVAS_FILTER_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { fastRaf } from '../../../util/schedulers';
|
import { fastRaf } from '../../../util/schedulers';
|
||||||
import { IS_CANVAS_FILTER_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
import formatGroupCallVolume from './helpers/formatGroupCallVolume';
|
import formatGroupCallVolume from './helpers/formatGroupCallVolume';
|
||||||
|
|
||||||
import useInterval from '../../../hooks/schedulers/useInterval';
|
import useInterval from '../../../hooks/schedulers/useInterval';
|
||||||
|
|||||||
@ -13,13 +13,13 @@ import {
|
|||||||
} from '../../../lib/secret-sauce';
|
} from '../../../lib/secret-sauce';
|
||||||
import { selectTabState } from '../../../global/selectors';
|
import { selectTabState } from '../../../global/selectors';
|
||||||
import { selectPhoneCallUser } from '../../../global/selectors/calls';
|
import { selectPhoneCallUser } from '../../../global/selectors/calls';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
|
||||||
import { formatMediaDuration } from '../../../util/dates/dateFormat';
|
|
||||||
import {
|
import {
|
||||||
IS_ANDROID,
|
IS_ANDROID,
|
||||||
IS_IOS,
|
IS_IOS,
|
||||||
IS_REQUEST_FULLSCREEN_SUPPORTED,
|
IS_REQUEST_FULLSCREEN_SUPPORTED,
|
||||||
} from '../../../util/windowEnvironment';
|
} from '../../../util/browser/windowEnvironment';
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
import { formatMediaDuration } from '../../../util/dates/dateFormat';
|
||||||
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
|
|||||||
@ -13,11 +13,11 @@ import type RLottieInstance from '../../lib/rlottie/RLottie';
|
|||||||
|
|
||||||
import { requestMeasure } from '../../lib/fasterdom/fasterdom';
|
import { requestMeasure } from '../../lib/fasterdom/fasterdom';
|
||||||
import { ensureRLottie, getRLottie } from '../../lib/rlottie/RLottie.async';
|
import { ensureRLottie, getRLottie } from '../../lib/rlottie/RLottie.async';
|
||||||
|
import { IS_ELECTRON } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
import generateUniqueId from '../../util/generateUniqueId';
|
import generateUniqueId from '../../util/generateUniqueId';
|
||||||
import { hexToRgb } from '../../util/switchTheme';
|
import { hexToRgb } from '../../util/switchTheme';
|
||||||
import { IS_ELECTRON } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useColorFilter from '../../hooks/stickers/useColorFilter';
|
import useColorFilter from '../../hooks/stickers/useColorFilter';
|
||||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type {
|
|||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { BufferedRange } from '../../hooks/useBuffering';
|
import type { BufferedRange } from '../../hooks/useBuffering';
|
||||||
import type { OldLangFn } from '../../hooks/useOldLang';
|
import type { OldLangFn } from '../../hooks/useOldLang';
|
||||||
import type { ISettings } from '../../types';
|
import type { ThemeKey } from '../../types';
|
||||||
import { ApiMediaFormat } from '../../api/types';
|
import { ApiMediaFormat } from '../../api/types';
|
||||||
import { AudioOrigin } from '../../types';
|
import { AudioOrigin } from '../../types';
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ import Icon from './icons/Icon';
|
|||||||
import './Audio.scss';
|
import './Audio.scss';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
message: ApiMessage;
|
message: ApiMessage;
|
||||||
senderTitle?: string;
|
senderTitle?: string;
|
||||||
uploadProgress?: number;
|
uploadProgress?: number;
|
||||||
@ -628,7 +628,7 @@ function renderVoice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function useWaveformCanvas(
|
function useWaveformCanvas(
|
||||||
theme: ISettings['theme'],
|
theme: ThemeKey,
|
||||||
media?: ApiVoice | ApiVideo,
|
media?: ApiVoice | ApiVideo,
|
||||||
playProgress = 0,
|
playProgress = 0,
|
||||||
isOwn = false,
|
isOwn = false,
|
||||||
|
|||||||
@ -69,6 +69,7 @@ type OwnProps = {
|
|||||||
peer?: ApiPeer | CustomPeer;
|
peer?: ApiPeer | CustomPeer;
|
||||||
photo?: ApiPhoto;
|
photo?: ApiPhoto;
|
||||||
webPhoto?: ApiWebDocument;
|
webPhoto?: ApiWebDocument;
|
||||||
|
previewUrl?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
isSavedMessages?: boolean;
|
isSavedMessages?: boolean;
|
||||||
isSavedDialog?: boolean;
|
isSavedDialog?: boolean;
|
||||||
@ -93,6 +94,7 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
peer,
|
peer,
|
||||||
photo,
|
photo,
|
||||||
webPhoto,
|
webPhoto,
|
||||||
|
previewUrl,
|
||||||
text,
|
text,
|
||||||
isSavedMessages,
|
isSavedMessages,
|
||||||
isSavedDialog,
|
isSavedDialog,
|
||||||
@ -169,7 +171,8 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const imgBlobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl);
|
const imgBlobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl);
|
||||||
const videoBlobUrl = useMedia(videoHash, !shouldLoadVideo, ApiMediaFormat.BlobUrl);
|
const videoBlobUrl = useMedia(videoHash, !shouldLoadVideo, ApiMediaFormat.BlobUrl);
|
||||||
const hasBlobUrl = Boolean(imgBlobUrl || videoBlobUrl);
|
const imgUrl = imgBlobUrl || previewUrl;
|
||||||
|
const hasBlobUrl = Boolean(imgUrl || videoBlobUrl);
|
||||||
// `videoBlobUrl` can be taken from memory cache, so we need to check `shouldLoadVideo` again
|
// `videoBlobUrl` can be taken from memory cache, so we need to check `shouldLoadVideo` again
|
||||||
const shouldPlayVideo = Boolean(videoBlobUrl && shouldLoadVideo);
|
const shouldPlayVideo = Boolean(videoBlobUrl && shouldLoadVideo);
|
||||||
|
|
||||||
@ -205,7 +208,7 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
<img
|
<img
|
||||||
src={imgBlobUrl}
|
src={imgUrl}
|
||||||
className={buildClassName(cn.media, 'avatar-media', transitionClassNames, videoBlobUrl && 'poster')}
|
className={buildClassName(cn.media, 'avatar-media', transitionClassNames, videoBlobUrl && 'poster')}
|
||||||
alt={author}
|
alt={author}
|
||||||
decoding="async"
|
decoding="async"
|
||||||
@ -262,10 +265,10 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
withStorySolid && forceFriendStorySolid && 'close-friend',
|
withStorySolid && forceFriendStorySolid && 'close-friend',
|
||||||
withStorySolid && (realPeer?.hasUnreadStories || forceUnreadStorySolid) && 'has-unread-story',
|
withStorySolid && (realPeer?.hasUnreadStories || forceUnreadStorySolid) && 'has-unread-story',
|
||||||
onClick && 'interactive',
|
onClick && 'interactive',
|
||||||
(!isSavedMessages && !imgBlobUrl) && 'no-photo',
|
(!isSavedMessages && !imgUrl) && 'no-photo',
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasMedia = Boolean(isSavedMessages || imgBlobUrl);
|
const hasMedia = Boolean(isSavedMessages || imgUrl);
|
||||||
|
|
||||||
const { handleClick, handleMouseDown } = useFastClick((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
|
const { handleClick, handleMouseDown } = useFastClick((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||||
if (withStory && storyViewerMode !== 'disabled' && realPeer?.hasStories) {
|
if (withStory && storyViewerMode !== 'disabled' && realPeer?.hasStories) {
|
||||||
|
|||||||
@ -35,9 +35,9 @@ import type {
|
|||||||
import type {
|
import type {
|
||||||
IAnchorPosition,
|
IAnchorPosition,
|
||||||
InlineBotSettings,
|
InlineBotSettings,
|
||||||
ISettings,
|
|
||||||
MessageList,
|
MessageList,
|
||||||
MessageListType,
|
MessageListType,
|
||||||
|
ThemeKey,
|
||||||
ThreadId,
|
ThreadId,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { MAIN_THREAD_ID } from '../../api/types';
|
import { MAIN_THREAD_ID } from '../../api/types';
|
||||||
@ -103,6 +103,8 @@ import {
|
|||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
import { selectCurrentLimit } from '../../global/selectors/limits';
|
import { selectCurrentLimit } from '../../global/selectors/limits';
|
||||||
|
import { selectSharedSettings } from '../../global/selectors/sharedState';
|
||||||
|
import { IS_IOS, IS_VOICE_RECORDING_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { formatMediaDuration, formatVoiceRecordDuration } from '../../util/dates/dateFormat';
|
import { formatMediaDuration, formatVoiceRecordDuration } from '../../util/dates/dateFormat';
|
||||||
import { processDeepLink } from '../../util/deeplink';
|
import { processDeepLink } from '../../util/deeplink';
|
||||||
@ -115,7 +117,6 @@ import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
|||||||
import parseHtmlAsFormattedText from '../../util/parseHtmlAsFormattedText';
|
import parseHtmlAsFormattedText from '../../util/parseHtmlAsFormattedText';
|
||||||
import { insertHtmlInSelection } from '../../util/selection';
|
import { insertHtmlInSelection } from '../../util/selection';
|
||||||
import { getServerTime } from '../../util/serverTime';
|
import { getServerTime } from '../../util/serverTime';
|
||||||
import { IS_IOS, IS_VOICE_RECORDING_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
import windowSize from '../../util/windowSize';
|
import windowSize from '../../util/windowSize';
|
||||||
import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix';
|
import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix';
|
||||||
import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment';
|
import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment';
|
||||||
@ -256,7 +257,7 @@ type StateProps =
|
|||||||
requestedDraftFiles?: File[];
|
requestedDraftFiles?: File[];
|
||||||
attachBots: GlobalState['attachMenu']['bots'];
|
attachBots: GlobalState['attachMenu']['bots'];
|
||||||
attachMenuPeerType?: ApiAttachMenuPeerType;
|
attachMenuPeerType?: ApiAttachMenuPeerType;
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
fileSizeLimit: number;
|
fileSizeLimit: number;
|
||||||
captionLimit: number;
|
captionLimit: number;
|
||||||
isCurrentUserPremium?: boolean;
|
isCurrentUserPremium?: boolean;
|
||||||
@ -2300,9 +2301,9 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const messageWithActualBotKeyboard = (isChatWithBot || !isChatWithUser)
|
const messageWithActualBotKeyboard = (isChatWithBot || !isChatWithUser)
|
||||||
&& selectNewestMessageWithBotKeyboardButtons(global, chatId, threadId);
|
&& selectNewestMessageWithBotKeyboardButtons(global, chatId, threadId);
|
||||||
const {
|
const {
|
||||||
language, shouldSuggestStickers, shouldSuggestCustomEmoji, shouldUpdateStickerSetOrder,
|
shouldSuggestStickers, shouldSuggestCustomEmoji, shouldUpdateStickerSetOrder, shouldPaidMessageAutoApprove,
|
||||||
shouldPaidMessageAutoApprove,
|
|
||||||
} = global.settings.byKey;
|
} = global.settings.byKey;
|
||||||
|
const { language, shouldCollectDebugLogs } = selectSharedSettings(global);
|
||||||
const {
|
const {
|
||||||
forwardMessages: { messageIds: forwardMessageIds },
|
forwardMessages: { messageIds: forwardMessageIds },
|
||||||
} = selectTabState(global);
|
} = selectTabState(global);
|
||||||
@ -2434,7 +2435,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
canBuyPremium: !isCurrentUserPremium && !selectIsPremiumPurchaseBlocked(global),
|
canBuyPremium: !isCurrentUserPremium && !selectIsPremiumPurchaseBlocked(global),
|
||||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||||
canSendOneTimeMedia: !isChatWithSelf && isChatWithUser && !isChatWithBot && !isInScheduledList,
|
canSendOneTimeMedia: !isChatWithSelf && isChatWithUser && !isChatWithBot && !isInScheduledList,
|
||||||
shouldCollectDebugLogs: global.settings.byKey.shouldCollectDebugLogs,
|
shouldCollectDebugLogs,
|
||||||
sentStoryReaction,
|
sentStoryReaction,
|
||||||
stealthMode: global.stories.stealthMode,
|
stealthMode: global.stories.stealthMode,
|
||||||
replyToTopic,
|
replyToTopic,
|
||||||
|
|||||||
@ -30,9 +30,9 @@ import {
|
|||||||
selectIsCurrentUserPremium,
|
selectIsCurrentUserPremium,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
import animateHorizontalScroll from '../../util/animateHorizontalScroll';
|
import animateHorizontalScroll from '../../util/animateHorizontalScroll';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { pickTruthy, unique, uniqueByField } from '../../util/iteratees';
|
import { pickTruthy, unique, uniqueByField } from '../../util/iteratees';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import { REM } from './helpers/mediaDimensions';
|
import { REM } from './helpers/mediaDimensions';
|
||||||
|
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -74,7 +74,7 @@ const Document = ({
|
|||||||
onMediaClick,
|
onMediaClick,
|
||||||
onDateClick,
|
onDateClick,
|
||||||
}: OwnProps) => {
|
}: OwnProps) => {
|
||||||
const { cancelMediaDownload, downloadMedia, setSettingOption } = getActions();
|
const { cancelMediaDownload, downloadMedia, setSharedSettingOption } = getActions();
|
||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
@ -158,7 +158,7 @@ const Document = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleSvgConfirm = useLastCallback(() => {
|
const handleSvgConfirm = useLastCallback(() => {
|
||||||
setSettingOption({ shouldWarnAboutSvg: !shouldNotWarnAboutSvg });
|
setSharedSettingOption({ shouldWarnAboutSvg: !shouldNotWarnAboutSvg });
|
||||||
closeSvgDialog();
|
closeSvgDialog();
|
||||||
handleDownload();
|
handleDownload();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import React, {
|
|||||||
|
|
||||||
import type { IconName } from '../../types/icons';
|
import type { IconName } from '../../types/icons';
|
||||||
|
|
||||||
|
import { IS_CANVAS_FILTER_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { formatMediaDateTime, formatPastTimeShort } from '../../util/dates/dateFormat';
|
import { formatMediaDateTime, formatPastTimeShort } from '../../util/dates/dateFormat';
|
||||||
import { IS_CANVAS_FILTER_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
import { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';
|
import { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';
|
||||||
import { getDocumentThumbnailDimensions } from './helpers/mediaDimensions';
|
import { getDocumentThumbnailDimensions } from './helpers/mediaDimensions';
|
||||||
import renderText from './helpers/renderText';
|
import renderText from './helpers/renderText';
|
||||||
|
|||||||
@ -63,9 +63,9 @@ const FullNameTitle: FC<OwnProps> = ({
|
|||||||
noLoopLimit,
|
noLoopLimit,
|
||||||
canCopyTitle,
|
canCopyTitle,
|
||||||
iconElement,
|
iconElement,
|
||||||
|
statusSparklesColor,
|
||||||
onEmojiStatusClick,
|
onEmojiStatusClick,
|
||||||
observeIntersection,
|
observeIntersection,
|
||||||
statusSparklesColor,
|
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
const { showNotification } = getActions();
|
const { showNotification } = getActions();
|
||||||
@ -73,9 +73,10 @@ const FullNameTitle: FC<OwnProps> = ({
|
|||||||
const customPeer = 'isCustomPeer' in peer ? peer : undefined;
|
const customPeer = 'isCustomPeer' in peer ? peer : undefined;
|
||||||
const isUser = realPeer && isApiPeerUser(realPeer);
|
const isUser = realPeer && isApiPeerUser(realPeer);
|
||||||
const title = realPeer && (isUser ? getUserFullName(realPeer) : getChatTitle(lang, realPeer));
|
const title = realPeer && (isUser ? getUserFullName(realPeer) : getChatTitle(lang, realPeer));
|
||||||
const isPremium = isUser && realPeer.isPremium;
|
const isPremium = (isUser && realPeer.isPremium) || customPeer?.isPremium;
|
||||||
const canShowEmojiStatus = withEmojiStatus && !isSavedMessages && realPeer;
|
const canShowEmojiStatus = withEmojiStatus && !isSavedMessages;
|
||||||
const emojiStatus = realPeer?.emojiStatus;
|
const emojiStatus = realPeer?.emojiStatus
|
||||||
|
|| (customPeer?.emojiStatusId ? { type: 'regular', documentId: customPeer.emojiStatusId } : undefined);
|
||||||
|
|
||||||
const handleTitleClick = useLastCallback((e) => {
|
const handleTitleClick = useLastCallback((e) => {
|
||||||
if (!title || !canCopyTitle) {
|
if (!title || !canCopyTitle) {
|
||||||
@ -89,7 +90,7 @@ const FullNameTitle: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const specialTitle = useMemo(() => {
|
const specialTitle = useMemo(() => {
|
||||||
if (customPeer) {
|
if (customPeer) {
|
||||||
return customPeer.title || lang(customPeer.titleKey!);
|
return renderText(customPeer.title || lang(customPeer.titleKey!));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSavedMessages) {
|
if (isSavedMessages) {
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import type { ApiVideo } from '../../api/types';
|
|||||||
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
||||||
|
|
||||||
import { getVideoMediaHash, getVideoPreviewMediaHash } from '../../global/helpers';
|
import { getVideoMediaHash, getVideoPreviewMediaHash } from '../../global/helpers';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
||||||
|
|
||||||
import useBuffering from '../../hooks/useBuffering';
|
import useBuffering from '../../hooks/useBuffering';
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import React, {
|
|||||||
|
|
||||||
import { MIN_PASSWORD_LENGTH } from '../../config';
|
import { MIN_PASSWORD_LENGTH } from '../../config';
|
||||||
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import stopEvent from '../../util/stopEvent';
|
import stopEvent from '../../util/stopEvent';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useTimeout from '../../hooks/schedulers/useTimeout';
|
import useTimeout from '../../hooks/schedulers/useTimeout';
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -20,10 +20,10 @@ import {
|
|||||||
selectUser,
|
selectUser,
|
||||||
selectUserStatus,
|
selectUserStatus,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { captureEvents, SwipeDirection } from '../../util/captureEvents';
|
import { captureEvents, SwipeDirection } from '../../util/captureEvents';
|
||||||
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import renderText from './helpers/renderText';
|
import renderText from './helpers/renderText';
|
||||||
|
|
||||||
import useIntervalForceUpdate from '../../hooks/schedulers/useIntervalForceUpdate';
|
import useIntervalForceUpdate from '../../hooks/schedulers/useIntervalForceUpdate';
|
||||||
|
|||||||
@ -17,9 +17,9 @@ import {
|
|||||||
isDeletedUser,
|
isDeletedUser,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { IS_CANVAS_FILTER_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { getFirstLetters } from '../../util/textFormat';
|
import { getFirstLetters } from '../../util/textFormat';
|
||||||
import { IS_CANVAS_FILTER_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
import { getPeerColorClass } from './helpers/peerColor';
|
import { getPeerColorClass } from './helpers/peerColor';
|
||||||
import renderText from './helpers/renderText';
|
import renderText from './helpers/renderText';
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import React, { memo, useCallback } from '../../lib/teact/teact';
|
import React, { memo, useCallback } from '../../lib/teact/teact';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
import Icon from './icons/Icon';
|
import Icon from './icons/Icon';
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import { getActions } from '../../global';
|
|||||||
import type { ApiBotInlineMediaResult, ApiSticker } from '../../api/types';
|
import type { ApiBotInlineMediaResult, ApiSticker } from '../../api/types';
|
||||||
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { getServerTime } from '../../util/serverTime';
|
import { getServerTime } from '../../util/serverTime';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
||||||
|
|
||||||
import useDynamicColorListener from '../../hooks/stickers/useDynamicColorListener';
|
import useDynamicColorListener from '../../hooks/stickers/useDynamicColorListener';
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
|||||||
|
|
||||||
import { getStickerMediaHash } from '../../global/helpers';
|
import { getStickerMediaHash } from '../../global/helpers';
|
||||||
import { selectIsAlwaysHighPriorityEmoji } from '../../global/selectors';
|
import { selectIsAlwaysHighPriorityEmoji } from '../../global/selectors';
|
||||||
|
import { IS_ANDROID, IS_IOS, IS_WEBM_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import * as mediaLoader from '../../util/mediaLoader';
|
import * as mediaLoader from '../../util/mediaLoader';
|
||||||
import { IS_ANDROID, IS_IOS, IS_WEBM_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useColorFilter from '../../hooks/stickers/useColorFilter';
|
import useColorFilter from '../../hooks/stickers/useColorFilter';
|
||||||
import useCoordsInSharedCanvas from '../../hooks/useCoordsInSharedCanvas';
|
import useCoordsInSharedCanvas from '../../hooks/useCoordsInSharedCanvas';
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import type {
|
|||||||
|
|
||||||
import { STICKER_SIZE_INLINE_DESKTOP_FACTOR, STICKER_SIZE_INLINE_MOBILE_FACTOR } from '../../../config';
|
import { STICKER_SIZE_INLINE_DESKTOP_FACTOR, STICKER_SIZE_INLINE_MOBILE_FACTOR } from '../../../config';
|
||||||
import { getPhotoInlineDimensions, getVideoDimensions } from '../../../global/helpers';
|
import { getPhotoInlineDimensions, getVideoDimensions } from '../../../global/helpers';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import windowSize from '../../../util/windowSize';
|
import windowSize from '../../../util/windowSize';
|
||||||
|
|
||||||
export const MEDIA_VIEWER_MEDIA_QUERY = '(max-height: 640px)';
|
export const MEDIA_VIEWER_MEDIA_QUERY = '(max-height: 640px)';
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
BASE_URL, IS_PACKAGED_ELECTRON, RE_LINK_TEMPLATE, RE_MENTION_TEMPLATE,
|
BASE_URL, IS_PACKAGED_ELECTRON, RE_LINK_TEMPLATE, RE_MENTION_TEMPLATE,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
import EMOJI_REGEX from '../../../lib/twemojiRegex';
|
import EMOJI_REGEX from '../../../lib/twemojiRegex';
|
||||||
|
import { IS_EMOJI_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { isDeepLink } from '../../../util/deepLinkParser';
|
import { isDeepLink } from '../../../util/deepLinkParser';
|
||||||
import {
|
import {
|
||||||
@ -16,7 +17,6 @@ import {
|
|||||||
} from '../../../util/emoji/emoji';
|
} from '../../../util/emoji/emoji';
|
||||||
import fixNonStandardEmoji from '../../../util/emoji/fixNonStandardEmoji';
|
import fixNonStandardEmoji from '../../../util/emoji/fixNonStandardEmoji';
|
||||||
import { compact } from '../../../util/iteratees';
|
import { compact } from '../../../util/iteratees';
|
||||||
import { IS_EMOJI_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import MentionLink from '../../middle/message/MentionLink';
|
import MentionLink from '../../middle/message/MentionLink';
|
||||||
import SafeLink from '../SafeLink';
|
import SafeLink from '../SafeLink';
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import { getActions } from '../../../global';
|
|||||||
|
|
||||||
import type { ActiveEmojiInteraction } from '../../../types';
|
import type { ActiveEmojiInteraction } from '../../../types';
|
||||||
|
|
||||||
|
import { IS_ELECTRON } from '../../../util/browser/windowEnvironment';
|
||||||
import buildStyle from '../../../util/buildStyle';
|
import buildStyle from '../../../util/buildStyle';
|
||||||
import safePlay from '../../../util/safePlay';
|
import safePlay from '../../../util/safePlay';
|
||||||
import { IS_ELECTRON } from '../../../util/windowEnvironment';
|
|
||||||
import { REM } from '../helpers/mediaDimensions';
|
import { REM } from '../helpers/mediaDimensions';
|
||||||
|
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { type TeactNode } from '../../../lib/teact/teact';
|
import React, { type TeactNode } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
|
import { IS_IOS } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { IS_IOS } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
|
|||||||
@ -5,12 +5,12 @@ import React, {
|
|||||||
import type { ApiBusinessWorkHours } from '../../../api/types';
|
import type { ApiBusinessWorkHours } from '../../../api/types';
|
||||||
|
|
||||||
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { formatTime, formatWeekday } from '../../../util/dates/dateFormat';
|
import { formatTime, formatWeekday } from '../../../util/dates/dateFormat';
|
||||||
import {
|
import {
|
||||||
getUtcOffset, getWeekStart, shiftTimeRanges, splitDays,
|
getUtcOffset, getWeekStart, shiftTimeRanges, splitDays,
|
||||||
} from '../../../util/dates/workHours';
|
} from '../../../util/dates/workHours';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useSelectorSignal from '../../../hooks/data/useSelectorSignal';
|
import useSelectorSignal from '../../../hooks/data/useSelectorSignal';
|
||||||
import useInterval from '../../../hooks/schedulers/useInterval';
|
import useInterval from '../../../hooks/schedulers/useInterval';
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import {
|
|||||||
import { requestMeasure } from '../../../lib/fasterdom/fasterdom';
|
import { requestMeasure } from '../../../lib/fasterdom/fasterdom';
|
||||||
import { getStickerMediaHash } from '../../../global/helpers';
|
import { getStickerMediaHash } from '../../../global/helpers';
|
||||||
import { selectIsPremiumPurchaseBlocked } from '../../../global/selectors';
|
import { selectIsPremiumPurchaseBlocked } from '../../../global/selectors';
|
||||||
|
import { IS_OFFSET_PATH_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { formatDateToString } from '../../../util/dates/dateFormat';
|
import { formatDateToString } from '../../../util/dates/dateFormat';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||||
import * as mediaLoader from '../../../util/mediaLoader';
|
import * as mediaLoader from '../../../util/mediaLoader';
|
||||||
import { IS_OFFSET_PATH_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
import renderText from '../helpers/renderText';
|
import renderText from '../helpers/renderText';
|
||||||
|
|
||||||
import useTimeout from '../../../hooks/schedulers/useTimeout';
|
import useTimeout from '../../../hooks/schedulers/useTimeout';
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import React, { memo, useMemo } from '../../../lib/teact/teact';
|
|||||||
import type { ApiEmojiStatusType, ApiReactionCustomEmoji } from '../../../api/types';
|
import type { ApiEmojiStatusType, ApiReactionCustomEmoji } from '../../../api/types';
|
||||||
|
|
||||||
import { getStickerHashById } from '../../../global/helpers';
|
import { getStickerHashById } from '../../../global/helpers';
|
||||||
|
import { IS_OFFSET_PATH_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import buildStyle from '../../../util/buildStyle';
|
import buildStyle from '../../../util/buildStyle';
|
||||||
import { IS_OFFSET_PATH_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
|||||||
|
|
||||||
import { isSameReaction } from '../../../global/helpers';
|
import { isSameReaction } from '../../../global/helpers';
|
||||||
import { selectPerformanceSettingsValue, selectTabState } from '../../../global/selectors';
|
import { selectPerformanceSettingsValue, selectTabState } from '../../../global/selectors';
|
||||||
|
import { IS_ANDROID, IS_IOS } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { IS_ANDROID, IS_IOS } from '../../../util/windowEnvironment';
|
|
||||||
import { LOCAL_TGS_URLS } from '../helpers/animatedAssets';
|
import { LOCAL_TGS_URLS } from '../helpers/animatedAssets';
|
||||||
import { REM } from '../helpers/mediaDimensions';
|
import { REM } from '../helpers/mediaDimensions';
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import type { ReducerAction } from '../../hooks/useReducer';
|
|||||||
import { LeftColumnContent, SettingsScreens } from '../../types';
|
import { LeftColumnContent, SettingsScreens } from '../../types';
|
||||||
|
|
||||||
import { selectCurrentChat, selectIsForumPanelOpen, selectTabState } from '../../global/selectors';
|
import { selectCurrentChat, selectIsForumPanelOpen, selectTabState } from '../../global/selectors';
|
||||||
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
|
||||||
import { captureControlledSwipe } from '../../util/swipeController';
|
|
||||||
import {
|
import {
|
||||||
IS_APP, IS_FIREFOX, IS_MAC_OS, IS_TOUCH_ENV, LAYERS_ANIMATION_NAME,
|
IS_APP, IS_FIREFOX, IS_MAC_OS, IS_TOUCH_ENV, LAYERS_ANIMATION_NAME,
|
||||||
} from '../../util/windowEnvironment';
|
} from '../../util/browser/windowEnvironment';
|
||||||
|
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
||||||
|
import { captureControlledSwipe } from '../../util/swipeController';
|
||||||
|
|
||||||
import useFoldersReducer from '../../hooks/reducers/useFoldersReducer';
|
import useFoldersReducer from '../../hooks/reducers/useFoldersReducer';
|
||||||
import { useHotkeys } from '../../hooks/useHotkeys';
|
import { useHotkeys } from '../../hooks/useHotkeys';
|
||||||
|
|||||||
117
src/components/left/main/AccountMenuItems.tsx
Normal file
117
src/components/left/main/AccountMenuItems.tsx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import type { ApiUser } from '../../../api/types';
|
||||||
|
import type { CustomPeer } from '../../../types';
|
||||||
|
|
||||||
|
import { getCurrentMaxAccountCount, getCurrentProdAccountCount } from '../../../global/helpers';
|
||||||
|
import { getAccountSlotUrl } from '../../../util/multiaccount';
|
||||||
|
import { REM } from '../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
import useMultiaccountInfo from '../../../hooks/useMultiaccountInfo';
|
||||||
|
|
||||||
|
import Avatar from '../../common/Avatar';
|
||||||
|
import FullNameTitle from '../../common/FullNameTitle';
|
||||||
|
import MenuItem from '../../ui/MenuItem';
|
||||||
|
import MenuSeparator from '../../ui/MenuSeparator';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
currentUser: ApiUser;
|
||||||
|
totalLimit: number;
|
||||||
|
onSelectCurrent?: VoidFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
const NOTIFICATION_DURATION = 7000;
|
||||||
|
|
||||||
|
const AccountMenuItems = ({
|
||||||
|
currentUser,
|
||||||
|
totalLimit,
|
||||||
|
onSelectCurrent,
|
||||||
|
}: OwnProps) => {
|
||||||
|
const { showNotification } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
const accounts = useMultiaccountInfo(currentUser);
|
||||||
|
|
||||||
|
const currentCount = getCurrentProdAccountCount();
|
||||||
|
const maxCount = getCurrentMaxAccountCount();
|
||||||
|
|
||||||
|
const shouldShowLimit = currentCount >= maxCount;
|
||||||
|
|
||||||
|
const handleLimitClick = useLastCallback(() => {
|
||||||
|
showNotification({
|
||||||
|
title: lang('PremiumLimitAccountsTitle'),
|
||||||
|
message: currentUser.isPremium ? lang('PremiumLimitAccounts') : lang('PremiumLimitAccountsNoPremium'),
|
||||||
|
duration: NOTIFICATION_DURATION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const newAccountUrl = useMemo(() => {
|
||||||
|
if (!Object.values(accounts).length) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCount === totalLimit) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let freeIndex = 1;
|
||||||
|
while (accounts[freeIndex]) {
|
||||||
|
freeIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAccountSlotUrl(freeIndex, true);
|
||||||
|
}, [accounts, currentCount, totalLimit]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Object.entries(accounts || {})
|
||||||
|
.sort(([, account]) => (account.userId === currentUser.id ? -1 : 1))
|
||||||
|
.map(([slot, account], index, arr) => {
|
||||||
|
const mockUser: CustomPeer = {
|
||||||
|
title: [account.firstName, account.lastName].filter(Boolean).join(' '),
|
||||||
|
isCustomPeer: true,
|
||||||
|
peerColorId: account.color,
|
||||||
|
emojiStatusId: account.emojiStatusId,
|
||||||
|
isPremium: account.isPremium,
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasSeparator = account.userId === currentUser.id && (newAccountUrl || arr.length > 1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MenuItem
|
||||||
|
className="account-menu-item"
|
||||||
|
customIcon={(
|
||||||
|
<Avatar
|
||||||
|
size="mini"
|
||||||
|
className="account-avatar"
|
||||||
|
peer={mockUser}
|
||||||
|
previewUrl={account.avatarUri}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
onClick={account.userId === currentUser.id ? onSelectCurrent : undefined}
|
||||||
|
href={account.userId !== currentUser.id ? getAccountSlotUrl(Number(slot)) : undefined}
|
||||||
|
>
|
||||||
|
<FullNameTitle peer={mockUser} withEmojiStatus emojiStatusSize={REM} />
|
||||||
|
</MenuItem>
|
||||||
|
{hasSeparator && <MenuSeparator />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{newAccountUrl && (
|
||||||
|
<MenuItem
|
||||||
|
icon="add"
|
||||||
|
rel="noopener" // Allow referrer to be passed
|
||||||
|
href={!shouldShowLimit ? newAccountUrl : undefined}
|
||||||
|
onClick={shouldShowLimit ? handleLimitClick : undefined}
|
||||||
|
>
|
||||||
|
{lang('MenuAddAccount')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(AccountMenuItems);
|
||||||
@ -48,9 +48,9 @@ import {
|
|||||||
selectUser,
|
selectUser,
|
||||||
selectUserStatus,
|
selectUserStatus,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { createLocationHash } from '../../../util/routing';
|
import { createLocationHash } from '../../../util/routing';
|
||||||
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useSelectorSignal from '../../../hooks/data/useSelectorSignal';
|
import useSelectorSignal from '../../../hooks/data/useSelectorSignal';
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -14,11 +14,11 @@ import type { TabWithProperties } from '../../ui/TabList';
|
|||||||
import { ALL_FOLDER_ID } from '../../../config';
|
import { ALL_FOLDER_ID } from '../../../config';
|
||||||
import { selectCanShareFolder, selectTabState } from '../../../global/selectors';
|
import { selectCanShareFolder, selectTabState } from '../../../global/selectors';
|
||||||
import { selectCurrentLimit } from '../../../global/selectors/limits';
|
import { selectCurrentLimit } from '../../../global/selectors/limits';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
|
import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
|
||||||
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
|
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities';
|
import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities';
|
||||||
|
|
||||||
import useDerivedState from '../../../hooks/useDerivedState';
|
import useDerivedState from '../../../hooks/useDerivedState';
|
||||||
|
|||||||
@ -19,10 +19,10 @@ import {
|
|||||||
FRESH_AUTH_PERIOD,
|
FRESH_AUTH_PERIOD,
|
||||||
SAVED_FOLDER_ID,
|
SAVED_FOLDER_ID,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
|
import { IS_APP, IS_MAC_OS } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { getOrderKey, getPinnedChatsCount } from '../../../util/folderManager';
|
import { getOrderKey, getPinnedChatsCount } from '../../../util/folderManager';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
import { IS_APP, IS_MAC_OS } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import usePeerStoriesPolling from '../../../hooks/polling/usePeerStoriesPolling';
|
import usePeerStoriesPolling from '../../../hooks/polling/usePeerStoriesPolling';
|
||||||
import useTopOverscroll from '../../../hooks/scroll/useTopOverscroll';
|
import useTopOverscroll from '../../../hooks/scroll/useTopOverscroll';
|
||||||
|
|||||||
@ -22,11 +22,11 @@ import {
|
|||||||
selectTabState,
|
selectTabState,
|
||||||
selectTopicsInfo,
|
selectTopicsInfo,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
|
import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
|
||||||
import { waitForTransitionEnd } from '../../../util/cssAnimationEndListeners';
|
import { waitForTransitionEnd } from '../../../util/cssAnimationEndListeners';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
|
|||||||
@ -9,8 +9,8 @@ import type { SettingsScreens } from '../../../types';
|
|||||||
import { LeftColumnContent } from '../../../types';
|
import { LeftColumnContent } from '../../../types';
|
||||||
|
|
||||||
import { PRODUCTION_URL } from '../../../config';
|
import { PRODUCTION_URL } from '../../../config';
|
||||||
|
import { IS_ELECTRON, IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { IS_ELECTRON, IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useForumPanelRender from '../../../hooks/useForumPanelRender';
|
import useForumPanelRender from '../../../hooks/useForumPanelRender';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -111,20 +111,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-status-effect {
|
.StatusButton {
|
||||||
top: 50%;
|
.emoji-status-effect {
|
||||||
left: 50%;
|
top: 50%;
|
||||||
}
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.emoji-status {
|
.emoji-status {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
--custom-emoji-size: 1.5rem;
|
--custom-emoji-size: 1.5rem;
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.StarIcon {
|
.StarIcon {
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @optimization
|
// @optimization
|
||||||
@ -153,4 +155,19 @@
|
|||||||
right: -0.125rem;
|
right: -0.125rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-menu-item {
|
||||||
|
--custom-emoji-size: 1rem;
|
||||||
|
|
||||||
|
.account-avatar {
|
||||||
|
margin-inline: 0.375rem 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullName {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
padding-top: 0.1875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React, {
|
|||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { GlobalState } from '../../../global/types';
|
import type { GlobalState } from '../../../global/types';
|
||||||
import type { ISettings } from '../../../types';
|
import type { ThemeKey } from '../../../types';
|
||||||
import { LeftColumnContent, SettingsScreens } from '../../../types';
|
import { LeftColumnContent, SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -20,10 +20,11 @@ import {
|
|||||||
selectTabState,
|
selectTabState,
|
||||||
selectTheme,
|
selectTheme,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
import { IS_APP, IS_ELECTRON, IS_MAC_OS } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
import { formatDateToString } from '../../../util/dates/dateFormat';
|
import { formatDateToString } from '../../../util/dates/dateFormat';
|
||||||
import { IS_APP, IS_ELECTRON, IS_MAC_OS } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
import useConnectionStatus from '../../../hooks/useConnectionStatus';
|
import useConnectionStatus from '../../../hooks/useConnectionStatus';
|
||||||
@ -68,10 +69,10 @@ type StateProps =
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
globalSearchChatId?: string;
|
globalSearchChatId?: string;
|
||||||
searchDate?: number;
|
searchDate?: number;
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
isMessageListOpen: boolean;
|
isMessageListOpen: boolean;
|
||||||
isCurrentUserPremium?: boolean;
|
isCurrentUserPremium?: boolean;
|
||||||
isConnectionStatusMinimized: ISettings['isConnectionStatusMinimized'];
|
isConnectionStatusMinimized?: boolean;
|
||||||
areChatsLoaded?: boolean;
|
areChatsLoaded?: boolean;
|
||||||
hasPasscode?: boolean;
|
hasPasscode?: boolean;
|
||||||
canSetPasscode?: boolean;
|
canSetPasscode?: boolean;
|
||||||
@ -109,7 +110,7 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
setGlobalSearchDate,
|
setGlobalSearchDate,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
setGlobalSearchChatId,
|
setGlobalSearchChatId,
|
||||||
lockScreen,
|
lockScreen,
|
||||||
requestNextSettingsScreen,
|
requestNextSettingsScreen,
|
||||||
@ -185,7 +186,7 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const toggleConnectionStatus = useLastCallback(() => {
|
const toggleConnectionStatus = useLastCallback(() => {
|
||||||
setSettingOption({ isConnectionStatusMinimized: !isConnectionStatusMinimized });
|
setSharedSettingOption({ isConnectionStatusMinimized: !isConnectionStatusMinimized });
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleLockScreen = useLastCallback(() => {
|
const handleLockScreen = useLastCallback(() => {
|
||||||
@ -340,7 +341,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const {
|
const {
|
||||||
connectionState, isSyncing, isFetchingDifference,
|
connectionState, isSyncing, isFetchingDifference,
|
||||||
} = global;
|
} = global;
|
||||||
const { isConnectionStatusMinimized } = global.settings.byKey;
|
const { isConnectionStatusMinimized } = selectSharedSettings(global);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
searchQuery,
|
searchQuery,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
|
import type { ApiUser } from '../../../api/types';
|
||||||
import type { GlobalState } from '../../../global/types';
|
import type { GlobalState } from '../../../global/types';
|
||||||
import type { AnimationLevel, ThemeKey } from '../../../types';
|
import type { AnimationLevel, ThemeKey } from '../../../types';
|
||||||
|
|
||||||
@ -20,10 +21,13 @@ import {
|
|||||||
INITIAL_PERFORMANCE_STATE_MID,
|
INITIAL_PERFORMANCE_STATE_MID,
|
||||||
INITIAL_PERFORMANCE_STATE_MIN,
|
INITIAL_PERFORMANCE_STATE_MIN,
|
||||||
} from '../../../global/initialState';
|
} from '../../../global/initialState';
|
||||||
import { selectTabState, selectTheme } from '../../../global/selectors';
|
import { selectTabState, selectTheme, selectUser } from '../../../global/selectors';
|
||||||
|
import { selectPremiumLimit } from '../../../global/selectors/limits';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
import { IS_MULTIACCOUNT_SUPPORTED } from '../../../util/browser/globalEnvironment';
|
||||||
|
import { IS_ELECTRON } from '../../../util/browser/windowEnvironment';
|
||||||
import { getPromptInstall } from '../../../util/installPrompt';
|
import { getPromptInstall } from '../../../util/installPrompt';
|
||||||
import { switchPermanentWebVersion } from '../../../util/permanentWebVersion';
|
import { switchPermanentWebVersion } from '../../../util/permanentWebVersion';
|
||||||
import { IS_ELECTRON } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManager';
|
import { useFolderManagerForUnreadCounters } from '../../../hooks/useFolderManager';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -32,8 +36,10 @@ import useOldLang from '../../../hooks/useOldLang';
|
|||||||
|
|
||||||
import AttachBotItem from '../../middle/composer/AttachBotItem';
|
import AttachBotItem from '../../middle/composer/AttachBotItem';
|
||||||
import MenuItem from '../../ui/MenuItem';
|
import MenuItem from '../../ui/MenuItem';
|
||||||
|
import MenuSeparator from '../../ui/MenuSeparator';
|
||||||
import Switcher from '../../ui/Switcher';
|
import Switcher from '../../ui/Switcher';
|
||||||
import Toggle from '../../ui/Toggle';
|
import Toggle from '../../ui/Toggle';
|
||||||
|
import AccountMenuItems from './AccountMenuItems';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
onSelectSettings: NoneToVoidFunction;
|
onSelectSettings: NoneToVoidFunction;
|
||||||
@ -45,9 +51,11 @@ type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
animationLevel: AnimationLevel;
|
animationLevel: AnimationLevel;
|
||||||
|
currentUser?: ApiUser;
|
||||||
theme: ThemeKey;
|
theme: ThemeKey;
|
||||||
canInstall?: boolean;
|
canInstall?: boolean;
|
||||||
attachBots: GlobalState['attachMenu']['bots'];
|
attachBots: GlobalState['attachMenu']['bots'];
|
||||||
|
accountsTotalLimit: number;
|
||||||
} & Pick<GlobalState, 'currentUserId' | 'archiveSettings'>;
|
} & Pick<GlobalState, 'currentUserId' | 'archiveSettings'>;
|
||||||
|
|
||||||
const LeftSideMenuItems = ({
|
const LeftSideMenuItems = ({
|
||||||
@ -57,6 +65,8 @@ const LeftSideMenuItems = ({
|
|||||||
theme,
|
theme,
|
||||||
canInstall,
|
canInstall,
|
||||||
attachBots,
|
attachBots,
|
||||||
|
currentUser,
|
||||||
|
accountsTotalLimit,
|
||||||
onSelectArchived,
|
onSelectArchived,
|
||||||
onSelectContacts,
|
onSelectContacts,
|
||||||
onSelectSettings,
|
onSelectSettings,
|
||||||
@ -65,7 +75,7 @@ const LeftSideMenuItems = ({
|
|||||||
}: OwnProps & StateProps) => {
|
}: OwnProps & StateProps) => {
|
||||||
const {
|
const {
|
||||||
openChat,
|
openChat,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
updatePerformanceSettings,
|
updatePerformanceSettings,
|
||||||
openChatByUsername,
|
openChatByUsername,
|
||||||
openUrl,
|
openUrl,
|
||||||
@ -91,8 +101,8 @@ const LeftSideMenuItems = ({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const newTheme = theme === 'light' ? 'dark' : 'light';
|
const newTheme = theme === 'light' ? 'dark' : 'light';
|
||||||
|
|
||||||
setSettingOption({ theme: newTheme });
|
setSharedSettingOption({ theme: newTheme });
|
||||||
setSettingOption({ shouldUseSystemTheme: false });
|
setSharedSettingOption({ shouldUseSystemTheme: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleAnimationLevelChange = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
|
const handleAnimationLevelChange = useLastCallback((e: React.SyntheticEvent<HTMLElement>) => {
|
||||||
@ -106,7 +116,7 @@ const LeftSideMenuItems = ({
|
|||||||
? INITIAL_PERFORMANCE_STATE_MIN
|
? INITIAL_PERFORMANCE_STATE_MIN
|
||||||
: (newLevel === ANIMATION_LEVEL_MAX ? INITIAL_PERFORMANCE_STATE_MAX : INITIAL_PERFORMANCE_STATE_MID);
|
: (newLevel === ANIMATION_LEVEL_MAX ? INITIAL_PERFORMANCE_STATE_MAX : INITIAL_PERFORMANCE_STATE_MID);
|
||||||
|
|
||||||
setSettingOption({ animationLevel: newLevel as AnimationLevel });
|
setSharedSettingOption({ animationLevel: newLevel as AnimationLevel });
|
||||||
updatePerformanceSettings(performanceSettings);
|
updatePerformanceSettings(performanceSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -132,6 +142,16 @@ const LeftSideMenuItems = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{IS_MULTIACCOUNT_SUPPORTED && currentUser && (
|
||||||
|
<>
|
||||||
|
<AccountMenuItems
|
||||||
|
currentUser={currentUser}
|
||||||
|
totalLimit={accountsTotalLimit}
|
||||||
|
onSelectCurrent={onSelectSettings}
|
||||||
|
/>
|
||||||
|
<MenuSeparator />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="saved-messages"
|
icon="saved-messages"
|
||||||
onClick={handleSelectSaved}
|
onClick={handleSelectSaved}
|
||||||
@ -244,16 +264,18 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const {
|
const {
|
||||||
currentUserId, archiveSettings,
|
currentUserId, archiveSettings,
|
||||||
} = global;
|
} = global;
|
||||||
const { animationLevel } = global.settings.byKey;
|
const { animationLevel } = selectSharedSettings(global);
|
||||||
const attachBots = global.attachMenu.bots;
|
const attachBots = global.attachMenu.bots;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentUserId,
|
currentUserId,
|
||||||
|
currentUser: selectUser(global, currentUserId!),
|
||||||
theme: selectTheme(global),
|
theme: selectTheme(global),
|
||||||
animationLevel,
|
animationLevel,
|
||||||
canInstall: Boolean(tabState.canInstall),
|
canInstall: Boolean(tabState.canInstall),
|
||||||
archiveSettings,
|
archiveSettings,
|
||||||
attachBots,
|
attachBots,
|
||||||
|
accountsTotalLimit: selectPremiumLimit(global, 'moreAccounts'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(LeftSideMenuItems));
|
)(LeftSideMenuItems));
|
||||||
|
|||||||
@ -64,7 +64,7 @@ const StatusButton: FC<StateProps> = ({ emojiStatus, collectibleStatuses }) => {
|
|||||||
}, [openStatusPicker]);
|
}, [openStatusPicker]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="extra-spacing">
|
<div className="StatusButton extra-spacing">
|
||||||
{Boolean(isEffectShown && emojiStatus) && (
|
{Boolean(isEffectShown && emojiStatus) && (
|
||||||
<CustomEmojiEffect
|
<CustomEmojiEffect
|
||||||
reaction={emojiStatus!}
|
reaction={emojiStatus!}
|
||||||
|
|||||||
@ -27,9 +27,9 @@ import {
|
|||||||
selectThreadParam,
|
selectThreadParam,
|
||||||
selectTopics,
|
selectTopics,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { createLocationHash } from '../../../util/routing';
|
import { createLocationHash } from '../../../util/routing';
|
||||||
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import type { ApiChat, ApiTopic } from '../../../../api/types';
|
|||||||
import type { MenuItemContextAction } from '../../../ui/ListItem';
|
import type { MenuItemContextAction } from '../../../ui/ListItem';
|
||||||
|
|
||||||
import { getCanManageTopic, getHasAdminRight } from '../../../../global/helpers';
|
import { getCanManageTopic, getHasAdminRight } from '../../../../global/helpers';
|
||||||
|
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../../util/browser/windowEnvironment';
|
||||||
import { compact } from '../../../../util/iteratees';
|
import { compact } from '../../../../util/iteratees';
|
||||||
import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useOldLang from '../../../../hooks/useOldLang';
|
import useOldLang from '../../../../hooks/useOldLang';
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import React, { memo, useCallback, useState } from '../../../lib/teact/teact';
|
|||||||
|
|
||||||
import { LeftColumnContent } from '../../../types';
|
import { LeftColumnContent } from '../../../types';
|
||||||
|
|
||||||
import { LAYERS_ANIMATION_NAME } from '../../../util/windowEnvironment';
|
import { LAYERS_ANIMATION_NAME } from '../../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import Transition from '../../ui/Transition';
|
import Transition from '../../ui/Transition';
|
||||||
import NewChatStep1 from './NewChatStep1';
|
import NewChatStep1 from './NewChatStep1';
|
||||||
|
|||||||
@ -2,13 +2,14 @@ import type {
|
|||||||
ApiChat, ApiGlobalMessageSearchType, ApiMessage, ApiUser,
|
ApiChat, ApiGlobalMessageSearchType, ApiMessage, ApiUser,
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
import type { GlobalState, TabState } from '../../../../global/types';
|
import type { GlobalState, TabState } from '../../../../global/types';
|
||||||
import type { ISettings } from '../../../../types';
|
import type { ThemeKey } from '../../../../types';
|
||||||
import type { SearchResultKey } from '../../../../util/keys/searchResultKey';
|
import type { SearchResultKey } from '../../../../util/keys/searchResultKey';
|
||||||
|
|
||||||
import { selectChat, selectTabState, selectTheme } from '../../../../global/selectors';
|
import { selectChat, selectTabState, selectTheme } from '../../../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../../../global/selectors/sharedState';
|
||||||
|
|
||||||
export type StateProps = {
|
export type StateProps = {
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
chatsById: Record<string, ApiChat>;
|
chatsById: Record<string, ApiChat>;
|
||||||
usersById: Record<string, ApiUser>;
|
usersById: Record<string, ApiUser>;
|
||||||
@ -29,6 +30,8 @@ export function createMapStateToProps(type: ApiGlobalMessageSearchType) {
|
|||||||
fetchingStatus, resultsByType, chatId,
|
fetchingStatus, resultsByType, chatId,
|
||||||
} = tabState.globalSearch;
|
} = tabState.globalSearch;
|
||||||
|
|
||||||
|
const { shouldWarnAboutSvg } = selectSharedSettings(global);
|
||||||
|
|
||||||
// One component is used for two different types of results.
|
// One component is used for two different types of results.
|
||||||
// The differences between them are only in the isVoice property.
|
// The differences between them are only in the isVoice property.
|
||||||
// The rest of the search results use their own personal components.
|
// The rest of the search results use their own personal components.
|
||||||
@ -50,7 +53,7 @@ export function createMapStateToProps(type: ApiGlobalMessageSearchType) {
|
|||||||
searchChatId: chatId,
|
searchChatId: chatId,
|
||||||
activeDownloads,
|
activeDownloads,
|
||||||
isChatProtected: chatId ? selectChat(global, chatId)?.isProtected : undefined,
|
isChatProtected: chatId ? selectChat(global, chatId)?.isProtected : undefined,
|
||||||
shouldWarnAboutSvg: global.settings.byKey.shouldWarnAboutSvg,
|
shouldWarnAboutSvg,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import type { FolderEditDispatch, FoldersState } from '../../../hooks/reducers/u
|
|||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { selectTabState } from '../../../global/selectors';
|
import { selectTabState } from '../../../global/selectors';
|
||||||
import { LAYERS_ANIMATION_NAME } from '../../../util/windowEnvironment';
|
import { LAYERS_ANIMATION_NAME } from '../../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import useTwoFaReducer from '../../../hooks/reducers/useTwoFaReducer';
|
import useTwoFaReducer from '../../../hooks/reducers/useTwoFaReducer';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React, {
|
|||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ApiSticker, ApiStickerSet } from '../../../api/types';
|
import type { ApiSticker, ApiStickerSet } from '../../../api/types';
|
||||||
import type { ISettings } from '../../../types';
|
import type { AccountSettings } from '../../../types';
|
||||||
|
|
||||||
import { selectCanPlayAnimatedEmojis } from '../../../global/selectors';
|
import { selectCanPlayAnimatedEmojis } from '../../../global/selectors';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
@ -23,7 +23,7 @@ type OwnProps = {
|
|||||||
onReset: () => void;
|
onReset: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = Pick<ISettings, (
|
type StateProps = Pick<AccountSettings, (
|
||||||
'shouldSuggestCustomEmoji'
|
'shouldSuggestCustomEmoji'
|
||||||
)> & {
|
)> & {
|
||||||
customEmojiSetIds?: string[];
|
customEmojiSetIds?: string[];
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { FC } from '../../../lib/teact/teact';
|
|||||||
import React, { memo, useCallback } from '../../../lib/teact/teact';
|
import React, { memo, useCallback } from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ISettings } from '../../../types';
|
import type { AccountSettings } from '../../../types';
|
||||||
|
|
||||||
import { AUTODOWNLOAD_FILESIZE_MB_LIMITS } from '../../../config';
|
import { AUTODOWNLOAD_FILESIZE_MB_LIMITS } from '../../../config';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
@ -18,7 +18,7 @@ type OwnProps = {
|
|||||||
onReset: () => void;
|
onReset: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = Pick<ISettings, (
|
type StateProps = Pick<AccountSettings, (
|
||||||
'canAutoLoadPhotoFromContacts' |
|
'canAutoLoadPhotoFromContacts' |
|
||||||
'canAutoLoadPhotoInPrivateChats' |
|
'canAutoLoadPhotoInPrivateChats' |
|
||||||
'canAutoLoadPhotoInGroups' |
|
'canAutoLoadPhotoInGroups' |
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ISettings } from '../../../types';
|
import type { AccountSettings } from '../../../types';
|
||||||
|
|
||||||
import { SUPPORTED_TRANSLATION_LANGUAGES } from '../../../config';
|
import { SUPPORTED_TRANSLATION_LANGUAGES } from '../../../config';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
@ -50,7 +50,7 @@ type OwnProps = {
|
|||||||
onReset: () => void;
|
onReset: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = Pick<ISettings, 'doNotTranslate'>;
|
type StateProps = Pick<AccountSettings, 'doNotTranslate'>;
|
||||||
|
|
||||||
const SettingsDoNotTranslate: FC<OwnProps & StateProps> = ({
|
const SettingsDoNotTranslate: FC<OwnProps & StateProps> = ({
|
||||||
isActive,
|
isActive,
|
||||||
|
|||||||
@ -5,9 +5,14 @@ import React, {
|
|||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import { DEBUG_LOG_FILENAME } from '../../../config';
|
import { DEBUG_LOG_FILENAME } from '../../../config';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
import {
|
||||||
|
IS_ELECTRON,
|
||||||
|
IS_SNAP_EFFECT_SUPPORTED,
|
||||||
|
IS_WAVE_TRANSFORM_SUPPORTED,
|
||||||
|
} from '../../../util/browser/windowEnvironment';
|
||||||
import { getDebugLogs } from '../../../util/debugConsole';
|
import { getDebugLogs } from '../../../util/debugConsole';
|
||||||
import download from '../../../util/download';
|
import download from '../../../util/download';
|
||||||
import { IS_ELECTRON, IS_SNAP_EFFECT_SUPPORTED, IS_WAVE_TRANSFORM_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
|
||||||
|
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
@ -39,7 +44,7 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
|||||||
shouldCollectDebugLogs,
|
shouldCollectDebugLogs,
|
||||||
shouldDebugExportedSenders,
|
shouldDebugExportedSenders,
|
||||||
}) => {
|
}) => {
|
||||||
const { requestConfetti, setSettingOption, requestWave } = getActions();
|
const { requestConfetti, setSharedSettingOption, requestWave } = getActions();
|
||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const snapButtonRef = useRef<HTMLDivElement>(null);
|
const snapButtonRef = useRef<HTMLDivElement>(null);
|
||||||
@ -128,7 +133,7 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
|||||||
label="Allow HTTP Transport"
|
label="Allow HTTP Transport"
|
||||||
checked={Boolean(shouldAllowHttpTransport)}
|
checked={Boolean(shouldAllowHttpTransport)}
|
||||||
// eslint-disable-next-line react/jsx-no-bind
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onCheck={() => setSettingOption({ shouldAllowHttpTransport: !shouldAllowHttpTransport })}
|
onCheck={() => setSharedSettingOption({ shouldAllowHttpTransport: !shouldAllowHttpTransport })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -136,21 +141,21 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
|||||||
disabled={!shouldAllowHttpTransport}
|
disabled={!shouldAllowHttpTransport}
|
||||||
checked={Boolean(shouldForceHttpTransport)}
|
checked={Boolean(shouldForceHttpTransport)}
|
||||||
// eslint-disable-next-line react/jsx-no-bind
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onCheck={() => setSettingOption({ shouldForceHttpTransport: !shouldForceHttpTransport })}
|
onCheck={() => setSharedSettingOption({ shouldForceHttpTransport: !shouldForceHttpTransport })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('DebugMenuEnableLogs')}
|
label={lang('DebugMenuEnableLogs')}
|
||||||
checked={Boolean(shouldCollectDebugLogs)}
|
checked={Boolean(shouldCollectDebugLogs)}
|
||||||
// eslint-disable-next-line react/jsx-no-bind
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onCheck={() => setSettingOption({ shouldCollectDebugLogs: !shouldCollectDebugLogs })}
|
onCheck={() => setSharedSettingOption({ shouldCollectDebugLogs: !shouldCollectDebugLogs })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Enable exported senders debug"
|
label="Enable exported senders debug"
|
||||||
checked={Boolean(shouldDebugExportedSenders)}
|
checked={Boolean(shouldDebugExportedSenders)}
|
||||||
// eslint-disable-next-line react/jsx-no-bind
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onCheck={() => setSettingOption({ shouldDebugExportedSenders: !shouldDebugExportedSenders })}
|
onCheck={() => setSharedSettingOption({ shouldDebugExportedSenders: !shouldDebugExportedSenders })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{IS_ELECTRON && (
|
{IS_ELECTRON && (
|
||||||
@ -174,11 +179,18 @@ const SettingsExperimental: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
|
const {
|
||||||
|
shouldForceHttpTransport,
|
||||||
|
shouldAllowHttpTransport,
|
||||||
|
shouldCollectDebugLogs,
|
||||||
|
shouldDebugExportedSenders,
|
||||||
|
} = selectSharedSettings(global);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shouldForceHttpTransport: global.settings.byKey.shouldForceHttpTransport,
|
shouldForceHttpTransport,
|
||||||
shouldAllowHttpTransport: global.settings.byKey.shouldAllowHttpTransport,
|
shouldAllowHttpTransport,
|
||||||
shouldCollectDebugLogs: global.settings.byKey.shouldCollectDebugLogs,
|
shouldCollectDebugLogs,
|
||||||
shouldDebugExportedSenders: global.settings.byKey.shouldDebugExportedSenders,
|
shouldDebugExportedSenders,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(SettingsExperimental));
|
)(SettingsExperimental));
|
||||||
|
|||||||
@ -4,16 +4,16 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ISettings, TimeFormat } from '../../../types';
|
import type { SharedSettings, ThemeKey, TimeFormat } from '../../../types';
|
||||||
import type { IRadioOption } from '../../ui/RadioGroup';
|
import type { IRadioOption } from '../../ui/RadioGroup';
|
||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { pick } from '../../../util/iteratees';
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
import { setTimeFormat } from '../../../util/oldLangProvider';
|
|
||||||
import { getSystemTheme } from '../../../util/systemTheme';
|
|
||||||
import {
|
import {
|
||||||
IS_ANDROID, IS_ELECTRON, IS_IOS, IS_MAC_OS, IS_WINDOWS,
|
IS_ANDROID, IS_ELECTRON, IS_IOS, IS_MAC_OS, IS_WINDOWS,
|
||||||
} from '../../../util/windowEnvironment';
|
} from '../../../util/browser/windowEnvironment';
|
||||||
|
import { setTimeFormat } from '../../../util/oldLangProvider';
|
||||||
|
import { getSystemTheme } from '../../../util/systemTheme';
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
@ -31,28 +31,26 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps =
|
type StateProps =
|
||||||
Pick<ISettings, (
|
Pick<SharedSettings, (
|
||||||
'messageTextSize' |
|
'messageTextSize' |
|
||||||
'animationLevel' |
|
|
||||||
'messageSendKeyCombo' |
|
'messageSendKeyCombo' |
|
||||||
'timeFormat'
|
'timeFormat' |
|
||||||
)> & {
|
'theme' |
|
||||||
theme: ISettings['theme'];
|
'shouldUseSystemTheme'
|
||||||
shouldUseSystemTheme: boolean;
|
)>;
|
||||||
};
|
|
||||||
|
|
||||||
const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
||||||
isActive,
|
isActive,
|
||||||
onScreenSelect,
|
|
||||||
onReset,
|
|
||||||
messageTextSize,
|
messageTextSize,
|
||||||
messageSendKeyCombo,
|
messageSendKeyCombo,
|
||||||
timeFormat,
|
timeFormat,
|
||||||
theme,
|
theme,
|
||||||
shouldUseSystemTheme,
|
shouldUseSystemTheme,
|
||||||
|
onScreenSelect,
|
||||||
|
onReset,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -96,26 +94,26 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
|||||||
document.documentElement.style.setProperty('--message-text-size', `${newSize}px`);
|
document.documentElement.style.setProperty('--message-text-size', `${newSize}px`);
|
||||||
document.documentElement.setAttribute('data-message-text-size', newSize.toString());
|
document.documentElement.setAttribute('data-message-text-size', newSize.toString());
|
||||||
|
|
||||||
setSettingOption({ messageTextSize: newSize });
|
setSharedSettingOption({ messageTextSize: newSize });
|
||||||
}, [setSettingOption]);
|
}, []);
|
||||||
|
|
||||||
const handleAppearanceThemeChange = useCallback((value: string) => {
|
const handleAppearanceThemeChange = useCallback((value: string) => {
|
||||||
const newTheme = value === 'auto' ? getSystemTheme() : value as ISettings['theme'];
|
const newTheme = value === 'auto' ? getSystemTheme() : value as ThemeKey;
|
||||||
|
|
||||||
setSettingOption({ theme: newTheme });
|
setSharedSettingOption({ theme: newTheme });
|
||||||
setSettingOption({ shouldUseSystemTheme: value === 'auto' });
|
setSharedSettingOption({ shouldUseSystemTheme: value === 'auto' });
|
||||||
}, [setSettingOption]);
|
}, []);
|
||||||
|
|
||||||
const handleTimeFormatChange = useCallback((newTimeFormat: string) => {
|
const handleTimeFormatChange = useCallback((newTimeFormat: string) => {
|
||||||
setSettingOption({ timeFormat: newTimeFormat as TimeFormat });
|
setSharedSettingOption({ timeFormat: newTimeFormat as TimeFormat });
|
||||||
setSettingOption({ wasTimeFormatSetManually: true });
|
setSharedSettingOption({ wasTimeFormatSetManually: true });
|
||||||
|
|
||||||
setTimeFormat(newTimeFormat as TimeFormat);
|
setTimeFormat(newTimeFormat as TimeFormat);
|
||||||
}, [setSettingOption]);
|
}, []);
|
||||||
|
|
||||||
const handleMessageSendComboChange = useCallback((newCombo: string) => {
|
const handleMessageSendComboChange = useCallback((newCombo: string) => {
|
||||||
setSettingOption({ messageSendKeyCombo: newCombo as ISettings['messageSendKeyCombo'] });
|
setSharedSettingOption({ messageSendKeyCombo: newCombo as SharedSettings['messageSendKeyCombo'] });
|
||||||
}, [setSettingOption]);
|
}, []);
|
||||||
|
|
||||||
const [isTrayIconEnabled, setIsTrayIconEnabled] = useState(false);
|
const [isTrayIconEnabled, setIsTrayIconEnabled] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -204,17 +202,18 @@ const SettingsGeneral: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const { theme, shouldUseSystemTheme } = global.settings.byKey;
|
const {
|
||||||
|
theme,
|
||||||
|
shouldUseSystemTheme,
|
||||||
|
messageSendKeyCombo,
|
||||||
|
messageTextSize,
|
||||||
|
timeFormat,
|
||||||
|
} = selectSharedSettings(global);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...pick(global.settings.byKey, [
|
messageSendKeyCombo,
|
||||||
'messageTextSize',
|
messageTextSize,
|
||||||
'animationLevel',
|
timeFormat,
|
||||||
'messageSendKeyCombo',
|
|
||||||
'isSensitiveEnabled',
|
|
||||||
'canChangeSensitive',
|
|
||||||
'timeFormat',
|
|
||||||
]),
|
|
||||||
theme,
|
theme,
|
||||||
shouldUseSystemTheme,
|
shouldUseSystemTheme,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type { ThemeKey } from '../../../types';
|
|||||||
import { SettingsScreens, UPLOADING_WALLPAPER_SLUG } from '../../../types';
|
import { SettingsScreens, UPLOADING_WALLPAPER_SLUG } from '../../../types';
|
||||||
|
|
||||||
import { DARK_THEME_PATTERN_COLOR, DEFAULT_PATTERN_COLOR } from '../../../config';
|
import { DARK_THEME_PATTERN_COLOR, DEFAULT_PATTERN_COLOR } from '../../../config';
|
||||||
import { selectTheme } from '../../../global/selectors';
|
import { selectTheme, selectThemeValues } from '../../../global/selectors';
|
||||||
import { getAverageColor, getPatternColor, rgb2hex } from '../../../util/colors';
|
import { getAverageColor, getPatternColor, rgb2hex } from '../../../util/colors';
|
||||||
import { validateFiles } from '../../../util/files';
|
import { validateFiles } from '../../../util/files';
|
||||||
import { throttle } from '../../../util/schedulers';
|
import { throttle } from '../../../util/schedulers';
|
||||||
@ -173,7 +173,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const theme = selectTheme(global);
|
const theme = selectTheme(global);
|
||||||
const { background, isBlurred } = global.settings.themes[theme] || {};
|
const { background, isBlurred } = selectThemeValues(global, theme) || {};
|
||||||
const { loadedWallpapers } = global.settings;
|
const { loadedWallpapers } = global.settings;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
import type { ThemeKey } from '../../../types';
|
import type { ThemeKey } from '../../../types';
|
||||||
import type { RealTouchEvent } from '../../../util/captureEvents';
|
import type { RealTouchEvent } from '../../../util/captureEvents';
|
||||||
|
|
||||||
import { selectTheme } from '../../../global/selectors';
|
import { selectTheme, selectThemeValues } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { captureEvents } from '../../../util/captureEvents';
|
import { captureEvents } from '../../../util/captureEvents';
|
||||||
import {
|
import {
|
||||||
@ -351,7 +351,7 @@ function drawHue(canvas: HTMLCanvasElement) {
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const theme = selectTheme(global);
|
const theme = selectTheme(global);
|
||||||
const { backgroundColor } = global.settings.themes[theme] || {};
|
const { backgroundColor } = selectThemeValues(global, theme) || {};
|
||||||
return {
|
return {
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
theme,
|
theme,
|
||||||
|
|||||||
@ -4,13 +4,13 @@ import React, {
|
|||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ApiLanguage } from '../../../api/types';
|
import type { AccountSettings, LangCode, SharedSettings } from '../../../types';
|
||||||
import type { ISettings, LangCode } from '../../../types';
|
|
||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { selectIsCurrentUserPremium } from '../../../global/selectors';
|
import { selectIsCurrentUserPremium } from '../../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
import { IS_TRANSLATION_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import { oldSetLanguage } from '../../../util/oldLangProvider';
|
import { oldSetLanguage } from '../../../util/oldLangProvider';
|
||||||
import { IS_TRANSLATION_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
@ -30,8 +30,8 @@ type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
isCurrentUserPremium: boolean;
|
isCurrentUserPremium: boolean;
|
||||||
languages?: ApiLanguage[];
|
} & Pick<AccountSettings, 'canTranslate' | 'canTranslateChats' | 'doNotTranslate'>
|
||||||
} & Pick<ISettings, | 'language' | 'canTranslate' | 'canTranslateChats' | 'doNotTranslate'>;
|
& Pick<SharedSettings, 'language' | 'languages'>;
|
||||||
|
|
||||||
const SettingsLanguage: FC<OwnProps & StateProps> = ({
|
const SettingsLanguage: FC<OwnProps & StateProps> = ({
|
||||||
isActive,
|
isActive,
|
||||||
@ -47,6 +47,7 @@ const SettingsLanguage: FC<OwnProps & StateProps> = ({
|
|||||||
const {
|
const {
|
||||||
loadLanguages,
|
loadLanguages,
|
||||||
setSettingOption,
|
setSettingOption,
|
||||||
|
setSharedSettingOption,
|
||||||
openPremiumModal,
|
openPremiumModal,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ const SettingsLanguage: FC<OwnProps & StateProps> = ({
|
|||||||
void oldSetLanguage(langCode as LangCode, () => {
|
void oldSetLanguage(langCode as LangCode, () => {
|
||||||
unmarkIsLoading();
|
unmarkIsLoading();
|
||||||
|
|
||||||
setSettingOption({ language: langCode as LangCode });
|
setSharedSettingOption({ language: langCode as LangCode });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -182,9 +183,9 @@ const SettingsLanguage: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const {
|
const {
|
||||||
language, canTranslate, canTranslateChats, doNotTranslate,
|
canTranslate, canTranslateChats, doNotTranslate,
|
||||||
} = global.settings.byKey;
|
} = global.settings.byKey;
|
||||||
const languages = global.settings.languages;
|
const { language, languages } = selectSharedSettings(global);
|
||||||
|
|
||||||
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
} from '../../../global/initialState';
|
} from '../../../global/initialState';
|
||||||
import { selectPerformanceSettings } from '../../../global/selectors';
|
import { selectPerformanceSettings } from '../../../global/selectors';
|
||||||
import { areDeepEqual } from '../../../util/areDeepEqual';
|
import { areDeepEqual } from '../../../util/areDeepEqual';
|
||||||
import { IS_BACKDROP_BLUR_SUPPORTED, IS_SNAP_EFFECT_SUPPORTED } from '../../../util/windowEnvironment';
|
import { IS_BACKDROP_BLUR_SUPPORTED, IS_SNAP_EFFECT_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -81,7 +81,7 @@ function SettingsPerformance({
|
|||||||
onReset,
|
onReset,
|
||||||
}: OwnProps & StateProps) {
|
}: OwnProps & StateProps) {
|
||||||
const {
|
const {
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
updatePerformanceSettings,
|
updatePerformanceSettings,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
@ -138,9 +138,9 @@ function SettingsPerformance({
|
|||||||
? INITIAL_PERFORMANCE_STATE_MIN
|
? INITIAL_PERFORMANCE_STATE_MIN
|
||||||
: (newLevel === ANIMATION_LEVEL_MED ? INITIAL_PERFORMANCE_STATE_MID : INITIAL_PERFORMANCE_STATE_MAX);
|
: (newLevel === ANIMATION_LEVEL_MED ? INITIAL_PERFORMANCE_STATE_MID : INITIAL_PERFORMANCE_STATE_MAX);
|
||||||
|
|
||||||
setSettingOption({ animationLevel: newLevel as AnimationLevel });
|
setSharedSettingOption({ animationLevel: newLevel as AnimationLevel });
|
||||||
updatePerformanceSettings(performance);
|
updatePerformanceSettings(performance);
|
||||||
}, [setSettingOption]);
|
}, []);
|
||||||
|
|
||||||
const handlePropertyGroupChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
const handlePropertyGroupChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, checked } = e.target;
|
const { name, checked } = e.target;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import type { GlobalState } from '../../../global/types';
|
|||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { selectCanSetPasscode, selectIsCurrentUserPremium } from '../../../global/selectors';
|
import { selectCanSetPasscode, selectIsCurrentUserPremium } from '../../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -66,7 +67,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
loadGlobalPrivacySettings,
|
loadGlobalPrivacySettings,
|
||||||
updateGlobalPrivacySettings,
|
updateGlobalPrivacySettings,
|
||||||
loadWebAuthorizations,
|
loadWebAuthorizations,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -97,7 +98,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
|||||||
}, [updateGlobalPrivacySettings]);
|
}, [updateGlobalPrivacySettings]);
|
||||||
|
|
||||||
const handleChatInTitleChange = useCallback((isChecked: boolean) => {
|
const handleChatInTitleChange = useCallback((isChecked: boolean) => {
|
||||||
setSettingOption({
|
setSharedSettingOption({
|
||||||
canDisplayChatInTitle: isChecked,
|
canDisplayChatInTitle: isChecked,
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -405,7 +406,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
settings: {
|
settings: {
|
||||||
byKey: {
|
byKey: {
|
||||||
hasPassword, isSensitiveEnabled, canChangeSensitive, shouldArchiveAndMuteNewNonContact,
|
hasPassword, isSensitiveEnabled, canChangeSensitive, shouldArchiveAndMuteNewNonContact,
|
||||||
canDisplayChatInTitle, shouldNewNonContactPeersRequirePremium, nonContactPeersPaidStars,
|
shouldNewNonContactPeersRequirePremium, nonContactPeersPaidStars,
|
||||||
},
|
},
|
||||||
privacy,
|
privacy,
|
||||||
},
|
},
|
||||||
@ -416,6 +417,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
appConfig,
|
appConfig,
|
||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
|
const { canDisplayChatInTitle } = selectSharedSettings(global);
|
||||||
const shouldChargeForMessages = Boolean(nonContactPeersPaidStars);
|
const shouldChargeForMessages = Boolean(nonContactPeersPaidStars);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import type {
|
|||||||
ApiSticker,
|
ApiSticker,
|
||||||
ApiStickerSet,
|
ApiStickerSet,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { ISettings } from '../../../types';
|
import type { AccountSettings } from '../../../types';
|
||||||
import { SettingsScreens } from '../../../types';
|
import { SettingsScreens } from '../../../types';
|
||||||
|
|
||||||
import { selectCanPlayAnimatedEmojis } from '../../../global/selectors';
|
import { selectCanPlayAnimatedEmojis } from '../../../global/selectors';
|
||||||
@ -36,7 +36,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps =
|
type StateProps =
|
||||||
Pick<ISettings, (
|
Pick<AccountSettings, (
|
||||||
'shouldSuggestStickers' | 'shouldUpdateStickerSetOrder'
|
'shouldSuggestStickers' | 'shouldUpdateStickerSetOrder'
|
||||||
)> & {
|
)> & {
|
||||||
addedSetIds?: string[];
|
addedSetIds?: string[];
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { withGlobal } from '../../../../global';
|
|||||||
import type { ApiSticker } from '../../../../api/types';
|
import type { ApiSticker } from '../../../../api/types';
|
||||||
|
|
||||||
import { selectAnimatedEmoji, selectTabState } from '../../../../global/selectors';
|
import { selectAnimatedEmoji, selectTabState } from '../../../../global/selectors';
|
||||||
import { IS_TOUCH_ENV } from '../../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import useAppLayout from '../../../../hooks/useAppLayout';
|
import useAppLayout from '../../../../hooks/useAppLayout';
|
||||||
import useHistoryBack from '../../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../../hooks/useHistoryBack';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { withGlobal } from '../../../../global';
|
|||||||
import type { ApiSticker } from '../../../../api/types';
|
import type { ApiSticker } from '../../../../api/types';
|
||||||
|
|
||||||
import { selectAnimatedEmoji } from '../../../../global/selectors';
|
import { selectAnimatedEmoji } from '../../../../global/selectors';
|
||||||
import { IS_TOUCH_ENV } from '../../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../../util/browser/windowEnvironment';
|
||||||
import renderText from '../../../common/helpers/renderText';
|
import renderText from '../../../common/helpers/renderText';
|
||||||
|
|
||||||
import useAppLayout from '../../../../hooks/useAppLayout';
|
import useAppLayout from '../../../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import type { TabState } from '../../global/types';
|
|||||||
import { ApiMediaFormat } from '../../api/types';
|
import { ApiMediaFormat } from '../../api/types';
|
||||||
|
|
||||||
import { selectTabState } from '../../global/selectors';
|
import { selectTabState } from '../../global/selectors';
|
||||||
|
import { IS_OPFS_SUPPORTED, IS_SERVICE_WORKER_SUPPORTED, MAX_BUFFER_SIZE } from '../../util/browser/windowEnvironment';
|
||||||
import download from '../../util/download';
|
import download from '../../util/download';
|
||||||
import generateUniqueId from '../../util/generateUniqueId';
|
import generateUniqueId from '../../util/generateUniqueId';
|
||||||
import * as mediaLoader from '../../util/mediaLoader';
|
import * as mediaLoader from '../../util/mediaLoader';
|
||||||
import { IS_OPFS_SUPPORTED, IS_SERVICE_WORKER_SUPPORTED, MAX_BUFFER_SIZE } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useLastCallback from '../../hooks/useLastCallback';
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
import useRunDebounced from '../../hooks/useRunDebounced';
|
import useRunDebounced from '../../hooks/useRunDebounced';
|
||||||
|
|||||||
@ -30,13 +30,14 @@ import {
|
|||||||
selectTabState,
|
selectTabState,
|
||||||
selectUser,
|
selectUser,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../global/selectors/sharedState';
|
||||||
|
import { IS_ANDROID, IS_ELECTRON, IS_WAVE_TRANSFORM_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { waitForTransitionEnd } from '../../util/cssAnimationEndListeners';
|
import { waitForTransitionEnd } from '../../util/cssAnimationEndListeners';
|
||||||
import { processDeepLink } from '../../util/deeplink';
|
import { processDeepLink } from '../../util/deeplink';
|
||||||
import { Bundles, loadBundle } from '../../util/moduleLoader';
|
import { Bundles, loadBundle } from '../../util/moduleLoader';
|
||||||
import { parseInitialLocationHash, parseLocationHash } from '../../util/routing';
|
import { parseInitialLocationHash, parseLocationHash } from '../../util/routing';
|
||||||
import updateIcon from '../../util/updateIcon';
|
import updateIcon from '../../util/updateIcon';
|
||||||
import { IS_ANDROID, IS_ELECTRON, IS_WAVE_TRANSFORM_SUPPORTED } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useInterval from '../../hooks/schedulers/useInterval';
|
import useInterval from '../../hooks/schedulers/useInterval';
|
||||||
import useTimeout from '../../hooks/schedulers/useTimeout';
|
import useTimeout from '../../hooks/schedulers/useTimeout';
|
||||||
@ -598,11 +599,6 @@ const Main = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { isMobile }): StateProps => {
|
(global, { isMobile }): StateProps => {
|
||||||
const {
|
const {
|
||||||
settings: {
|
|
||||||
byKey: {
|
|
||||||
wasTimeFormatSetManually,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
currentUserId,
|
currentUserId,
|
||||||
} = global;
|
} = global;
|
||||||
|
|
||||||
@ -631,6 +627,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
deleteFolderDialogModal,
|
deleteFolderDialogModal,
|
||||||
} = selectTabState(global);
|
} = selectTabState(global);
|
||||||
|
|
||||||
|
const { wasTimeFormatSetManually } = selectSharedSettings(global);
|
||||||
|
|
||||||
const gameMessage = openedGame && selectChatMessage(global, openedGame.chatId, openedGame.messageId);
|
const gameMessage = openedGame && selectChatMessage(global, openedGame.chatId, openedGame.messageId);
|
||||||
const gameTitle = gameMessage?.content.game?.title;
|
const gameTitle = gameMessage?.content.game?.title;
|
||||||
const { chatId } = selectCurrentMessageList(global) || {};
|
const { chatId } = selectCurrentMessageList(global) || {};
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type { ApiCountryCode, ApiUser, ApiUserStatus } from '../../api/types';
|
|||||||
|
|
||||||
import { getUserStatus } from '../../global/helpers';
|
import { getUserStatus } from '../../global/helpers';
|
||||||
import { selectUser, selectUserStatus } from '../../global/selectors';
|
import { selectUser, selectUserStatus } from '../../global/selectors';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import { formatPhoneNumberWithCode } from '../../util/phoneNumber';
|
import { formatPhoneNumberWithCode } from '../../util/phoneNumber';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import renderText from '../common/helpers/renderText';
|
import renderText from '../common/helpers/renderText';
|
||||||
|
|
||||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
|
|||||||
@ -88,6 +88,7 @@ const LIMITS_TITLES: Record<ApiLimitTypeForPromo, string> = {
|
|||||||
dialogFilters: 'FoldersLimitTitle',
|
dialogFilters: 'FoldersLimitTitle',
|
||||||
dialogFiltersChats: 'ChatPerFolderLimitTitle',
|
dialogFiltersChats: 'ChatPerFolderLimitTitle',
|
||||||
recommendedChannels: 'SimilarChannelsLimitTitle',
|
recommendedChannels: 'SimilarChannelsLimitTitle',
|
||||||
|
moreAccounts: 'ConnectedAccountsLimitTitle',
|
||||||
};
|
};
|
||||||
|
|
||||||
const LIMITS_DESCRIPTIONS: Record<ApiLimitTypeForPromo, string> = {
|
const LIMITS_DESCRIPTIONS: Record<ApiLimitTypeForPromo, string> = {
|
||||||
@ -101,6 +102,7 @@ const LIMITS_DESCRIPTIONS: Record<ApiLimitTypeForPromo, string> = {
|
|||||||
dialogFilters: 'FoldersLimitSubtitle',
|
dialogFilters: 'FoldersLimitSubtitle',
|
||||||
dialogFiltersChats: 'ChatPerFolderLimitSubtitle',
|
dialogFiltersChats: 'ChatPerFolderLimitSubtitle',
|
||||||
recommendedChannels: 'SimilarChannelsLimitSubtitle',
|
recommendedChannels: 'SimilarChannelsLimitSubtitle',
|
||||||
|
moreAccounts: 'ConnectedAccountsLimitSubtitle',
|
||||||
};
|
};
|
||||||
|
|
||||||
const BORDER_THRESHOLD = 20;
|
const BORDER_THRESHOLD = 20;
|
||||||
@ -216,13 +218,16 @@ const PremiumFeatureModal: FC<OwnProps> = ({
|
|||||||
stopScrolling();
|
stopScrolling();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currentSection = filteredSections[currentSlideIndex];
|
||||||
|
const hasHeaderBackdrop = currentSection !== 'double_limits' && currentSection !== 'stories';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.root}>
|
<div className={styles.root}>
|
||||||
<Button
|
<Button
|
||||||
round
|
round
|
||||||
size="smaller"
|
size="smaller"
|
||||||
className={buildClassName(styles.backButton, currentSlideIndex !== 0 && styles.whiteBackButton)}
|
className={buildClassName(styles.backButton, hasHeaderBackdrop && styles.whiteBackButton)}
|
||||||
color={currentSlideIndex === 0 ? 'translucent' : 'translucent-white'}
|
color={hasHeaderBackdrop ? 'translucent-white' : 'translucent'}
|
||||||
onClick={onBack}
|
onClick={onBack}
|
||||||
ariaLabel={oldLang('Back')}
|
ariaLabel={oldLang('Back')}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -11,9 +11,10 @@ import { MEDIA_TIMESTAMP_SAVE_MINIMUM_DURATION } from '../../config';
|
|||||||
import {
|
import {
|
||||||
selectIsMessageProtected, selectMessageTimestampableDuration, selectTabState,
|
selectIsMessageProtected, selectMessageTimestampableDuration, selectTabState,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import { ARE_WEBCODECS_SUPPORTED } from '../../util/browser/globalEnvironment';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import stopEvent from '../../util/stopEvent';
|
import stopEvent from '../../util/stopEvent';
|
||||||
import { ARE_WEBCODECS_SUPPORTED, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import { calculateMediaViewerDimensions } from '../common/helpers/mediaDimensions';
|
import { calculateMediaViewerDimensions } from '../common/helpers/mediaDimensions';
|
||||||
import { renderMessageText } from '../common/helpers/renderMessageText';
|
import { renderMessageText } from '../common/helpers/renderMessageText';
|
||||||
import getViewableMedia from './helpers/getViewableMedia';
|
import getViewableMedia from './helpers/getViewableMedia';
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import React, { useEffect, useState } from '../../lib/teact/teact';
|
|||||||
|
|
||||||
import type { TextPart } from '../../types';
|
import type { TextPart } from '../../types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { throttle } from '../../util/schedulers';
|
import { throttle } from '../../util/schedulers';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
import { REM } from '../common/helpers/mediaDimensions';
|
import { REM } from '../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import type { RealTouchEvent } from '../../util/captureEvents';
|
|||||||
import type { MediaViewerItem } from './helpers/getViewableMedia';
|
import type { MediaViewerItem } from './helpers/getViewableMedia';
|
||||||
|
|
||||||
import { animateNumber, timingFunctions } from '../../util/animation';
|
import { animateNumber, timingFunctions } from '../../util/animation';
|
||||||
|
import { IS_IOS, IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import {
|
import {
|
||||||
captureEvents,
|
captureEvents,
|
||||||
@ -17,7 +18,6 @@ import {
|
|||||||
} from '../../util/captureEvents';
|
} from '../../util/captureEvents';
|
||||||
import { clamp, isBetween, round } from '../../util/math';
|
import { clamp, isBetween, round } from '../../util/math';
|
||||||
import { debounce } from '../../util/schedulers';
|
import { debounce } from '../../util/schedulers';
|
||||||
import { IS_IOS, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useTimeout from '../../hooks/schedulers/useTimeout';
|
import useTimeout from '../../hooks/schedulers/useTimeout';
|
||||||
import useDebouncedCallback from '../../hooks/useDebouncedCallback';
|
import useDebouncedCallback from '../../hooks/useDebouncedCallback';
|
||||||
|
|||||||
@ -9,11 +9,11 @@ import type { BufferedRange } from '../../hooks/useBuffering';
|
|||||||
|
|
||||||
import { createVideoPreviews, getPreviewDimensions, renderVideoPreview } from '../../lib/video-preview/VideoPreview';
|
import { createVideoPreviews, getPreviewDimensions, renderVideoPreview } from '../../lib/video-preview/VideoPreview';
|
||||||
import { animateNumber } from '../../util/animation';
|
import { animateNumber } from '../../util/animation';
|
||||||
|
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { captureEvents } from '../../util/captureEvents';
|
import { captureEvents } from '../../util/captureEvents';
|
||||||
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
||||||
import { clamp, round } from '../../util/math';
|
import { clamp, round } from '../../util/math';
|
||||||
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import { useThrottledSignal } from '../../hooks/useAsyncResolvers';
|
import { useThrottledSignal } from '../../hooks/useAsyncResolvers';
|
||||||
import useCurrentTimeSignal from '../../hooks/useCurrentTimeSignal';
|
import useCurrentTimeSignal from '../../hooks/useCurrentTimeSignal';
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import { getActions } from '../../global';
|
|||||||
|
|
||||||
import type { ApiDimensions } from '../../api/types';
|
import type { ApiDimensions } from '../../api/types';
|
||||||
|
|
||||||
|
import { IS_IOS, IS_TOUCH_ENV, IS_YA_BROWSER } from '../../util/browser/windowEnvironment';
|
||||||
import { clamp } from '../../util/math';
|
import { clamp } from '../../util/math';
|
||||||
import safePlay from '../../util/safePlay';
|
import safePlay from '../../util/safePlay';
|
||||||
import stopEvent from '../../util/stopEvent';
|
import stopEvent from '../../util/stopEvent';
|
||||||
import { IS_IOS, IS_TOUCH_ENV, IS_YA_BROWSER } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useUnsupportedMedia from '../../hooks/media/useUnsupportedMedia';
|
import useUnsupportedMedia from '../../hooks/media/useUnsupportedMedia';
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -9,10 +9,10 @@ import type { ApiDimensions } from '../../api/types';
|
|||||||
import type { BufferedRange } from '../../hooks/useBuffering';
|
import type { BufferedRange } from '../../hooks/useBuffering';
|
||||||
import type { IconName } from '../../types/icons';
|
import type { IconName } from '../../types/icons';
|
||||||
|
|
||||||
|
import { IS_IOS, IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
||||||
import { formatFileSize } from '../../util/textFormat';
|
import { formatFileSize } from '../../util/textFormat';
|
||||||
import { IS_IOS, IS_TOUCH_ENV } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
import useCurrentTimeSignal from '../../hooks/useCurrentTimeSignal';
|
import useCurrentTimeSignal from '../../hooks/useCurrentTimeSignal';
|
||||||
|
|||||||
@ -5,10 +5,10 @@ import { ANIMATION_END_DELAY, MESSAGE_CONTENT_SELECTOR } from '../../../config';
|
|||||||
import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||||
import { getMessageHtmlId } from '../../../global/helpers';
|
import { getMessageHtmlId } from '../../../global/helpers';
|
||||||
import { applyStyles } from '../../../util/animation';
|
import { applyStyles } from '../../../util/animation';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import stopEvent from '../../../util/stopEvent';
|
import stopEvent from '../../../util/stopEvent';
|
||||||
import getOffsetToContainer from '../../../util/visibility/getOffsetToContainer';
|
import getOffsetToContainer from '../../../util/visibility/getOffsetToContainer';
|
||||||
import { isElementInViewport } from '../../../util/visibility/isElementInViewport';
|
import { isElementInViewport } from '../../../util/visibility/isElementInViewport';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
import windowSize from '../../../util/windowSize';
|
import windowSize from '../../../util/windowSize';
|
||||||
import {
|
import {
|
||||||
calculateDimensions,
|
calculateDimensions,
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import type { ActiveEmojiInteraction } from '../../types';
|
|||||||
import {
|
import {
|
||||||
selectAnimatedEmojiEffect,
|
selectAnimatedEmojiEffect,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import { IS_ANDROID } from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { IS_ANDROID } from '../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
import useLastCallback from '../../hooks/useLastCallback';
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import {
|
|||||||
selectTranslationLanguage,
|
selectTranslationLanguage,
|
||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
import { ARE_CALLS_SUPPORTED, IS_APP } from '../../util/windowEnvironment';
|
import { ARE_CALLS_SUPPORTED, IS_APP } from '../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import { useHotkeys } from '../../hooks/useHotkeys';
|
import { useHotkeys } from '../../hooks/useHotkeys';
|
||||||
import useLastCallback from '../../hooks/useLastCallback';
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
selectSelectedMessagesCount,
|
selectSelectedMessagesCount,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../global/selectors/sharedState';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import captureKeyboardListeners from '../../util/captureKeyboardListeners';
|
import captureKeyboardListeners from '../../util/captureKeyboardListeners';
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
|||||||
showNotification,
|
showNotification,
|
||||||
reportMessages,
|
reportMessages,
|
||||||
openDeleteMessageModal,
|
openDeleteMessageModal,
|
||||||
setSettingOption,
|
setSharedSettingOption,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleSvgConfirm = useLastCallback(() => {
|
const handleSvgConfirm = useLastCallback(() => {
|
||||||
setSettingOption({ shouldWarnAboutSvg: false });
|
setSharedSettingOption({ shouldWarnAboutSvg: false });
|
||||||
closeSvgDialog();
|
closeSvgDialog();
|
||||||
handleDownload();
|
handleDownload();
|
||||||
});
|
});
|
||||||
@ -238,7 +239,9 @@ const MessageSelectToolbar: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const tabState = selectTabState(global);
|
const tabState = selectTabState(global);
|
||||||
|
const { shouldWarnAboutSvg } = selectSharedSettings(global);
|
||||||
const chat = selectCurrentChat(global);
|
const chat = selectCurrentChat(global);
|
||||||
|
|
||||||
const { type: messageListType, chatId } = selectCurrentMessageList(global) || {};
|
const { type: messageListType, chatId } = selectCurrentMessageList(global) || {};
|
||||||
const isSchedule = messageListType === 'scheduled';
|
const isSchedule = messageListType === 'scheduled';
|
||||||
const { canDelete } = selectCanDeleteSelectedMessages(global);
|
const { canDelete } = selectCanDeleteSelectedMessages(global);
|
||||||
@ -263,7 +266,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
selectedMessageIds,
|
selectedMessageIds,
|
||||||
hasProtectedMessage,
|
hasProtectedMessage,
|
||||||
isAnyModalOpen,
|
isAnyModalOpen,
|
||||||
shouldWarnAboutSvg: global.settings.byKey.shouldWarnAboutSvg,
|
shouldWarnAboutSvg,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(MessageSelectToolbar));
|
)(MessageSelectToolbar));
|
||||||
|
|||||||
@ -54,17 +54,18 @@ import {
|
|||||||
selectPinnedIds,
|
selectPinnedIds,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectTheme,
|
selectTheme,
|
||||||
|
selectThemeValues,
|
||||||
selectThreadInfo,
|
selectThreadInfo,
|
||||||
selectTopic,
|
selectTopic,
|
||||||
selectTopics,
|
selectTopics,
|
||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
import {
|
||||||
|
IS_ANDROID, IS_ELECTRON, IS_IOS, IS_SAFARI, IS_TRANSLATION_SUPPORTED, MASK_IMAGE_DISABLED,
|
||||||
|
} from '../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
||||||
import {
|
|
||||||
IS_ANDROID, IS_ELECTRON, IS_IOS, IS_SAFARI, IS_TRANSLATION_SUPPORTED, MASK_IMAGE_DISABLED,
|
|
||||||
} from '../../util/windowEnvironment';
|
|
||||||
import calculateMiddleFooterTransforms from './helpers/calculateMiddleFooterTransforms';
|
import calculateMiddleFooterTransforms from './helpers/calculateMiddleFooterTransforms';
|
||||||
|
|
||||||
import useAppLayout from '../../hooks/useAppLayout';
|
import useAppLayout from '../../hooks/useAppLayout';
|
||||||
@ -726,7 +727,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const theme = selectTheme(global);
|
const theme = selectTheme(global);
|
||||||
const {
|
const {
|
||||||
isBlurred: isBackgroundBlurred, background: customBackground, backgroundColor, patternColor,
|
isBlurred: isBackgroundBlurred, background: customBackground, backgroundColor, patternColor,
|
||||||
} = global.settings.themes[theme] || {};
|
} = selectThemeValues(global, theme) || {};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
messageLists, isLeftColumnShown, activeEmojiInteractions,
|
messageLists, isLeftColumnShown, activeEmojiInteractions,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { memo } from '../../lib/teact/teact';
|
|||||||
import { getActions, withGlobal } from '../../global';
|
import { getActions, withGlobal } from '../../global';
|
||||||
|
|
||||||
import { getUserFirstOrLastName } from '../../global/helpers';
|
import { getUserFirstOrLastName } from '../../global/helpers';
|
||||||
import { selectTheme, selectUser } from '../../global/selectors';
|
import { selectTheme, selectThemeValues, selectUser } from '../../global/selectors';
|
||||||
import { formatStarsAsIcon } from '../../util/localization/format';
|
import { formatStarsAsIcon } from '../../util/localization/format';
|
||||||
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
import { LOCAL_TGS_URLS } from '../common/helpers/animatedAssets';
|
||||||
import renderText from '../common/helpers/renderText';
|
import renderText from '../common/helpers/renderText';
|
||||||
@ -95,7 +95,7 @@ function RequirementToContactMessage({ patternColor, userName, paidMessagesStars
|
|||||||
export default memo(
|
export default memo(
|
||||||
withGlobal<OwnProps>((global, { userId }): StateProps => {
|
withGlobal<OwnProps>((global, { userId }): StateProps => {
|
||||||
const theme = selectTheme(global);
|
const theme = selectTheme(global);
|
||||||
const { patternColor } = global.settings.themes[theme] || {};
|
const { patternColor } = selectThemeValues(global, theme) || {};
|
||||||
const user = selectUser(global, userId);
|
const user = selectUser(global, userId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { FC } from '../../../lib/teact/teact';
|
|||||||
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import type { ApiDocument } from '../../../api/types';
|
import type { ApiDocument } from '../../../api/types';
|
||||||
import type { ISettings } from '../../../types';
|
import type { ThemeKey } from '../../../types';
|
||||||
import { ApiMediaFormat } from '../../../api/types';
|
import { ApiMediaFormat } from '../../../api/types';
|
||||||
|
|
||||||
import { getDocumentMediaHash } from '../../../global/helpers';
|
import { getDocumentMediaHash } from '../../../global/helpers';
|
||||||
@ -15,7 +15,7 @@ import styles from './AttachBotIcon.module.scss';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
icon: ApiDocument;
|
icon: ApiDocument;
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ADDITIONAL_STROKE_WIDTH = '0.5px';
|
const ADDITIONAL_STROKE_WIDTH = '0.5px';
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import React, {
|
|||||||
import { getActions } from '../../../global';
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
import type { ApiAttachBot } from '../../../api/types';
|
import type { ApiAttachBot } from '../../../api/types';
|
||||||
import type { IAnchorPosition, ISettings, ThreadId } from '../../../types';
|
import type { IAnchorPosition, ThemeKey, ThreadId } from '../../../types';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
@ -17,7 +17,7 @@ import AttachBotIcon from './AttachBotIcon';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
bot: ApiAttachBot;
|
bot: ApiAttachBot;
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
isInSideMenu?: true;
|
isInSideMenu?: true;
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
threadId?: ThreadId;
|
threadId?: ThreadId;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import React, {
|
|||||||
|
|
||||||
import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types';
|
import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types';
|
||||||
import type { GlobalState } from '../../../global/types';
|
import type { GlobalState } from '../../../global/types';
|
||||||
import type { ISettings, MessageListType, ThreadId } from '../../../types';
|
import type { MessageListType, ThemeKey, ThreadId } from '../../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONTENT_TYPES_WITH_PREVIEW, DEBUG_LOG_FILENAME, SUPPORTED_AUDIO_CONTENT_TYPES,
|
CONTENT_TYPES_WITH_PREVIEW, DEBUG_LOG_FILENAME, SUPPORTED_AUDIO_CONTENT_TYPES,
|
||||||
@ -20,11 +20,11 @@ import {
|
|||||||
getMessageWebPagePhoto,
|
getMessageWebPagePhoto,
|
||||||
getMessageWebPageVideo,
|
getMessageWebPageVideo,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { getDebugLogs } from '../../../util/debugConsole';
|
import { getDebugLogs } from '../../../util/debugConsole';
|
||||||
import { validateFiles } from '../../../util/files';
|
import { validateFiles } from '../../../util/files';
|
||||||
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -54,7 +54,7 @@ export type OwnProps = {
|
|||||||
attachBots?: GlobalState['attachMenu']['bots'];
|
attachBots?: GlobalState['attachMenu']['bots'];
|
||||||
peerType?: ApiAttachMenuPeerType;
|
peerType?: ApiAttachMenuPeerType;
|
||||||
shouldCollectDebugLogs?: boolean;
|
shouldCollectDebugLogs?: boolean;
|
||||||
theme: ISettings['theme'];
|
theme: ThemeKey;
|
||||||
onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void;
|
onFileSelect: (files: File[], shouldSuggestCompression?: boolean) => void;
|
||||||
onPollCreate: NoneToVoidFunction;
|
onPollCreate: NoneToVoidFunction;
|
||||||
onMenuOpen: NoneToVoidFunction;
|
onMenuOpen: NoneToVoidFunction;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
|||||||
import { getAttachmentMediaType, isUserId } from '../../../global/helpers';
|
import { getAttachmentMediaType, isUserId } from '../../../global/helpers';
|
||||||
import { selectChatFullInfo, selectIsChatWithSelf } from '../../../global/selectors';
|
import { selectChatFullInfo, selectIsChatWithSelf } from '../../../global/selectors';
|
||||||
import { selectCurrentLimit } from '../../../global/selectors/limits';
|
import { selectCurrentLimit } from '../../../global/selectors/limits';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
import { validateFiles } from '../../../util/files';
|
import { validateFiles } from '../../../util/files';
|
||||||
@ -750,7 +751,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
const chatFullInfo = !isUserId(chatId) ? selectChatFullInfo(global, chatId) : undefined;
|
const chatFullInfo = !isUserId(chatId) ? selectChatFullInfo(global, chatId) : undefined;
|
||||||
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
||||||
const { language, shouldSuggestCustomEmoji } = global.settings.byKey;
|
const { shouldSuggestCustomEmoji } = global.settings.byKey;
|
||||||
|
const { language } = selectSharedSettings(global);
|
||||||
const baseEmojiKeywords = global.emojiKeywords[BASE_EMOJI_KEYWORD_LANG];
|
const baseEmojiKeywords = global.emojiKeywords[BASE_EMOJI_KEYWORD_LANG];
|
||||||
const emojiKeywords = language !== BASE_EMOJI_KEYWORD_LANG ? global.emojiKeywords[language] : undefined;
|
const emojiKeywords = language !== BASE_EMOJI_KEYWORD_LANG ? global.emojiKeywords[language] : undefined;
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { getActions } from '../../../global';
|
|||||||
|
|
||||||
import type { ApiBotCommand } from '../../../api/types';
|
import type { ApiBotCommand } from '../../../api/types';
|
||||||
|
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
import type { ApiMessage } from '../../../api/types';
|
import type { ApiMessage } from '../../../api/types';
|
||||||
|
|
||||||
import { selectChatMessage, selectCurrentMessageList } from '../../../global/selectors';
|
import { selectChatMessage, selectCurrentMessageList } from '../../../global/selectors';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import renderKeyboardButtonText from './helpers/renderKeyboardButtonText';
|
import renderKeyboardButtonText from './helpers/renderKeyboardButtonText';
|
||||||
|
|
||||||
import useMouseInside from '../../../hooks/useMouseInside';
|
import useMouseInside from '../../../hooks/useMouseInside';
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import type {
|
|||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { IAnchorPosition } from '../../../types';
|
import type { IAnchorPosition } from '../../../types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps';
|
import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import type { FC } from '../../../lib/teact/teact';
|
|||||||
import React, { memo } from '../../../lib/teact/teact';
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import { BASE_URL, IS_PACKAGED_ELECTRON } from '../../../config';
|
import { BASE_URL, IS_PACKAGED_ELECTRON } from '../../../config';
|
||||||
|
import { IS_EMOJI_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { handleEmojiLoad, LOADED_EMOJIS } from '../../../util/emoji/emoji';
|
import { handleEmojiLoad, LOADED_EMOJIS } from '../../../util/emoji/emoji';
|
||||||
import { IS_EMOJI_SUPPORTED } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,11 @@ import type {
|
|||||||
import { MENU_TRANSITION_DURATION, RECENT_SYMBOL_SET_ID } from '../../../config';
|
import { MENU_TRANSITION_DURATION, RECENT_SYMBOL_SET_ID } from '../../../config';
|
||||||
import animateHorizontalScroll from '../../../util/animateHorizontalScroll';
|
import animateHorizontalScroll from '../../../util/animateHorizontalScroll';
|
||||||
import animateScroll from '../../../util/animateScroll';
|
import animateScroll from '../../../util/animateScroll';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { uncompressEmoji } from '../../../util/emoji/emoji';
|
import { uncompressEmoji } from '../../../util/emoji/emoji';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
|
import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
import { REM } from '../../common/helpers/mediaDimensions';
|
import { REM } from '../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
import useAppLayout from '../../../hooks/useAppLayout';
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type { ApiVideo } from '../../../api/types';
|
|||||||
|
|
||||||
import { SLIDE_TRANSITION_DURATION } from '../../../config';
|
import { SLIDE_TRANSITION_DURATION } from '../../../config';
|
||||||
import { selectCurrentMessageList, selectIsChatWithSelf } from '../../../global/selectors';
|
import { selectCurrentMessageList, selectIsChatWithSelf } from '../../../global/selectors';
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|||||||
@ -7,11 +7,11 @@ import type {
|
|||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import { LoadMoreDirection } from '../../../types';
|
import { LoadMoreDirection } from '../../../types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { throttle } from '../../../util/schedulers';
|
import { throttle } from '../../../util/schedulers';
|
||||||
import setTooltipItemVisible from '../../../util/setTooltipItemVisible';
|
import setTooltipItemVisible from '../../../util/setTooltipItemVisible';
|
||||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||||
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
||||||
|
|||||||
@ -9,22 +9,23 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
|
|
||||||
import type { ApiInputMessageReplyInfo } from '../../../api/types';
|
import type { ApiInputMessageReplyInfo } from '../../../api/types';
|
||||||
import type {
|
import type {
|
||||||
IAnchorPosition, ISettings, MessageListType, ThreadId,
|
IAnchorPosition, MessageListType, SharedSettings, ThreadId,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
import type { Signal } from '../../../util/signals';
|
import type { Signal } from '../../../util/signals';
|
||||||
|
|
||||||
import { EDITABLE_INPUT_ID } from '../../../config';
|
import { EDITABLE_INPUT_ID } from '../../../config';
|
||||||
import { requestForcedReflow, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
import { requestForcedReflow, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||||
import { selectCanPlayAnimatedEmojis, selectDraft, selectIsInSelectMode } from '../../../global/selectors';
|
import { selectCanPlayAnimatedEmojis, selectDraft, selectIsInSelectMode } from '../../../global/selectors';
|
||||||
|
import { selectSharedSettings } from '../../../global/selectors/sharedState';
|
||||||
|
import {
|
||||||
|
IS_ANDROID, IS_EMOJI_SUPPORTED, IS_IOS, IS_TOUCH_ENV,
|
||||||
|
} from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
|
import captureKeyboardListeners from '../../../util/captureKeyboardListeners';
|
||||||
import { getIsDirectTextInputDisabled } from '../../../util/directInputManager';
|
import { getIsDirectTextInputDisabled } from '../../../util/directInputManager';
|
||||||
import parseEmojiOnlyString from '../../../util/emoji/parseEmojiOnlyString';
|
import parseEmojiOnlyString from '../../../util/emoji/parseEmojiOnlyString';
|
||||||
import focusEditableElement from '../../../util/focusEditableElement';
|
import focusEditableElement from '../../../util/focusEditableElement';
|
||||||
import { debounce } from '../../../util/schedulers';
|
import { debounce } from '../../../util/schedulers';
|
||||||
import {
|
|
||||||
IS_ANDROID, IS_EMOJI_SUPPORTED, IS_IOS, IS_TOUCH_ENV,
|
|
||||||
} from '../../../util/windowEnvironment';
|
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
import { isSelectionInsideInput } from './helpers/selection';
|
import { isSelectionInsideInput } from './helpers/selection';
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ type OwnProps = {
|
|||||||
type StateProps = {
|
type StateProps = {
|
||||||
replyInfo?: ApiInputMessageReplyInfo;
|
replyInfo?: ApiInputMessageReplyInfo;
|
||||||
isSelectModeActive?: boolean;
|
isSelectModeActive?: boolean;
|
||||||
messageSendKeyCombo?: ISettings['messageSendKeyCombo'];
|
messageSendKeyCombo?: SharedSettings['messageSendKeyCombo'];
|
||||||
canPlayAnimatedEmojis: boolean;
|
canPlayAnimatedEmojis: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -649,7 +650,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId, threadId }: OwnProps): StateProps => {
|
(global, { chatId, threadId }: OwnProps): StateProps => {
|
||||||
const { messageSendKeyCombo } = global.settings.byKey;
|
const { messageSendKeyCombo } = selectSharedSettings(global);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messageSendKeyCombo,
|
messageSendKeyCombo,
|
||||||
|
|||||||
@ -4,9 +4,9 @@ import { getActions, getGlobal } from '../../../global';
|
|||||||
|
|
||||||
import type { ApiSendAsPeerId } from '../../../api/types';
|
import type { ApiSendAsPeerId } from '../../../api/types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import setTooltipItemVisible from '../../../util/setTooltipItemVisible';
|
import setTooltipItemVisible from '../../../util/setTooltipItemVisible';
|
||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
|
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useMouseInside from '../../../hooks/useMouseInside';
|
import useMouseInside from '../../../hooks/useMouseInside';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user